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

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 (90) hide show
  1. package/dist/dev-shared.js +1399 -285
  2. package/dist/dev.attribution.js +459 -307
  3. package/dist/dev.js +1864 -435
  4. package/dist/observe/affects.js +3 -1
  5. package/dist/observe/attribution.js +7 -1
  6. package/dist/observe/boundaries.js +209 -154
  7. package/dist/observe/core/action.js +18 -8
  8. package/dist/observe/core/async.js +220 -110
  9. package/dist/observe/core/attribution-costs.js +66 -0
  10. package/dist/observe/core/attribution-feedback.js +282 -0
  11. package/dist/observe/core/attribution-hooks.js +23 -1
  12. package/dist/observe/core/attribution-queries.js +28 -0
  13. package/dist/observe/core/attribution.js +262 -485
  14. package/dist/observe/core/constants.js +34 -1
  15. package/dist/observe/core/context.js +3 -3
  16. package/dist/observe/core/core.js +867 -367
  17. package/dist/observe/core/dev.js +78 -17
  18. package/dist/observe/core/effect.js +67 -51
  19. package/dist/observe/core/error-hooks.js +71 -0
  20. package/dist/observe/core/external.js +4 -4
  21. package/dist/observe/core/graph.js +37 -37
  22. package/dist/observe/core/heap.js +45 -45
  23. package/dist/observe/core/invariants.js +2 -0
  24. package/dist/observe/core/lanes.js +86 -49
  25. package/dist/observe/core/optimistic.js +242 -95
  26. package/dist/observe/core/owner.js +98 -84
  27. package/dist/observe/core/scheduler.js +543 -305
  28. package/dist/observe/core/verdict.js +247 -129
  29. package/dist/observe/index.js +7 -3
  30. package/dist/observe/map.js +126 -124
  31. package/dist/observe/signals.js +33 -17
  32. package/dist/observe/store/index.js +2 -0
  33. package/dist/observe/store/next/optimistic.js +141 -132
  34. package/dist/observe/store/next/projection.js +34 -21
  35. package/dist/observe/store/next/reconcile.js +58 -56
  36. package/dist/observe/store/next/store.js +260 -146
  37. package/dist/observe/store/store.js +5 -3
  38. package/dist/observe/store/utils.js +948 -135
  39. package/dist/prod/attribution.js +26 -17
  40. package/dist/prod/boundaries.js +128 -76
  41. package/dist/prod/core/action.js +16 -8
  42. package/dist/prod/core/async.js +251 -143
  43. package/dist/prod/core/constants.js +34 -1
  44. package/dist/prod/core/context.js +3 -3
  45. package/dist/prod/core/core.js +843 -347
  46. package/dist/prod/core/dev.js +17 -1
  47. package/dist/prod/core/effect.js +48 -34
  48. package/dist/prod/core/error-hooks.js +71 -0
  49. package/dist/prod/core/external.js +4 -4
  50. package/dist/prod/core/graph.js +37 -37
  51. package/dist/prod/core/heap.js +45 -45
  52. package/dist/prod/core/lanes.js +90 -53
  53. package/dist/prod/core/optimistic.js +247 -100
  54. package/dist/prod/core/owner.js +57 -45
  55. package/dist/prod/core/scheduler.js +543 -305
  56. package/dist/prod/core/verdict.js +245 -127
  57. package/dist/prod/index.js +7 -3
  58. package/dist/prod/map.js +112 -112
  59. package/dist/prod/signals.js +28 -12
  60. package/dist/prod/store/next/optimistic.js +135 -128
  61. package/dist/prod/store/next/projection.js +31 -20
  62. package/dist/prod/store/next/store.js +325 -252
  63. package/dist/prod/store/store.js +2 -2
  64. package/dist/prod/store/utils.js +946 -135
  65. package/dist/types/attribution.d.ts +7 -2
  66. package/dist/types/attribution.prod.d.ts +10 -1
  67. package/dist/types/boundaries.d.ts +10 -1
  68. package/dist/types/core/action.d.ts +12 -5
  69. package/dist/types/core/attribution-costs.d.ts +35 -0
  70. package/dist/types/core/attribution-feedback.d.ts +133 -0
  71. package/dist/types/core/attribution-hooks.d.ts +28 -3
  72. package/dist/types/core/attribution-queries.d.ts +10 -0
  73. package/dist/types/core/attribution.d.ts +51 -172
  74. package/dist/types/core/constants.d.ts +33 -0
  75. package/dist/types/core/core.d.ts +186 -5
  76. package/dist/types/core/dev.d.ts +129 -9
  77. package/dist/types/core/error-hooks.d.ts +71 -0
  78. package/dist/types/core/index.d.ts +3 -1
  79. package/dist/types/core/invariants.d.ts +4 -0
  80. package/dist/types/core/lanes.d.ts +31 -4
  81. package/dist/types/core/scheduler.d.ts +95 -2
  82. package/dist/types/core/types.d.ts +3 -0
  83. package/dist/types/index.d.ts +2 -2
  84. package/dist/types/signals.d.ts +8 -0
  85. package/dist/types/store/index.d.ts +2 -1
  86. package/dist/types/store/next/optimistic.d.ts +1 -1
  87. package/dist/types/store/next/store.d.ts +6 -5
  88. package/dist/types/store/next/target.d.ts +1 -1
  89. package/dist/types/store/utils.d.ts +177 -6
  90. package/package.json +1 -1
