@solidjs/signals 2.0.0-rc.19 → 2.0.0-rc.20

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 (74) hide show
  1. package/dist/dev-shared.js +553 -264
  2. package/dist/dev.attribution.js +18 -18
  3. package/dist/dev.js +1030 -439
  4. package/dist/observe/affects.js +12 -2
  5. package/dist/observe/boundaries.js +168 -115
  6. package/dist/observe/core/async.js +57 -37
  7. package/dist/observe/core/attribution.js +6 -6
  8. package/dist/observe/core/constants.js +9 -1
  9. package/dist/observe/core/copies.js +10 -0
  10. package/dist/observe/core/core.js +261 -181
  11. package/dist/observe/core/effect.js +32 -27
  12. package/dist/observe/core/graph.js +7 -7
  13. package/dist/observe/core/heap.js +29 -29
  14. package/dist/observe/core/lanes.js +301 -101
  15. package/dist/observe/core/owner.js +13 -13
  16. package/dist/observe/core/scheduler.js +124 -69
  17. package/dist/observe/core/truth.js +9 -7
  18. package/dist/observe/core/verdict.js +160 -98
  19. package/dist/observe/deferred.js +1 -1
  20. package/dist/observe/index.js +2 -0
  21. package/dist/observe/map.js +120 -116
  22. package/dist/observe/reveal.js +48 -48
  23. package/dist/observe/signals.js +5 -5
  24. package/dist/observe/store/affects.js +2 -2
  25. package/dist/observe/store/optimistic.js +272 -176
  26. package/dist/observe/store/projection.js +21 -10
  27. package/dist/observe/store/reconcile.js +8 -2
  28. package/dist/observe/store/store.js +91 -55
  29. package/dist/observe/store/types.js +11 -1
  30. package/dist/observe/store/utils.js +1 -1
  31. package/dist/prod/affects.js +12 -2
  32. package/dist/prod/boundaries.js +164 -109
  33. package/dist/prod/core/async.js +201 -181
  34. package/dist/prod/core/constants.js +9 -1
  35. package/dist/prod/core/copies.js +10 -0
  36. package/dist/prod/core/core.js +244 -164
  37. package/dist/prod/core/dev.js +108 -3
  38. package/dist/prod/core/effect.js +28 -23
  39. package/dist/prod/core/graph.js +9 -9
  40. package/dist/prod/core/heap.js +16 -16
  41. package/dist/prod/core/identities.js +1 -1
  42. package/dist/prod/core/lanes.js +307 -95
  43. package/dist/prod/core/owner.js +22 -22
  44. package/dist/prod/core/scheduler.js +266 -211
  45. package/dist/prod/core/truth.js +9 -7
  46. package/dist/prod/core/verdict.js +161 -99
  47. package/dist/prod/deferred.js +1 -1
  48. package/dist/prod/index.js +2 -0
  49. package/dist/prod/map.js +78 -74
  50. package/dist/prod/reveal.js +34 -34
  51. package/dist/prod/signals.js +3 -3
  52. package/dist/prod/store/affects.js +15 -15
  53. package/dist/prod/store/optimistic.js +185 -89
  54. package/dist/prod/store/projection.js +49 -38
  55. package/dist/prod/store/reconcile.js +8 -2
  56. package/dist/prod/store/store.js +99 -63
  57. package/dist/prod/store/types.js +11 -1
  58. package/dist/types/affects.d.ts +3 -2
  59. package/dist/types/boundaries.d.ts +14 -2
  60. package/dist/types/core/async.d.ts +2 -1
  61. package/dist/types/core/constants.d.ts +8 -0
  62. package/dist/types/core/copies.d.ts +54 -0
  63. package/dist/types/core/core.d.ts +15 -0
  64. package/dist/types/core/dev.d.ts +1 -1
  65. package/dist/types/core/lanes.d.ts +8 -1
  66. package/dist/types/core/scheduler.d.ts +36 -4
  67. package/dist/types/core/truth.d.ts +3 -1
  68. package/dist/types/core/types.d.ts +6 -0
  69. package/dist/types/index.d.ts +2 -0
  70. package/dist/types/store/hooks.d.ts +15 -1
  71. package/dist/types/store/store.d.ts +2 -1
  72. package/dist/types/store/target.d.ts +5 -0
  73. package/dist/types/store/types.d.ts +7 -0
  74. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { STATUS_ERROR, STATUS_PENDING, STATUS_NO_VALUE, STATUS_UNINITIALIZED, CONFIG_GUESS, REACTIVE_RECOMPUTING_DEPS, CONFIG_HELD, REACTIVE_STAGED_READ, CONFIG_STAGED, CONFIG_STAGED_ERROR, CONFIG_AUTO_DISPOSE, REACTIVE_ZOMBIE, NewSet, REACTIVE_DIRTY, CONFIG_INPUTS_PUBLISHED, NOT_PENDING, REACTIVE_DISPOSED, CONFIG_REDERIVE, CONFIG_VERDICT, CONFIG_OVERRIDE } from "./constants.js";