@@ -1,14 +1,14 @@
1
- import { NOT_PENDING, unwrapOverride, STATUS_UNINITIALIZED, REACTIVE_DIRTY, REACTIVE_CHECK, CONFIG_HAS_LANE, OVERRIDE_UNDEFINED, STATUS_PENDING, CONFIG_OVERRIDE_SUPERSEDED, EFFECT_RENDER, CONFIG_AUTHORITATIVE_OBSERVED, REACTIVE_MANUAL_WRITE, REACTIVE_OPTIMISTIC_DIRTY, LANE_RUN, EFFECT_USER } from "./constants.js";
1
+ import { NOT_PENDING, unwrapOverride, STATUS_UNINITIALIZED, REACTIVE_DIRTY, REACTIVE_CHECK, CONFIG_HAS_LANE, OVERRIDE_UNDEFINED, STATUS_PENDING, CONFIG_DERIVED_OVERRIDE, CONFIG_OPTIMISTIC, CONFIG_OVERRIDE_SUPERSEDED, EFFECT_RENDER, CONFIG_AUTHORITATIVE_OBSERVED, REACTIVE_MANUAL_WRITE, REACTIVE_OPTIMISTIC_DIRTY, LANE_RUN, EFFECT_USER } from "./constants.js";
2
2
 
3
- import { ext, stale, latestReadActive, currentOptimisticLane } from "./core.js";
3
+ import { ext, hasActiveOverride, stale, enterStagedRead, latestReadActive, currentOptimisticLane } from "./core.js";
4
4
 
5
5
  import { NotReadyError } from "./error.js";
6
6
 
7
7
  import "./invariants.js";
8
8
 
9
- import { resolveTransition, getOrCreateLane, hasActiveOverride, activeLanes, signalLanes, laneHeld, findLane, resolveLane, assignOrMergeLane } from "./lanes.js";
9
+ import { resolveTransition, getOrCreateLane, activeLanes, signalLanes, laneHeld, findLane, resolveLane, readsHeldCommitted, assignOrMergeLane } from "./lanes.js";
10
10
 
11
- import { GlobalQueue, activeTransition, globalQueue, origin, clock, insertSubs, schedule, queuePendingNode } from "./scheduler.js";
11
+ import { GlobalQueue, activeTransition, globalQueue, origin, clock, insertSubs, schedule, sourceObserved, currentTransition, queuePendingNode } from "./scheduler.js";
12
12
 
13
13
  /**
14
14
  * The optimistic write engine, moved out of core.ts/scheduler.ts. Everything
@@ -24,18 +24,18 @@ import { GlobalQueue, activeTransition, globalQueue, origin, clock, insertSubs,
24
24
  * once the gate holds — the same late-binding contract as verdict.ts.
25
25
  */
26
26
  /** The optimistic half of setSignal, fired when `_overrideValue !== undefined`. */ function optimisticWrite(e, n) {
27
- const i = e.o?.be !== NOT_PENDING;
28
- const t = i ? unwrapOverride(e.o?.be) : e.me;
27
+ const i = e.o?.Ce !== NOT_PENDING;
28
+ const t = i ? unwrapOverride(e.o?.Ce) : e.Qe;
29
29
  if (typeof n === "function") n = n(t);
30
- const u = !!(e.S & STATUS_UNINITIALIZED) ||
30
+ const r = !!(e.S & STATUS_UNINITIALIZED) ||
31
31
  // A dirty node's _value is stale (its queued recompute hasn't run — e.g.
32
32
  // a latest() shadow marked by the previous landing's companion snap), so
33
33
  // equality against it must not swallow the write. Without this, a sync
34
34
  // push returning the shadow to that stale value was dropped, the snap
35
35
  // recompute then committed the parent's old value, and the banner showed
36
36
  // the previous transition's target (#3041 follow-up).
37
- !!((e.ie ?? 0) & (REACTIVE_DIRTY | REACTIVE_CHECK)) || !e.ve || !e.ve(t, n);
38
- if (!u) {
37
+ !!((e.ue ?? 0) & (REACTIVE_DIRTY | REACTIVE_CHECK)) || !e.Fe || !e.Fe(t, n);
38
+ if (!r) {
39
39
  // Same-value write with an active override still entangles the current
40
40
  // action's transition — the hold must outlast all overlapping actions —
41
41
  // and renews the override's PROVENANCE: the newer action re-asks the
@@ -45,7 +45,7 @@ import { GlobalQueue, activeTransition, globalQueue, origin, clock, insertSubs,
45
45
  if (i) {
46
46
  const n = resolveTransition(e);
47
47
  if (n && activeTransition !== n) globalQueue.initTransition(n);
48
- if (origin > e.o.Rt) e.o.Rt = origin;
48
+ if (origin > e.o.vt) e.o.vt = origin;
49
49
  }
50
50
  return n;
51
51
  }
@@ -53,42 +53,93 @@ import { GlobalQueue, activeTransition, globalQueue, origin, clock, insertSubs,
53
53
  // No revert target is stashed: while the override is active every reader
54
54
  // sees it (A17), so authoritative arrivals commit silently into _value and
55
55
  // reverting is just dropping the override — _value is already correct.
56
- else globalQueue.m.it.push(e);
56
+ else globalQueue.m.rt.push(e);
57
57
  // Stamp ownership on the node (post-merge, so entangled writers share the
58
58
  // joint root). resolveTransition prefers this over the lane's _transition,
59
59
  // which a shared subscriber can merge across transactions (#2912).
60
- ext(e).Ot = activeTransition;
61
- ext(e).It = clock;
60
+ ext(e).Ft = activeTransition;
61
+ ext(e).Ct = clock;
62
62
  // Provenance: the action asking. An answer an OLDER action's flight brings
63
63
  // back is a stale question and holds silently to commit (#3331).
64
- ext(e).Rt = origin;
65
- const r = getOrCreateLane(e);
66
- ext(e).Oe = r;
64
+ ext(e).vt = origin;
65
+ const u = getOrCreateLane(e);
66
+ ext(e).Ue = u;
67
67
  // A fresh override re-masks: whatever truth is staged, this write is the
68
68
  // value for the graph again until the source answers it (#3331).
69
- e.T = (e.T | CONFIG_HAS_LANE) & ~CONFIG_OVERRIDE_SUPERSEDED;
69
+ e.T = (e.T | CONFIG_HAS_LANE) & -8912897;
70
70
  // Literal undefined must not land raw: the slot doubles as the optimistic
71
71
  // brand, and erasing it makes the write invisible and routes follow-up
72
72
  // writes off the optimistic path into permanent commits (#2898).
73
- ext(e).be = n === undefined ? OVERRIDE_UNDEFINED : n;
73
+ ext(e).Ce = n === undefined ? OVERRIDE_UNDEFINED : n;
74
74
  // syncCompanions only pokes _pendingSignal/_latestValueComputed — with
75
75
  // neither companion present the call is a guaranteed no-op.
76
- (e.o?.Le !== undefined || e.o?.Qe !== undefined) && GlobalQueue.pe !== null && GlobalQueue.pe(e, n);
77
- if (e.oe !== undefined) e._e = clock;
76
+ (e.o?.je !== undefined || e.o?.xe !== undefined) && GlobalQueue.me !== null && GlobalQueue.me(e, n);
77
+ if (e.ce !== undefined) e.Pe = clock;
78
78
  // §12e: computed-only slot
79
79
  insertSubs(e, true);
80
80
  schedule();
81
81
  return n;
82
82
  }
83
83
 
84
+ /**
85
+ * Lanes stage (#3479): a lane pass's publish for a memo. An optimistic
86
+ * derivation is an override — the speculative result lives in the override
87
+ * slot, `_value` stays the committed truth. The whole optimistic frame is then
88
+ * in one place: the lane's readers and untracked reads see it (A17), a render
89
+ * effect off the held lane sees the committed frame whole (readsHeldCommitted,
90
+ * #3460) — the source's shadow AND its derivations — where a speculative
91
+ * `_value` beside a committed shadow tore it. The node joins the
92
+ * transaction's optimistic nodes on its first speculative publish; the revert
93
+ * drops the override and re-derives it from the truth (a derived override has
94
+ * no truth of its own — see resolveOptimisticNodes, endOptimism).
95
+ */ function laneOverride(e, n, i) {
96
+ // The wake-only channel (#3009, see recomputeLane): a plain write to a
97
+ // latest()-tracked source rides a companion-sourced lane with no
98
+ // transaction on either side only to wake the verdict companions. Nothing
99
+ // is speculative — the pass commits directly, as any plain write does.
100
+ i = findLane(i);
101
+ if (!i.Ge && !activeTransition && i.an.o?.Ht !== undefined) {
102
+ e.Qe = n;
103
+ return;
104
+ }
105
+ if (!hasActiveOverride(e)) {
106
+ // It reverts with the lane's transaction (a landing runs outside any
107
+ // flush, where the ambient batch would revert it at its own end); an
108
+ // orphan lane's falls to the batch, adopted with it (initTransition) as a
109
+ // write's is. No `_overrideOwner`: a derived override is a plain member,
110
+ // its transaction its lane's (resolveTransition), and it merges lanes
111
+ // through itself as any shared reader does (assignOrMergeLane). No
112
+ // provenance stamp either: not an intent, any truth supersedes it.
113
+ (i.Ge ? currentTransition(i.Ge) : globalQueue.m).rt.push(e);
114
+ }
115
+ // A lane pass's output is a derivation — also over a WRITTEN guess it
116
+ // corrects (a `createOptimistic(fn)` re-derived from fresh upstream data):
117
+ // the guess is gone, the slot holds fn's answer, and the revert promotes it
118
+ // rather than dropping to a stale `_value` and re-asking downstream (the
119
+ // next user write re-arms the guess: optimisticWrite clears the bit). No
120
+ // `_overrideTime` stamp: that marks a user WRITE unflushed until the flush
121
+ // that carries it (A28) and shields it from same-tick supersession — a pass's
122
+ // result is neither (a pulled ownerless memo publishes outside any flush).
123
+ // A fresh lane frame ends a supersession in force: the pass just dropped
124
+ // the staged truth it pointed at (recompute, INV-11 corollary) — left set,
125
+ // the flag served a `_value` never committed (fuzzer latest-1 #2481).
126
+ e.T = (e.T | CONFIG_DERIVED_OVERRIDE) & ~CONFIG_OVERRIDE_SUPERSEDED;
127
+ e.o.Ce = n === undefined ? OVERRIDE_UNDEFINED : n;
128
+ }
129
+
84
130
  /**
85
131
  * transitionComplete's override blockage: a settling transition stays open
86
132
  * while one of its optimistic nodes holds an active override that is still
87
- * pending on real (non-affects-sentinel) async.
133
+ * pending on real (non-affects-sentinel) async. A derived override's flight is
134
+ * the lane's own work, never authoritative — it does not hold the settle.
135
+ * Neither is a companion's (#3494): the `latest()` shadow backfilled under the
136
+ * owner's transaction (A28 (3)) is an observation of the flight, and a
137
+ * mainline `latest(details)` after the flight's last reader unmounted held the
138
+ * released write until the orphaned request landed.
88
139
  */ function transitionBlocked(e) {
89
- for (let n = 0; n < e.it.length; n++) {
90
- const i = e.it[n];
91
- if (hasActiveOverride(i) && "S" in i && i.S & STATUS_PENDING && i.o?._ instanceof NotReadyError) {
140
+ for (let n = 0; n < e.rt.length; n++) {
141
+ const i = e.rt[n];
142
+ if (!(i.T & CONFIG_DERIVED_OVERRIDE) && i.o?.Ht === undefined && hasActiveOverride(i) && "S" in i && i.S & STATUS_PENDING && i.o?._ instanceof NotReadyError) {
92
143
  return true;
93
144
  }
94
145
  }
@@ -102,30 +153,42 @@ function resolveOptimisticNodes(e) {
102
153
  const n = e.length;
103
154
  for (let i = 0; i < n; i++) {
104
155
  const n = e[i];
105
- if (n.o !== null) n.o.Oe = undefined;
156
+ if (n.o !== null) n.o.Ue = undefined;
106
157
  // Revert is a pure drop: there is no revert target to commit —
107
158
  // override-covered authoritative values hold in _pendingValue and
108
159
  // elevate on their OWN transition's schedule (A18 as re-ruled 2026-07-07).
109
160
  if (!(n.S & STATUS_PENDING)) n.S &= ~STATUS_UNINITIALIZED;
110
- const t = n.o?.be;
111
- ext(n).be = NOT_PENDING;
161
+ const t = n.o?.Ce;
162
+ // A derived override (lanes stage, #3479) has no truth of its own: the
163
+ // slot disarms — the memo is plain again — and the override PROMOTES to
164
+ // `_value`. Not superseded, nothing it derives from told it otherwise
165
+ // (a source override that reverts to a differing truth dirties it just
166
+ // above — sources join this list before their derivations — and its
167
+ // recompute then replaces the promotion), so by the graph's invariant
168
+ // the override IS what a recompute from the truth yields. Re-deriving
169
+ // instead re-asked an async member's flight and held the transaction on
170
+ // it — a waterfall after the reveal.
171
+ const r = n.T & CONFIG_DERIVED_OVERRIDE;
172
+ ext(n).Ce = r && !(n.T & CONFIG_OPTIMISTIC) ? undefined : NOT_PENDING;
112
173
  // A superseded override's subscribers already re-derived from the truth
113
174
  // when it arrived (#3331) — the drop changes nothing they read. Everyone
114
175
  // else learns of the correction here: this drop IS their notification.
115
176
  const u = (n.T & CONFIG_OVERRIDE_SUPERSEDED) !== 0;
116
- n.T &= ~CONFIG_OVERRIDE_SUPERSEDED;
117
- if (!u && t !== NOT_PENDING && n.me !== unwrapOverride(t)) insertSubs(n, true);
118
- n.ge = null;
119
- if (n.o !== null) n.o.Ot = null;
177
+ n.T &= -8912897;
178
+ if (!u && t !== NOT_PENDING && n.Qe !== unwrapOverride(t)) {
179
+ if (r) n.Qe = unwrapOverride(t); else insertSubs(n, true);
180
+ }
181
+ n.Ge = null;
182
+ if (n.o !== null) n.o.Ft = null;
120
183
  }
121
184
  // Settlement checkpoint (#2838): companions caught in this batch (or owned
122
185
  // by a node in it) re-derive from committed state, so verdicts survive the
123
186
  // transition that produced them (A19 — pending is a property of the data).
124
187
  for (let i = 0; i < n; i++) {
125
188
  const n = e[i];
126
- if (n.o?.Le || n.o?.Qe) GlobalQueue.un(n);
127
- const t = n.o?.Gt;
128
- if (t && (t.o?.Le === n || t.o?.Qe === n)) GlobalQueue.un(t);
189
+ if (n.o?.je || n.o?.xe) GlobalQueue.En(n);
190
+ const t = n.o?.Ht;
191
+ if (t && (t.o?.je === n || t.o?.xe === n)) GlobalQueue.En(t);
129
192
  }
130
193
  e.splice(0, n);
131
194
  }
@@ -160,10 +223,10 @@ function resolveOptimisticNodes(e) {
160
223
  * wake hook is installed by the setters of that bit; optional here because
161
224
  * the bit only implies the optimistic engine was consulted.
162
225
  */ function supersedeOverride(e, n) {
163
- const i = !e.ve || !e.ve(n, unwrapOverride(e.o.be));
226
+ const i = !e.Fe || !e.Fe(n, unwrapOverride(e.o.Ce));
164
227
  if (!i) {
165
228
  if (!(e.T & CONFIG_OVERRIDE_SUPERSEDED)) {
166
- if (e.T & CONFIG_AUTHORITATIVE_OBSERVED) GlobalQueue.Qt?.(e);
229
+ if (e.T & CONFIG_AUTHORITATIVE_OBSERVED) GlobalQueue.Zt?.(e);
167
230
  return;
168
231
  }
169
232
  e.T &= ~CONFIG_OVERRIDE_SUPERSEDED;
@@ -174,34 +237,114 @@ function resolveOptimisticNodes(e) {
174
237
  // still the truth when the transaction commits, but it does not move the
175
238
  // graph now — a slow source must not leak back in over a newer intent.
176
239
  // 0 is mainline (no action): always the current question.
177
- if (origin && origin < e.o.Rt) return;
240
+ if (origin && origin < e.o.vt) return;
178
241
  e.T |= CONFIG_OVERRIDE_SUPERSEDED;
179
- const n = e.o?.Oe;
242
+ const n = e.o?.Ue;
180
243
  if (n) {
181
244
  const i = findLane(n);
182
245
  const t = [ e ];
183
246
  while (t.length) {
184
247
  const e = t.pop();
185
- const n = e.o?.Oe;
248
+ const n = e.o?.Ue;
186
249
  if (!n || findLane(n) !== i) continue;
187
- e.o.Oe = undefined;
188
- i.he.delete(e);
189
- for (let n = e.u; n !== null; n = n.Te) t.push(n.Ie);
250
+ e.o.Ue = undefined;
251
+ i.ye.delete(e);
252
+ for (let n = e.u; n !== null; n = n.Ne) t.push(n._e);
190
253
  }
191
254
  }
192
255
  }
193
256
  insertSubs(e);
194
257
  }
195
258
 
259
+ /**
260
+ * The flush's pre-verdict step once the action bodies have ended (#3427).
261
+ * The bodies were the optimism's justification; with them over, the
262
+ * overrides still in force revert at the settle — unless the transaction is
263
+ * still waiting on AUTHORITATIVE work: an override node's own source in
264
+ * flight (`transitionBlocked` — that answer supersedes or confirms on
265
+ * arrival), or a held flight that does not derive from an override (a plain
266
+ * write's load the action asked for). Through that window the optimistic
267
+ * world stands: a co-written "saving" flag stays rendered until the page it
268
+ * covers lands (A17 — the optimistic world is one).
269
+ *
270
+ * The flights that DO derive from an override — routed through a live lane —
271
+ * are obsolete: their input is the guess that is about to revert, and nobody
272
+ * will read their answer. With nothing authoritative left, each override's
273
+ * truth is already here (the staged value an A17-silent landing left, else
274
+ * the committed value) and supersedes it now, exactly as an arriving
275
+ * differing truth does (A18, #3331): the graph re-derives from it as this
276
+ * transaction's held work — a lane-derived memo re-asks with the truth, its
277
+ * other changed inputs included — and the transaction settles when THAT
278
+ * lands. Before this the settle first waited for the obsolete flight,
279
+ * revealed the obsolete optimistic frame when it landed, and only then
280
+ * started the correction — a waterfall with a flash in the middle. Returns
281
+ * whether it superseded anything (the caller re-runs the heap).
282
+ *
283
+ * The optimistic world is one, so it ends early only when all of it can. An
284
+ * optimistic STORE edit cannot yet: its truth is the base layer under an
285
+ * overlay that `_clearOptimisticStores` folds off at settlement, with no
286
+ * tracked/displayed split — superseding its tracking signals alone would
287
+ * re-derive readers against a still-displayed overlay (and a memo reading
288
+ * both a signal and the store would ask a mixed question). A transaction
289
+ * holding one keeps the settle-then-revert order throughout. Companions
290
+ * (`_parentSource` set) are optimistic nodes too — a verdict written through
291
+ * the optimistic path so it flushes ahead of the hold — but they answer for
292
+ * their owner and snap at settlement (`_snapCompanions`), not here.
293
+ */ function endOptimism(e) {
294
+ if (!e.he || e.pe.length || !e.rt.length || e.dn.size || transitionBlocked(e)) return false;
295
+ for (const n of e.oe.keys()) if (sourceObserved(e, n, e) && n.o?.ae?.has(n) && !resolveLane(n)) return false;
296
+ let n = false;
297
+ for (const i of e.rt) {
298
+ if (!hasActiveOverride(i) || i.o.Ht ||
299
+ // A derived override re-derives when its source's is superseded.
300
+ i.T & (CONFIG_OVERRIDE_SUPERSEDED | CONFIG_DERIVED_OVERRIDE) || i.S & STATUS_UNINITIALIZED) continue;
301
+ const e = i.ve !== NOT_PENDING ? i.ve : i.Qe;
302
+ if (!i.Fe || !i.Fe(e, unwrapOverride(i.o.Ce))) {
303
+ supersedeOverride(i, e);
304
+ // Judged by the mark, not the call: a provenance refusal (an older
305
+ // action's window is still open) leaves the node for a later pass.
306
+ if (i.T & CONFIG_OVERRIDE_SUPERSEDED) n = true;
307
+ }
308
+ }
309
+ return n;
310
+ }
311
+
196
312
  /** read()'s value for a tracked reader of a superseded node: the truth —
197
313
  * staged, or already committed (a mainline landing commits at the head of
198
314
  * its flush, ahead of the heap run, and the override drops only at the
199
315
  * batch's end; in between the graph must not fall back to the override it
200
316
  * has left) — or the displayed override for a stale (render) reader of some
201
317
  * OTHER transaction, the same visibility a foreign transaction's staged
202
- * write has. */ function supersededRead(e) {
203
- if (stale && e.ge && activeTransition !== e.ge) return unwrapOverride(e.o?.be);
204
- return e.Ge !== NOT_PENDING ? e.Ge : e.me;
318
+ * write has. */
319
+ /**
320
+ * A tracked read of an active override (read()'s override arm). Lanes mirror
321
+ * transitions (#3460): a render effect OFF the override's held lane — re-run
322
+ * by a sync write, or mounted mid-hold — sees the committed value, as a stale
323
+ * reader of a held transaction does, and publishes now; the lane's release
324
+ * re-runs it (readsHeldCommitted). The lane defers the override's own readers'
325
+ * runs, so the committed value is what is on screen — the override is the
326
+ * visible value only once the lane has revealed (or, demoted at body-end,
327
+ * A18). Otherwise the override displays, unless the node's own source
328
+ * answered with a DIFFERENT value (A18 supersession, #3331): the optimism is
329
+ * over for the graph — a tracked reader sees the staged truth — while the
330
+ * override remains the DISPLAYED value for untracked reads (and for a stale
331
+ * reader of some other transaction).
332
+ */ function overrideRead(e, n) {
333
+ if (stale && readsHeldCommitted(e, n)) return e.Qe;
334
+ if (!(e.T & CONFIG_OVERRIDE_SUPERSEDED)) return unwrapOverride(e.o?.Ce);
335
+ // The owning transaction: `_overrideOwner` (#2912), not the stamp — an
336
+ // override written directly inside an action never passes the adoption
337
+ // loop that stamps `_transition`, and a body-end supersession (#3427)
338
+ // stages nothing that would queue it. Without the owner a stale reader of
339
+ // a body-ended node read the committed truth beside a display still
340
+ // showing the override.
341
+ const i = resolveTransition(e);
342
+ if (stale && i && activeTransition !== i) return unwrapOverride(e.o?.Ce);
343
+ // A superseded read is a staged read (A29) whether the truth is staged or
344
+ // already committed: the pass that derives from it derives from the
345
+ // owning transaction's world (the override is still displayed by it).
346
+ enterStagedRead(e, i);
347
+ return e.ve !== NOT_PENDING ? e.ve : e.Qe;
205
348
  }
206
349
 
207
350
  /**
@@ -216,11 +359,11 @@ function resolveOptimisticNodes(e) {
216
359
  * landing took setSignal's plain path: a differing truth staged silently
217
360
  * under the override and the graph never moved until the commit.
218
361
  */ function landOnOverride(e, n) {
219
- const i = e.Ge === NOT_PENDING ? e.me : e.Ge;
362
+ const i = e.ve === NOT_PENDING ? e.Qe : e.ve;
220
363
  if (typeof n === "function") n = n(i);
221
- if (e.Ge === NOT_PENDING) queuePendingNode(e);
222
- e.Ge = n;
223
- GlobalQueue.pe?.(e, n);
364
+ if (e.ve === NOT_PENDING) queuePendingNode(e);
365
+ e.ve = n;
366
+ GlobalQueue.me?.(e, n);
224
367
  supersedeOverride(e, n);
225
368
  schedule();
226
369
  return n;
@@ -235,32 +378,32 @@ function runQueue(e, n) {
235
378
  * laneHeld).
236
379
  */ function runLaneEffects(e) {
237
380
  for (const n of activeLanes) {
238
- if (n.rn || laneHeld(n)) continue;
239
- const i = n.tn[e - 1];
381
+ if (n.cn || laneHeld(n)) continue;
382
+ const i = n.fn[e - 1];
240
383
  if (i.length) {
241
- n.tn[e - 1] = [];
384
+ n.fn[e - 1] = [];
242
385
  runQueue(i, e);
243
386
  }
244
387
  }
245
388
  // Optimistic patch applications ride the same visibility slot as lane
246
389
  // effects (in-flight DOM updates); no-op unless patches registered.
247
- if (e === EFFECT_RENDER) GlobalQueue.ln?.();
390
+ if (e === EFFECT_RENDER) GlobalQueue.In?.();
248
391
  }
249
392
 
250
393
  function cleanupCompletedLanes(e) {
251
394
  for (const n of activeLanes) {
252
- const i = e ? n.ge === e : !n.ge;
395
+ const i = e ? n.Ge === e : !n.Ge;
253
396
  if (!i) continue;
254
- if (!n.rn) {
255
- if (n.tn[0].length) runQueue(n.tn[0], EFFECT_RENDER);
256
- if (n.tn[1].length) runQueue(n.tn[1], EFFECT_USER);
397
+ if (!n.cn) {
398
+ if (n.fn[0].length) runQueue(n.fn[0], EFFECT_RENDER);
399
+ if (n.fn[1].length) runQueue(n.fn[1], EFFECT_USER);
257
400
  }
258
- if (n.nn.o?.Oe === n) if (n.nn.o !== null) n.nn.o.Oe = undefined;
259
- n.he.clear();
260
- n.tn[0].length = 0;
261
- n.tn[1].length = 0;
401
+ if (n.an.o?.Ue === n) if (n.an.o !== null) n.an.o.Ue = undefined;
402
+ n.ye.clear();
403
+ n.fn[0].length = 0;
404
+ n.fn[1].length = 0;
262
405
  activeLanes.delete(n);
263
- signalLanes.delete(n.nn);
406
+ signalLanes.delete(n.an);
264
407
  }
265
408
  }
266
409
 
@@ -274,11 +417,13 @@ function cleanupCompletedLanes(e) {
274
417
  // this is only reachable under a lane, which implies the engine.
275
418
  if (e.S & STATUS_UNINITIALIZED) return true;
276
419
  // Per-lane suspension: only throw if in same lane as pending async
277
- // AND the node doesn't have an active override (overrides are the visible value,
278
- // downstream in the lane should read the override, not throw)
279
- const n = e.o?.Oe;
420
+ // AND the node doesn't have an active WRITTEN override (overrides are the
421
+ // visible value, downstream in the lane should read the override, not
422
+ // throw). A derived override (#3479) is a previous speculative answer, not
423
+ // an intent: the re-ask pending behind it suspends like any lane async.
424
+ const n = e.o?.Ue;
280
425
  if (!n) return false;
281
- return findLane(n) === findLane(currentOptimisticLane) && !hasActiveOverride(e);
426
+ return findLane(n) === findLane(currentOptimisticLane) && (!hasActiveOverride(e) || (e.T & CONFIG_DERIVED_OVERRIDE) !== 0);
282
427
  }
283
428
 
284
429
  /**
@@ -298,10 +443,10 @@ function cleanupCompletedLanes(e) {
298
443
  * that reads a pending mid-transition write sees the committed value; the sub
299
444
  * is recorded for replay at commit.
300
445
  */ function gatedRead(e, n, i) {
301
- if (latestReadActive || e.Ge === NOT_PENDING || e.oe || n !== e && !(n.ie & REACTIVE_MANUAL_WRITE)) {
446
+ if (latestReadActive || e.ve === NOT_PENDING || e.ce || n !== e && !(n.ue & REACTIVE_MANUAL_WRITE)) {
302
447
  return false;
303
448
  }
304
- activeTransition.lt.add(i);
449
+ activeTransition.ct.add(i);
305
450
  return true;
306
451
  }
307
452
 
@@ -309,7 +454,7 @@ function cleanupCompletedLanes(e) {
309
454
  * read()'s value selection under a lane: return the committed `_value` for
310
455
  * optimistic/lane-assigned signals, stale-mode reads, and pending owners.
311
456
  */ function laneReadsCommitted(e, n, i) {
312
- if (e.o?.be !== undefined || !!e.o?.Oe || !!(n.S & STATUS_PENDING)) {
457
+ if (e.o?.Ce !== undefined || !!e.o?.Ue || !!(n.S & STATUS_PENDING)) {
313
458
  // The committed view hides a staged in-flight value that will promote
314
459
  // silently (commitPendingNode never re-notifies). gatedRead records plain
315
460
  // signals for replay at commit; async memos are excluded from it by the
@@ -324,10 +469,10 @@ function cleanupCompletedLanes(e) {
324
469
  // against an unchanged frame (#3330). An override-covered node's revert
325
470
  // notifies its own subscribers when the truth differs (resolveOptimistic
326
471
  // Nodes), so the reader is recorded only for the staged-vs-committed gap.
327
- if (e.Ge !== NOT_PENDING && e.Ge !== e.me) (activeTransition ?? globalQueue.m).lt.add(i);
472
+ if (e.ve !== NOT_PENDING && e.ve !== e.Qe) (activeTransition ?? globalQueue.m).ct.add(i);
328
473
  return true;
329
474
  }
330
- if (n === e && stale && i.o?.Gt !== e) {
475
+ if (n === e && stale && i.o?.Ht !== e) {
331
476
  // The committed view can hide a staged write (a lane member — even just
332
477
  // an isPending companion flip — puts the reader "under a lane"). The
333
478
  // staged value commits with no re-delivery (commitPendingNode never
@@ -339,7 +484,7 @@ function cleanupCompletedLanes(e) {
339
484
  // into the transaction (#3041 follow-up: a pending-gated branch that
340
485
  // first read its async source during the landing flush stayed one value
341
486
  // behind permanently); with none, into the ambient batch.
342
- if (e.Ge !== NOT_PENDING) (activeTransition ?? globalQueue.m).lt.add(i);
487
+ if (e.ve !== NOT_PENDING) (activeTransition ?? globalQueue.m).ct.add(i);
343
488
  return true;
344
489
  }
345
490
  return false;
@@ -362,18 +507,18 @@ function cleanupCompletedLanes(e) {
362
507
  // recompute() runs plain: the value stages and commits with the flush.
363
508
  // (el's own override slot excludes companions themselves; a lane merged
364
509
  // into a real optimistic lane resolves to a non-companion source.)
365
- if (!globalQueue.sn && !activeTransition && !n.ge && n.nn.o?.Gt !== undefined && e.o?.be === undefined) {
366
- if (e.o !== null) e.o.Oe = undefined;
510
+ if (!globalQueue.Kt && !activeTransition && !n.Ge && n.an.o?.Ht !== undefined && e.o?.Ce === undefined) {
511
+ if (e.o !== null) e.o.Ue = undefined;
367
512
  return false;
368
513
  }
369
514
  return n;
370
515
  }
371
- for (let n = e.fe; n; n = n.ae) {
372
- const i = n.Se;
373
- if (i.ie & REACTIVE_OPTIMISTIC_DIRTY) {
516
+ for (let n = e.Se; n; n = n.de) {
517
+ const i = n.Ee;
518
+ if (i.ue & REACTIVE_OPTIMISTIC_DIRTY) {
374
519
  const n = resolveLane(i);
375
520
  if (n) {
376
- e.ie |= REACTIVE_OPTIMISTIC_DIRTY;
521
+ e.ue |= REACTIVE_OPTIMISTIC_DIRTY;
377
522
  assignOrMergeLane(e, n);
378
523
  return n;
379
524
  }
@@ -387,9 +532,9 @@ function cleanupCompletedLanes(e) {
387
532
  * companion is NOT refreshed here: its verdict never read _pendingAsync, and
388
533
  * the source's own write/commit/settlement paths keep it current. */ function laneAsyncPending(e) {
389
534
  const n = findLane(currentOptimisticLane);
390
- if (n.nn !== e) {
391
- n.he.add(e);
392
- ext(e).Oe = n;
535
+ if (n.an !== e) {
536
+ n.ye.add(e);
537
+ ext(e).Ue = n;
393
538
  e.T |= CONFIG_HAS_LANE;
394
539
  }
395
540
  }
@@ -397,13 +542,13 @@ function cleanupCompletedLanes(e) {
397
542
  /** recompute()'s success path: the node's async settled, clear it from its lane. */ function laneAsyncSettled(e) {
398
543
  const n = resolveLane(e);
399
544
  if (n) {
400
- n.he.delete(e);
545
+ n.ye.delete(e);
401
546
  }
402
547
  }
403
548
 
404
549
  function trackOptimisticStore(e) {
405
550
  // After initTransition, globalQueue._batch IS activeTransition (same reference)
406
- globalQueue.m.En.add(e);
551
+ globalQueue.m.dn.add(e);
407
552
  schedule();
408
553
  }
409
554
 
@@ -412,23 +557,25 @@ function trackOptimisticStore(e) {
412
557
  * create optimistic state (verdict.ts at module top level, createOptimistic
413
558
  * and createOptimisticStore at first call) BEFORE any optimistic node exists.
414
559
  */ function installOptimisticEngine() {
415
- if (GlobalQueue.Bt !== null) return;
416
- GlobalQueue.Bt = optimisticWrite;
417
- GlobalQueue.fn = resolveOptimisticNodes;
418
- GlobalQueue.cn = transitionBlocked;
419
- GlobalQueue.dn = cleanupCompletedLanes;
420
- GlobalQueue.In = runLaneEffects;
421
- GlobalQueue.ye = supersedeOverride;
422
- GlobalQueue.Yt = supersededRead;
423
- GlobalQueue.zt = landOnOverride;
424
- GlobalQueue.Zt = gatedRead;
425
- GlobalQueue.qt = laneSuspends;
426
- GlobalQueue.Mt = laneLive;
427
- GlobalQueue.Kt = laneReadsCommitted;
428
- GlobalQueue.nt = recomputeLane;
429
- GlobalQueue.ot = laneAsyncPending;
430
- GlobalQueue.ut = laneAsyncSettled;
431
- GlobalQueue.Nn = trackOptimisticStore;
560
+ if (GlobalQueue.ln !== null) return;
561
+ GlobalQueue.ln = optimisticWrite;
562
+ GlobalQueue.On = resolveOptimisticNodes;
563
+ GlobalQueue.Nn = transitionBlocked;
564
+ GlobalQueue.Rn = cleanupCompletedLanes;
565
+ GlobalQueue._n = runLaneEffects;
566
+ GlobalQueue.we = supersedeOverride;
567
+ GlobalQueue.Tn = endOptimism;
568
+ GlobalQueue.en = overrideRead;
569
+ GlobalQueue.Ve = laneOverride;
570
+ GlobalQueue.un = landOnOverride;
571
+ GlobalQueue.tn = gatedRead;
572
+ GlobalQueue.$t = laneSuspends;
573
+ GlobalQueue.Xt = laneLive;
574
+ GlobalQueue.Bt = laneReadsCommitted;
575
+ GlobalQueue.st = recomputeLane;
576
+ GlobalQueue._t = laneAsyncPending;
577
+ GlobalQueue.ft = laneAsyncSettled;
578
+ GlobalQueue.Dn = trackOptimisticStore;
432
579
  }
433
580
 
434
581
  export { installOptimisticEngine };