1
+ import { STATUS_ERROR, STATUS_PENDING, STATUS_NO_VALUE, STATUS_UNINITIALIZED, CONFIG_GUESS, REACTIVE_REASK, REACTIVE_RECOMPUTING_DEPS, CONFIG_ASYNC, REACTIVE_WINDOW, CONFIG_HELD, REACTIVE_STAGED_READ, CONFIG_STAGED, CONFIG_STAGED_ERROR, CONFIG_AUTO_DISPOSE, REACTIVE_ZOMBIE, NewSet, REACTIVE_DIRTY, CONFIG_INPUTS_PUBLISHED, NOT_PENDING, REACTIVE_DISPOSED, CONFIG_REDERIVE, CONFIG_VERDICT, CONFIG_OVERRIDE } from "./constants.js";
2
2
 
3
3
  import { attrHooks } from "./attribution-hooks.js";
4
4
 
@@ -14,7 +14,7 @@ import { enqueueSub } from "./heap.js";
14
14
 
15
15
  import { disposeChildren, cleanup } from "./owner.js";
16
16
 
17
- import { passLane, joinFuture, question, MAINLINE_QUESTION, globalQueue, schedule, clock, flush, freshHook, txOf, laneStageHook, queuePendingNode } from "./scheduler.js";
17
+ import { guessing, passLane, joinFuture, txOf, holdWorkHook, question, MAINLINE_QUESTION, globalQueue, schedule, clock, flush, freshHook, laneStageHook, queuePendingNode } from "./scheduler.js";
18
18
 
19
19
  // The lazily-created Set is the ONE container for pending sources. Its
20
20
  // predecessor — a singular slot promoted to a Set on the second source —
@@ -71,16 +71,16 @@ function retryReaches(e, t) {
71
71
 
72
72
  function setPendingError(e, t, n) {
73
73
  if (!t) {
74
- if (e.T !== null) e.T.F = null;
74
+ if (e.T !== null) e.T.U = null;
75
75
  return;
76
76
  }
77
77
  if (n instanceof NotReadyError && n.source === t) {
78
- ext(e).F = n;
78
+ ext(e).U = n;
79
79
  return;
80
80
  }
81
- const r = e.T?.F;
81
+ const r = e.T?.U;
82
82
  if (!(r instanceof NotReadyError) || r.source !== t) {
83
- ext(e).F = new NotReadyError(t);
83
+ ext(e).U = new NotReadyError(t);
84
84
  }
85
85
  }
86
86
 
@@ -150,13 +150,13 @@ function releaseSettledDependents(e) {
150
150
  // (#4109). A flush that parks nothing publishes it at its commit (S-38).
151
151
  // Not a projection's derive: its readers learn its error through the
152
152
  // family, which the commit's publish never reaches (#4189).
153
- if (!(e.l & CONFIG_HELD || n && e.R & REACTIVE_STAGED_READ && globalQueue.q && !e.fam) || passLane) return false;
153
+ if (!(e.l & CONFIG_HELD || n && e.R & REACTIVE_STAGED_READ && globalQueue.Y && !e.fam) || passLane) return false;
154
154
  // The node answered (an error ends the wait — no longer pending, nor
155
155
  // blocked); a shown error stays its display until the commit.
156
156
  clearPendingSources(e);
157
157
  if (e.T) e.T.fe = false;
158
158
  if (!((e.m &= STATUS_ERROR | STATUS_UNINITIALIZED) & STATUS_ERROR)) setPendingError(e);
159
- e.ie = t instanceof StatusError ? t : new StatusError(e, t);
159
+ e.ue = t instanceof StatusError ? t : new StatusError(e, t);
160
160
  e.l |= CONFIG_STAGED | CONFIG_STAGED_ERROR;
161
161
  // Readers parked on the flight re-run and derive from the staging; the
162
162
  // verdict readers the walk wakes need a flush (#4106).
@@ -171,7 +171,7 @@ function settleErroredDependents(e, t) {
171
171
  const visit = e => {
172
172
  if (r.has(e)) return;
173
173
  r.add(e);
174
- if (e.T?.F === t) {
174
+ if (e.T?.U === t) {
175
175
  enqueueSub(e);
176
176
  n = true;
177
177
  }
@@ -205,10 +205,11 @@ function settlePendingSource(e, t = e) {
205
205
  // A19: a verdict reader holds no pending of its own (it was re-derived
206
206
  // when the source went pending, `propagateStatus`), and a landing
207
207
  // equal to the committed value notifies nobody — the source settling
208
- // is its verdict changing: it runs again.
209
- return s.l & CONFIG_VERDICT && enqueueSub(s);
208
+ // is its verdict changing: it runs again. (Verdict readers exist only
209
+ // with the verdict engine installed.)
210
+ return holdWorkHook && s.l & CONFIG_VERDICT && enqueueSub(s);
210
211
  o.add(s);
211
- s.ae = clock;
212
+ s.ie = clock;
212
213
  const f = s.T?.se?.values().next().value;
213
214
  // STATUS_ERROR + pending sources only coexist via an errored loading
214
215
  // window's park (notifyStatus(STATUS_ERROR) clears pending sources
@@ -301,7 +302,10 @@ r) {
301
302
  });
302
303
  }
303
304
  if (!s && !o) {
304
- if (e.T !== null) e.T.Ee = null;
305
+ if (e.T !== null) {
306
+ e.T.Ee = null;
307
+ if (holdWorkHook) e.l &= ~CONFIG_ASYNC;
308
+ }
305
309
  // A sync landing is the first real answer for a loadingValue node.
306
310
  e.ce = false;
307
311
  return t;
@@ -312,9 +316,14 @@ r) {
312
316
  // fired _flightTeardown. A future non-recompute registration path must
313
317
  // release it here before overwriting _inFlight.
314
318
  ext(e).Ee = t;
319
+ // D-25 (verdict.ts `holdWork`): an async memo whose answering pass opened
320
+ // no verdict window of its own (`markVerdictReader` clears the bit).
321
+ // Kept by the verdict engine alone (`holdWorkHook`): a build without it
322
+ // folds the bit's upkeep away.
323
+ if (holdWorkHook && !(e.R & REACTIVE_WINDOW)) e.l |= CONFIG_ASYNC;
315
324
  // The question this flight answers (A18 provenance, lanes.ts): the action
316
325
  // whose slice asked it; mainline is always the current question.
317
- e.T.de = question || MAINLINE_QUESTION;
326
+ e.T.Ie = question || MAINLINE_QUESTION;
318
327
  // The run that asked this flight read every input without throwing: an
319
328
  // input still in flight was masked for it (an active override, A17), so
320
329
  // pending state those inputs propagated onto the node earlier does not
@@ -340,7 +349,7 @@ r) {
340
349
  // error-retry pull (updateIfNecessary) can also re-ask.
341
350
  if (e.T !== null) e.T.Ee = null;
342
351
  parkLoadingWindow(e, o);
343
- e.ae = clock;
352
+ e.ie = clock;
344
353
  return;
345
354
  }
346
355
  // D-41: a held node's error is staged (`stageError`). A derived store's
@@ -358,7 +367,7 @@ r) {
358
367
  // rejected flight will never settle its self entry, so transfer ownership
359
368
  // after notifyStatus has propagated the replacement source.
360
369
  if (s) settlePendingSource(e);
361
- e.ae = clock;
370
+ e.ie = clock;
362
371
  // A real error settles derivatively-pending dependents (notifyStatus
363
372
  // cleared their pending sources), so stranded lazy ones release here —
364
373
  // the error twin of settlePendingSource's release (#2934).
@@ -390,7 +399,7 @@ r) {
390
399
  // a verdict reader of the next flight would suspend instead of being
391
400
  // served the screen; held, both at the derive's commit.
392
401
  if (!(e.l & CONFIG_HELD)) {
393
- e.T.Te = undefined;
402
+ e.T.Te = null;
394
403
  e.l &= ~CONFIG_INPUTS_PUBLISHED;
395
404
  }
396
405
  if (s) landStatus(e, true);
@@ -422,7 +431,7 @@ r) {
422
431
  // (`_pendingValue` set inside setSignal) is not — commitPendingNode closes
423
432
  // the window when the flush commits it, so no one-frame pulse can leak to
424
433
  // observers between the landing and its commit (#2990).
425
- if (e.ie === NOT_PENDING) {
434
+ if (e.ue === NOT_PENDING) {
426
435
  e.ce = false;
427
436
  // The landing published: the dependency tail the flight's pass left
428
437
  // linked goes now (A30, #3410). A staged landing has not replaced the
@@ -494,7 +503,7 @@ r) {
494
503
  }
495
504
  };
496
505
  const iterate = () => {
497
- let n, r, l = false, a = false, S = true;
506
+ let n, r, l = false, S = false, a = true;
498
507
  // Protocol tolerance, matching `for await`: `await` unwraps whatever
499
508
  // next() returns — a thenable OR a bare IteratorResult. Real producers
500
509
  // use the bare form as a promise-free fast path when a value is already
@@ -512,7 +521,7 @@ r) {
512
521
  // stash: it must write through the async path or the value is
513
522
  // silently dropped. (The deferred posture never has a caller, so
514
523
  // initialRead starts false there and everything writes through.)
515
- if (S && i) {
524
+ if (a && i) {
516
525
  n = r;
517
526
  l = true;
518
527
  if (r.done) u = true;
@@ -533,17 +542,17 @@ r) {
533
542
  settleAutodispose();
534
543
  }
535
544
  }, n => {
536
- if (S && i) {
545
+ if (a && i) {
537
546
  r = n;
538
- a = true;
547
+ S = true;
539
548
  } else if (e.T?.Ee === t) {
540
549
  u = true;
541
550
  handleError(n);
542
551
  settleAutodispose();
543
552
  }
544
553
  });
545
- S = false;
546
- if (a) {
554
+ a = false;
555
+ if (S) {
547
556
  // Match the promise branch, but only rethrow during the initial read.
548
557
  u = true;
549
558
  handleError(r);
@@ -657,7 +666,7 @@ function clearStatus(e, t = false) {
657
666
  if (e.T?.se) clearPendingSources(e);
658
667
  if (e.T?.fe) e.T.fe = false;
659
668
  e.m = t ? 0 : e.m & STATUS_UNINITIALIZED;
660
- if (e.T?.F) setPendingError(e);
669
+ if (e.T?.U) setPendingError(e);
661
670
  const n = statusNotifierOf(e);
662
671
  if (n) n.call(e);
663
672
  }
@@ -699,11 +708,11 @@ function clearStatus(e, t = false) {
699
708
  function notifyStatus(e, t, n) {
700
709
  // Wrap regular errors to track source node
701
710
  if (t === STATUS_ERROR && !(n instanceof StatusError) && !(n instanceof NotReadyError)) n = new StatusError(e, n);
702
- const r = t === STATUS_PENDING && n instanceof NotReadyError ? n.source : undefined;
711
+ const r = t === STATUS_PENDING && n instanceof NotReadyError && n.source;
703
712
  // (CARVE 2: the lane assignment went with the engine.)
704
713
  if (t === STATUS_PENDING && r) {
705
714
  // D-41: a re-ask of a shown error keeps it the display (`_shownError`).
706
- if (e.m & STATUS_ERROR) e.T.Te = e.T.F;
715
+ if (e.m & STATUS_ERROR) e.T.Te = e.T.U;
707
716
  addPendingSource(e, r);
708
717
  // A re-ask of an error that answered the first read: still no value.
709
718
  e.m = STATUS_PENDING | (e.m & STATUS_NO_VALUE ? STATUS_UNINITIALIZED : e.m & STATUS_UNINITIALIZED);
@@ -715,16 +724,21 @@ function notifyStatus(e, t, n) {
715
724
  // An error answering a node with no value marks it so; a re-ask of it
716
725
  // (pending) is uninitialized again; a write (STATUS_NONE) gives it one.
717
726
  e.m = t | (t === STATUS_ERROR ? e.m & (STATUS_UNINITIALIZED | STATUS_NO_VALUE) ? STATUS_NO_VALUE : 0 : t === STATUS_PENDING && e.m & STATUS_NO_VALUE ? STATUS_UNINITIALIZED : e.m & STATUS_UNINITIALIZED);
718
- ext(e).F = n;
727
+ ext(e).U = n;
719
728
  }
720
729
  // Lanes: a written guess is an optimistic boundary (A17 — "the optimistic
721
730
  // future value until we know otherwise"). Its own source in flight is its
722
731
  // status, not its readers': they read the guess. The flight is the parent
723
732
  // transition's to wait on — the frame it was asked in holds (A17: "a
724
733
  // transition whose optimistic node is still pending on its own fetch is
725
- // not complete"), through the node itself (`blocked`).
726
- if (t === STATUS_PENDING && e.l & CONFIG_GUESS) {
727
- if (passLane === null) joinFuture(null);
734
+ // not complete"), through the node itself (`blocked`). An input changed
735
+ // from outside the guess's hold asks a new question: the frame that
736
+ // changed it is held with that hold (D-34, #4336) — it shows beside the
737
+ // guess's truth, which reveals at that hold's commit (F-1). A `refresh()`
738
+ // re-asks the same question: its frame is its own.
739
+ // (No guess written, no arm.)
740
+ if (guessing && t === STATUS_PENDING && e.l & CONFIG_GUESS) {
741
+ if (passLane === null) joinFuture(e.R & REACTIVE_REASK ? null : txOf(e)._parent);
728
742
  return;
729
743
  }
730
744
  const o = statusNotifierOf(e);
@@ -740,9 +754,9 @@ function notifyStatus(e, t, n) {
740
754
  * family's leaves, which are not the derive's dependents — the family
741
755
  * propagates the derive's status from each leaf to the leaf's readers
742
756
  * (store/projection.ts `wakeFamily`), exactly as a memo's would reach its. */ function propagateStatus(e, t, n) {
743
- const r = t === STATUS_PENDING && n instanceof NotReadyError ? n.source : undefined;
757
+ const r = t === STATUS_PENDING && n instanceof NotReadyError && n.source;
744
758
  forEachDependent(e, (o, s) => {
745
- o.ae = clock;
759
+ o.ie = clock;
746
760
  // A pending mark on a kept-tail link re-derives the subscriber instead of
747
761
  // marking it (A30, #3494 review; fuzzer latest-1 #2141; #3519 review).
748
762
  // Past `_depsTail` lie the committed frame's deps, kept by A30 because
@@ -762,7 +776,13 @@ function notifyStatus(e, t, n) {
762
776
  // Inheriting the error would make a probe's reader errored. A boundary's
763
777
  // output (CONFIG_REDERIVE, boundaries.ts) the same: content or fallback
764
778
  // is its pass's call.
765
- if (o.l & (CONFIG_REDERIVE | CONFIG_VERDICT) || t === STATUS_PENDING && s.Ie !== o.Ne) {
779
+ // Not one D-25 makes the hold's work (verdict.ts `holdWork`): an async
780
+ // memo with no verdict window of its own reads a verdict memo's value,
781
+ // and that source going pending changes none of its reads — re-derived,
782
+ // it is served the committed value it already derived from (A10) and
783
+ // asks that question again. It waits on the source like any derivation
784
+ // (F-9), and asks its next question once, at the landing (#4397).
785
+ if (o.l & CONFIG_REDERIVE || holdWorkHook && o.l & CONFIG_VERDICT && !(r && holdWorkHook(o, e)) || t === STATUS_PENDING && s.de !== o.Ne) {
766
786
  enqueueSub(o);
767
787
  schedule();
768
788
  return;
@@ -775,10 +795,10 @@ function notifyStatus(e, t, n) {
775
795
  // shape: the unmount it stages makes the observer a zombie whose say is
776
796
  // moot for this transaction, A15 #3463).
777
797
  if (t === STATUS_PENDING && r && o.T?.se?.has(r)) {
778
- if (passLane === null && (o.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && globalQueue.q && !freshHook?.(o, r.ae === clock)) joinFuture(txOf(o));
798
+ if (passLane === null && (o.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && globalQueue.Y && !freshHook?.(o, r.ie === clock)) joinFuture(txOf(o));
779
799
  return;
780
800
  }
781
- if (t === STATUS_PENDING && r || t !== STATUS_PENDING && (o.T?.F !== n || o.T?.se)) {
801
+ if (t === STATUS_PENDING && r || t !== STATUS_PENDING && (o.T?.U !== n || o.T?.se)) {
782
802
  // The marked subscriber is queued for the commit sweep so its status
783
803
  // bookkeeping (loading window, uninitialized clear) runs with the flush
784
804
  // — with the lane, when the pass propagating is the lane's work and
@@ -801,4 +821,4 @@ function notifyStatus(e, t, n) {
801
821
  });
802
822
  }
803
823
 
804
- export { addPendingSource, clearStatus, forEachDependent, handleAsync, isThenable, notifyStatus, onSupersede, parkLoadingWindow, propagateStatus, releaseFlightTeardown, releaseIfSettledUnobserved, releaseSettledDependents, setPendingError, settleErroredDependents, settlePendingSource, stageError };
824
+ export { addPendingSource, clearStatus, forEachDependent, handleAsync, isThenable, notifyStatus, onSupersede, parkLoadingWindow, propagateStatus, releaseFlightTeardown, releaseIfSettledUnobserved, releaseSettledDependents, removePendingSource, setPendingError, settleErroredDependents, settlePendingSource, stageError };
@@ -2705,7 +2705,7 @@ const engineHooks = {
2705
2705
  prevDeps: n || !wantsRerun() ? null : captureDeps(e),
2706
2706
  // Mirror recompute's own prev-value resolution: an earlier run in the
2707
2707
  // same flush may still be holding in _pendingValue.
2708
- prevValue: e.ie !== NOT_PENDING ? e.ie : e.le,
2708
+ prevValue: e.ue !== NOT_PENDING ? e.ue : e.le,
2709
2709
  // A create run inherits the interaction of whatever is building it: the
2710
2710
  // enclosing recompute (a parent's fn creating children) or, at the top
2711
2711
  // of the recompute stack, the effect callback / handler frame.
@@ -2732,7 +2732,7 @@ const engineHooks = {
2732
2732
  // exempt — a side-effect-only compute's work IS its effect phase, and
2733
2733
  // identity of `undefined` proves nothing.
2734
2734
  if (t && r.causes !== null && e.i) {
2735
- const n = e.ie !== NOT_PENDING ? e.ie : e.le;
2735
+ const n = e.ue !== NOT_PENDING ? e.ue : e.le;
2736
2736
  if (n !== undefined && n === r.prevValue) t = false;
2737
2737
  }
2738
2738
  // Unstable-output check: memos only, non-create, plain runs with a
@@ -2740,12 +2740,12 @@ const engineHooks = {
2740
2740
  // plain-flush memo commits and in `_value` for direct ones. Overlay runs
2741
2741
  // are excluded — an optimistic re-derive legitimately produces fresh
2742
2742
  // equivalents while the lane settles.
2743
- if (r.causes !== null && t && !o && !i && !e.i) checkUnstableOutput(e, r.prevValue, e.ie !== NOT_PENDING ? e.ie : e.le);
2743
+ if (r.causes !== null && t && !o && !i && !e.i) checkUnstableOutput(e, r.prevValue, e.ue !== NOT_PENDING ? e.ue : e.le);
2744
2744
  // The same exemption for memos: a run that committed `undefined` did its
2745
2745
  // work as a side effect (a projection's draft writes or reconcile, a
2746
2746
  // write from inside a memo), so core's `undefined === undefined` gate
2747
2747
  // proves nothing. Reported as changed, so no consumer counts it as waste.
2748
- if (!t && (e.ie !== NOT_PENDING ? e.ie : e.le) === undefined) t = true;
2748
+ if (!t && (e.ue !== NOT_PENDING ? e.ue : e.le) === undefined) t = true;
2749
2749
  if (r.causes !== null) recordRerun(e, r, {
2750
2750
  selfMs: c,
2751
2751
  totalMs: a
@@ -2788,7 +2788,7 @@ const engineHooks = {
2788
2788
  },
2789
2789
  asyncStart(e) {
2790
2790
  asyncStartSeq = e.ge?.seq ?? 0;
2791
- asyncStartTime = e.ae;
2791
+ asyncStartTime = e.ie;
2792
2792
  asyncStartValue = e.le;
2793
2793
  },
2794
2794
  asyncEnd(e, n, t, o) {
@@ -2799,7 +2799,7 @@ const engineHooks = {
2799
2799
  // (or `_time`, for a same-reference commit under `equals: false`), and
2800
2800
  // a transition hold parks the value in `_pendingValue`. A landing the
2801
2801
  // equality gate swallowed moves none of them and must leave no stamp.
2802
- const o = e.le !== asyncStartValue || e.ae !== asyncStartTime || e.ie === t;
2802
+ const o = e.le !== asyncStartValue || e.ie !== asyncStartTime || e.ue === t;
2803
2803
  if (o) stampWrite(e, "async", n === undefined ? NO_VALUES : n, t);
2804
2804
  // Flight over either way — an equality-swallowed landing still spent
2805
2805
  // the wall time (finalizeFlight only chains through a fresh stamp).
@@ -78,6 +78,11 @@ const REACTIVE_MANUAL_WRITE = 1 << 10;
78
78
  * later read of the same pass routed it into a verdict lane — that was not
79
79
  * the probe's answer (lanes.ts). Per pass. */ const REACTIVE_PROBE_UNANSWERED = 1 << 19;
80
80
 
81
+ /** The pass opened a verdict window of its own (`isPending`/`latest`) — not
82
+ * only read a verdict memo (F-6, core.ts `read`). An async memo whose pass
83
+ * did not is D-25's hold work while its flight is up (verdict.ts
84
+ * `holdWork`). Per pass (1 << 20 is lanes.ts's LEFT_SHOWN). */ const REACTIVE_WINDOW = 1 << 21;
85
+
81
86
  // Static configuration bits packed into Owner/Computed/Signal _config.
82
87
  const CONFIG_OWNED_WRITE = 1 << 0;
83
88
 
@@ -219,6 +224,9 @@ const CONFIG_HAS_SNAPSHOT = 1 << 9;
219
224
  * joins nothing, so two mounts under one boundary made in separate flushes
220
225
  * keep their holds apart (D-4, S-5 rows 1′–3′, #4283). */ const CONFIG_FRAME = 1 << 23;
221
226
 
227
+ /** The node's last answering pass registered a flight: an async memo. Kept
228
+ * by the verdict engine alone (verdict.ts `holdWork`), which reads it. */ const CONFIG_ASYNC = 1 << 29;
229
+
222
230
  const STATUS_NONE = 0;
223
231
 
224
232
  const STATUS_PENDING = 1 << 0;
@@ -258,4 +266,4 @@ const defaultContext = {};
258
266
 
259
267
  const NewSet = Set;
260
268
 
261
- export { $REFRESH, CAUGHT_REARMED, CONFIG_AUTHORITATIVE, CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, CONFIG_FRAME, CONFIG_FRESH_READ, CONFIG_GUESS, CONFIG_HAS_SNAPSHOT, CONFIG_HELD, CONFIG_HELD_FRAME, CONFIG_INPUTS_PUBLISHED, CONFIG_IN_SNAPSHOT_SCOPE, CONFIG_KEY_BAG, CONFIG_LAGS, CONFIG_MANUAL_WRITE, CONFIG_NO_SNAPSHOT, CONFIG_OVERRIDE, CONFIG_OWNED_WRITE, CONFIG_PLUMBING, CONFIG_PROMOTED, CONFIG_REDERIVE, CONFIG_SLOT_NODE, CONFIG_STAGED, CONFIG_STAGED_ERROR, CONFIG_SYNC, CONFIG_TRANSPARENT, CONFIG_VERDICT, EFFECT_RENDER, EFFECT_TRACKED, EFFECT_USER, NOT_PENDING, NO_SNAPSHOT, NewSet, REACTIVE_CHECK, REACTIVE_DIRTY, REACTIVE_DISPOSED, REACTIVE_FRAME_READ, REACTIVE_IN_HEAP, REACTIVE_IN_HEAP_HEIGHT, REACTIVE_JOINED, REACTIVE_LANE_DIRTY, REACTIVE_LANE_READ, REACTIVE_LAZY, REACTIVE_MANUAL_WRITE, REACTIVE_MISSED_WAKE, REACTIVE_NONE, REACTIVE_PROBED, REACTIVE_PROBE_UNANSWERED, REACTIVE_REASK, REACTIVE_RECOMPUTING_DEPS, REACTIVE_SCREEN_READ, REACTIVE_SNAPSHOT_STALE, REACTIVE_STAGED_READ, REACTIVE_ZOMBIE, STATUS_ERROR, STATUS_NONE, STATUS_NO_VALUE, STATUS_PENDING, STATUS_UNINITIALIZED, SUPPORTS_PROXY, defaultContext };
269
+ export { $REFRESH, CAUGHT_REARMED, CONFIG_ASYNC, CONFIG_AUTHORITATIVE, CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, CONFIG_FRAME, CONFIG_FRESH_READ, CONFIG_GUESS, CONFIG_HAS_SNAPSHOT, CONFIG_HELD, CONFIG_HELD_FRAME, CONFIG_INPUTS_PUBLISHED, CONFIG_IN_SNAPSHOT_SCOPE, CONFIG_KEY_BAG, CONFIG_LAGS, CONFIG_MANUAL_WRITE, CONFIG_NO_SNAPSHOT, CONFIG_OVERRIDE, CONFIG_OWNED_WRITE, CONFIG_PLUMBING, CONFIG_PROMOTED, CONFIG_REDERIVE, CONFIG_SLOT_NODE, CONFIG_STAGED, CONFIG_STAGED_ERROR, CONFIG_SYNC, CONFIG_TRANSPARENT, CONFIG_VERDICT, EFFECT_RENDER, EFFECT_TRACKED, EFFECT_USER, NOT_PENDING, NO_SNAPSHOT, NewSet, REACTIVE_CHECK, REACTIVE_DIRTY, REACTIVE_DISPOSED, REACTIVE_FRAME_READ, REACTIVE_IN_HEAP, REACTIVE_IN_HEAP_HEIGHT, REACTIVE_JOINED, REACTIVE_LANE_DIRTY, REACTIVE_LANE_READ, REACTIVE_LAZY, REACTIVE_MANUAL_WRITE, REACTIVE_MISSED_WAKE, REACTIVE_NONE, REACTIVE_PROBED, REACTIVE_PROBE_UNANSWERED, REACTIVE_REASK, REACTIVE_RECOMPUTING_DEPS, REACTIVE_SCREEN_READ, REACTIVE_SNAPSHOT_STALE, REACTIVE_STAGED_READ, REACTIVE_WINDOW, REACTIVE_ZOMBIE, STATUS_ERROR, STATUS_NONE, STATUS_NO_VALUE, STATUS_PENDING, STATUS_UNINITIALIZED, SUPPORTS_PROXY, defaultContext };
@@ -0,0 +1,10 @@
1
+ /** @internal Runs `fn` with this copy marked as the one running. */
2
+ function runAsSolidCopy(n) {
3
+ return n();
4
+ }
5
+
6
+ /** @internal An ownerless component or context read: warns if another copy is running. */ function checkForeignOwnerless() {
7
+ return;
8
+ }
9
+
10
+ export { checkForeignOwnerless, runAsSolidCopy };