@solidjs/signals 2.0.0-rc.13 → 2.0.0-rc.15

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 (121) hide show
  1. package/dist/dev-shared.js +2059 -3768
  2. package/dist/dev.attribution.js +237 -101
  3. package/dist/dev.js +7466 -8497
  4. package/dist/observe/affects.js +128 -104
  5. package/dist/observe/boundaries.js +492 -665
  6. package/dist/observe/core/action.js +63 -66
  7. package/dist/observe/core/async.js +243 -379
  8. package/dist/observe/core/attribution-queries.js +1 -1
  9. package/dist/observe/core/attribution.js +394 -253
  10. package/dist/observe/core/constants.js +120 -187
  11. package/dist/observe/core/context.js +3 -3
  12. package/dist/observe/core/core.js +874 -1440
  13. package/dist/observe/core/dev.js +3 -3
  14. package/dist/observe/core/effect.js +73 -84
  15. package/dist/observe/core/external.js +5 -5
  16. package/dist/observe/core/graph.js +62 -71
  17. package/dist/observe/core/heap.js +75 -98
  18. package/dist/observe/core/invariants.js +1 -34
  19. package/dist/observe/core/lanes.js +750 -181
  20. package/dist/observe/core/owner.js +80 -101
  21. package/dist/observe/core/scheduler.js +719 -1356
  22. package/dist/observe/core/verdict.js +314 -621
  23. package/dist/observe/flatten.js +79 -0
  24. package/dist/observe/index.js +15 -13
  25. package/dist/observe/map.js +232 -235
  26. package/dist/observe/reveal.js +212 -0
  27. package/dist/observe/signals.js +144 -216
  28. package/dist/observe/store/affects.js +142 -0
  29. package/dist/observe/store/hooks.js +13 -0
  30. package/dist/observe/store/index.js +27 -24
  31. package/dist/observe/store/optimistic.js +571 -0
  32. package/dist/observe/store/projection.js +308 -0
  33. package/dist/observe/store/reconcile.js +259 -0
  34. package/dist/observe/store/store.js +1988 -277
  35. package/dist/observe/store/storePath.js +1 -1
  36. package/dist/{prod/store/next → observe/store}/target.js +17 -18
  37. package/dist/observe/store/types.js +73 -0
  38. package/dist/observe/store/utils.js +1 -13
  39. package/dist/prod/affects.js +130 -106
  40. package/dist/prod/boundaries.js +476 -654
  41. package/dist/prod/core/action.js +71 -74
  42. package/dist/prod/core/async.js +306 -444
  43. package/dist/prod/core/constants.js +117 -186
  44. package/dist/prod/core/context.js +3 -3
  45. package/dist/prod/core/core.js +888 -1462
  46. package/dist/prod/core/effect.js +88 -99
  47. package/dist/prod/core/external.js +5 -5
  48. package/dist/prod/core/graph.js +62 -71
  49. package/dist/prod/core/heap.js +75 -98
  50. package/dist/prod/core/invariants.js +1 -32
  51. package/dist/prod/core/lanes.js +712 -181
  52. package/dist/prod/core/owner.js +75 -96
  53. package/dist/prod/core/scheduler.js +686 -1335
  54. package/dist/prod/core/verdict.js +309 -621
  55. package/dist/prod/flatten.js +77 -0
  56. package/dist/prod/index.js +15 -13
  57. package/dist/prod/map.js +142 -145
  58. package/dist/prod/reveal.js +212 -0
  59. package/dist/prod/signals.js +155 -227
  60. package/dist/prod/store/affects.js +142 -0
  61. package/dist/prod/store/hooks.js +13 -0
  62. package/dist/prod/store/index.js +26 -19
  63. package/dist/prod/store/optimistic.js +566 -0
  64. package/dist/prod/store/projection.js +301 -0
  65. package/dist/prod/store/reconcile.js +259 -0
  66. package/dist/prod/store/store.js +1883 -272
  67. package/dist/prod/store/storePath.js +1 -1
  68. package/dist/{observe/store/next → prod/store}/target.js +13 -17
  69. package/dist/prod/store/types.js +73 -0
  70. package/dist/prod/store/utils.js +1 -11
  71. package/dist/types/affects.d.ts +11 -30
  72. package/dist/types/boundaries.d.ts +66 -176
  73. package/dist/types/carved.d.ts +1 -0
  74. package/dist/types/core/action.d.ts +5 -6
  75. package/dist/types/core/async.d.ts +10 -5
  76. package/dist/types/core/attribution-hooks.d.ts +20 -1
  77. package/dist/types/core/attribution.d.ts +26 -11
  78. package/dist/types/core/constants.d.ts +130 -180
  79. package/dist/types/core/core.d.ts +134 -264
  80. package/dist/types/core/dev.d.ts +2 -2
  81. package/dist/types/core/effect.d.ts +0 -7
  82. package/dist/types/core/graph.d.ts +7 -1
  83. package/dist/types/core/heap.d.ts +5 -7
  84. package/dist/types/core/index.d.ts +5 -5
  85. package/dist/types/core/invariants.d.ts +0 -29
  86. package/dist/types/core/lanes.d.ts +74 -86
  87. package/dist/types/core/owner.d.ts +3 -3
  88. package/dist/types/core/scheduler.d.ts +255 -331
  89. package/dist/types/core/types.d.ts +45 -85
  90. package/dist/types/core/verdict.d.ts +3 -0
  91. package/dist/types/flatten.d.ts +8 -0
  92. package/dist/types/index.d.ts +6 -4
  93. package/dist/types/reveal.d.ts +19 -0
  94. package/dist/types/signals.d.ts +35 -91
  95. package/dist/types/store/affects.d.ts +12 -0
  96. package/dist/types/store/hooks.d.ts +48 -0
  97. package/dist/types/store/index.d.ts +34 -15
  98. package/dist/types/store/optimistic.d.ts +23 -0
  99. package/dist/types/store/projection.d.ts +18 -0
  100. package/dist/types/store/reconcile.d.ts +3 -0
  101. package/dist/types/store/store.d.ts +132 -145
  102. package/dist/types/store/storePath.d.ts +1 -1
  103. package/dist/types/store/target.d.ts +151 -0
  104. package/dist/types/store/types.d.ts +84 -0
  105. package/package.json +1 -1
  106. package/dist/observe/core/optimistic.js +0 -669
  107. package/dist/observe/store/next/optimistic.js +0 -717
  108. package/dist/observe/store/next/projection.js +0 -266
  109. package/dist/observe/store/next/reconcile.js +0 -375
  110. package/dist/observe/store/next/store.js +0 -2608
  111. package/dist/prod/core/optimistic.js +0 -658
  112. package/dist/prod/store/next/optimistic.js +0 -710
  113. package/dist/prod/store/next/projection.js +0 -257
  114. package/dist/prod/store/next/reconcile.js +0 -373
  115. package/dist/prod/store/next/store.js +0 -2484
  116. package/dist/types/core/optimistic.d.ts +0 -6
  117. package/dist/types/store/next/optimistic.d.ts +0 -25
  118. package/dist/types/store/next/projection.d.ts +0 -27
  119. package/dist/types/store/next/reconcile.d.ts +0 -10
  120. package/dist/types/store/next/store.d.ts +0 -145
  121. package/dist/types/store/next/target.d.ts +0 -196
@@ -1,205 +1,736 @@
1
- import { CONFIG_DERIVED_OVERRIDE, CONFIG_HAS_LANE, REACTIVE_DISPOSED } from "./constants.js";
1
+ import { CONFIG_GUESS, NOT_PENDING, CONFIG_OVERRIDE, REACTIVE_DISPOSED, CONFIG_VERDICT, REACTIVE_PROBE_UNANSWERED, REACTIVE_LANE_DIRTY, CONFIG_AUTHORITATIVE, CONFIG_CHILDREN_FORBIDDEN, STATUS_PENDING, EFFECT_RENDER, CONFIG_HELD, STATUS_UNINITIALIZED, REACTIVE_SCREEN_READ, REACTIVE_FRAME_READ, REACTIVE_LANE_READ, REACTIVE_RECOMPUTING_DEPS, CONFIG_STAGED, REACTIVE_JOINED, REACTIVE_STAGED_READ, CONFIG_SLOT_NODE, REACTIVE_IN_HEAP, REACTIVE_DIRTY, REACTIVE_CHECK, CONFIG_INPUTS_PUBLISHED } from "./constants.js";
2
2
 
3
- import { hasActiveOverride, ext, ownsHold, currentOptimisticLane } from "./core.js";
3
+ import { tracking, ext, stagedRead } from "./core.js";
4
+
5
+ import { NotReadyError } from "./error.js";
4
6
 
5
7
  import { enqueueSub } from "./heap.js";
6
8
 
7
- import { currentTransition, activeTransition, waitingTransition } from "./scheduler.js";
8
-
9
- // Map from optimistic signal to its lane (reused for multiple writes to same signal)
10
- const signalLanes = new WeakMap;
11
-
12
- // All active lanes (for cleanup on transition completion)
13
- const activeLanes = new Set;
14
-
15
- /**
16
- * Get an existing lane for a signal or create a new one.
17
- * Reuses lane for multiple writes to the same signal.
18
- */ function getOrCreateLane(n) {
19
- let e = signalLanes.get(n);
20
- if (e) {
21
- return findLane(e);
22
- }
23
- // Detect parent lane: _parentSource chains from pendingSignal → pendingValueComputed → original.
24
- // The child lane should not merge with the parent lane.
25
- const i = n.o?.kn;
26
- const t = i?.o?.me;
27
- const r = t ? findLane(t) : null;
28
- e = {
29
- ni: n,
30
- Qe: new Set,
31
- dn: [ [], [] ],
32
- ei: null,
33
- we: activeTransition,
34
- ii: r
35
- };
36
- signalLanes.set(n, e);
37
- activeLanes.add(e);
38
- // A companion may have written before the owner's first optimistic write
39
- // (affects() as an action's first statement pokes the verdict companion of a
40
- // still lane-less node, #2887), leaving its lane parentless. Adopt it now:
41
- // parent-child is a property of the nodes, not of write order — otherwise
42
- // the owner's write merges the companion's subscribers into this lane and
43
- // their effects wait on its async instead of flushing immediately.
44
- adoptCompanionLane(n.o?.Ze, e);
45
- adoptCompanionLane(n.o?.He, e);
46
- return e;
9
+ import { schedule, question, nextQuestion, GlobalQueue, blocked, txOf, passLane, sameLane, flushTransaction, resolveTx, queuePendingNode, list, clock, insertSubs, laneDirty, merge, newTransaction, reruns, releaseQueues, ownFlights, setPassLane, holdNode, joinFuture, commitPendingNode } from "./scheduler.js";
10
+
11
+ // Lanes (plan sec. 28 replay, 2026-10-02; maintainer rulings 2026-10-01/02). A lane
12
+ // is "a new base of a transition": the sub-frame an optimistic write opens
13
+ // in the transition of the frame it is made in. It sees the screen plus its
14
+ // own guesses (plan sec. 19), breaks out of the parent's hold — its effects run now —
15
+ // and holds itself if its own derivations hit async (and, blocked, holds its
16
+ // parent). It ends when the parent lands: a guess reverts to the truth it
17
+ // covered, or lands as the truth that superseded it. A frame that does not
18
+ // park has nothing to be optimistic over: the write is void.
19
+ // Three places per node, each meaning one thing always: `_value` is the
20
+ // committed truth, `_pendingValue` a transaction's staging (the future), and
21
+ // `_x._lane` the lane's value — a written guess or a lane pass's derivation.
22
+ // The lane carries the state machine: `_shown` once it has revealed. The
23
+ // screen shows a lane's value once the lane has shown (`display`); a direct
24
+ // read sees it throughout (A17); an authoritative reader (`until`) sees the
25
+ // truth beneath it (Q3, 2026-10-02: "optimistic overrides are intentionally
26
+ // not part of authoritative truth").
27
+ // The seat of a pass is its node's (core.ts `recompute`): a node carrying a
28
+ // lane's derived value runs as the lane's whoever dirtied it; a derivation's
29
+ // tracked read of a lane's value moves its pass into the lane (`enterLane`);
30
+ // a leaf's never does — it reads the screen, a stale reader of a lane that
31
+ // has not shown (#3460). Lane work's values go to the lane slot (or, once
32
+ // the lane has shown, to its staging for the next reveal), its runs to the
33
+ // lane's queues.
34
+ // This module is the lane engine, installed on `GlobalQueue` when something
35
+ // imports it (`createOptimistic`, or verdict.ts for its verdict lanes). The
36
+ // core keeps only bit tests and `passLane`: a program with no optimism
37
+ // carries none of this.
38
+ /** Live lanes (parented). Scanned at every seam while non-empty. */
39
+ const lanes = [];
40
+
41
+ /** A pass left a shown slot the equality gate can no longer see (#3892). */ const LEFT_SHOWN = 1 << 20;
42
+
43
+ function newLane(e) {
44
+ const n = newTransaction(true, e);
45
+ lanes.push(n);
46
+ return n;
47
+ }
48
+
49
+ /** A lane node's current value: its guess, or the latest it derived — the
50
+ * staging a shown lane holds for its next reveal, else its slot; the
51
+ * committed value while it has none (its first lane pass in flight). */ function laneValueOf(e) {
52
+ if (!(e.i & CONFIG_GUESS) && e.Oe !== NOT_PENDING) return e.Oe;
53
+ const n = e.m.B;
54
+ return n !== NOT_PENDING ? n : e.Ae;
47
55
  }
48
56
 
49
- function adoptCompanionLane(n, e) {
50
- if (!n) return;
51
- const i = signalLanes.get(n);
52
- if (!i) return;
53
- const t = findLane(i);
54
- // Only the companion's own unmerged root is safely re-parentable: a root
55
- // that absorbed other lanes carries work that is not a child of this owner.
56
- if (t !== e && t.ni === n && !t.ii) t.ii = e;
57
+ /** What the screen shows for a lane's node: the lane's value once the lane
58
+ * has revealed, the committed truth before. */ function display(e) {
59
+ const n = e.m.B;
60
+ return e.m.He.Ze && n !== NOT_PENDING ? n : e.Ae;
57
61
  }
58
62
 
59
- /**
60
- * Union-find: find the root lane.
61
- */ function findLane(n) {
62
- while (n.ei) n = n.ei;
63
+ /** Guesses written since the last seam (`[node, value, question, …]`).
64
+ * Applied at the seam, once the frame's verdict is known — the parent is
65
+ * the frame's transaction, and there is none to be optimistic over when the
66
+ * frame commits (the write is as if it never happened: nothing was
67
+ * applied). The lane's passes run in the next round of the same flush, so
68
+ * the guess is visible at flush like any write (A28). */ const pendingGuesses = [];
69
+
70
+ /** What the writer sees of a node: an unflushed guess to it, else the
71
+ * lane's value or the committed one — what an optimistic updater composes
72
+ * on (a store setter's draft too, store/optimistic.ts). */ function guessedValueOf(e) {
73
+ const n = pendingGuessOf(e);
74
+ if (n !== NOT_PENDING) return n;
75
+ return e.i & CONFIG_OVERRIDE ? laneValueOf(e) : e.Ae;
76
+ }
77
+
78
+ /** The unflushed guess to `n`, else NOT_PENDING. */ function pendingGuessOf(e) {
79
+ for (let n = pendingGuesses.length - 3; n >= 0; n -= 3) if (pendingGuesses[n] === e) return pendingGuesses[n + 1];
80
+ return NOT_PENDING;
81
+ }
82
+
83
+ function optimisticWrite(e, n) {
84
+ // What the user sees: an unflushed guess to the same node, else the lane's
85
+ // value or the committed one. The updater composes on it; guessing it
86
+ // again is no guess (the node's comparator, as for any write) — unless
87
+ // the node already carries one: the user re-asked, and the re-ask renews
88
+ // the guess's question and entangles its frame (#3347) without notifying.
89
+ const t = guessedValueOf(e);
90
+ if (typeof n === "function") n = n(t);
91
+ if (e.ye && e.ye(t, n) && !(e.i & CONFIG_GUESS)) return n;
92
+ pendingGuesses.push(e, n, question || nextQuestion());
93
+ schedule();
63
94
  return n;
64
95
  }
65
96
 
66
- /**
67
- * Is the lane held? `_pendingAsync` records the async the lane OWNS (derived
68
- * under it); a transaction's reporter map records the async a render effect
69
- * OBSERVED pending with no boundary taking it (INV-3, the one registration
70
- * site). A hold needs both — the same rule the transaction itself uses, so a
71
- * memo nobody renders, or one a fallback-showing boundary caught, cannot tear
72
- * a frame and holds nothing (#3289). An orphan lane has no observation record
73
- * and never holds.
74
- *
75
- * The observation is looked up per NODE, in whichever live transaction
76
- * recorded it — not in this lane's transaction. Lanes merge across
77
- * transactions (#2912: ownership never travels through lanes), so after a
78
- * merge the root's transaction holds the observations of only one member;
79
- * the async the other member's transaction observed must hold the merged
80
- * reveal just the same (A15 for lanes, #3335).
81
- */ function laneHeld(n) {
82
- if (!n.we) return false;
83
- for (const e of n.Qe) if (waitingTransition(e) !== null) return true;
97
+ /** The seam: each guess becomes its node's lane value, in a lane — the
98
+ * node's own if it carries one (a later write into the same lane), else a
99
+ * new one under `parent` (the frame's transaction), under the hold already
100
+ * on the node (a guess over that transition's world — the truth it holds
101
+ * stays staged beneath, for the lane's end to commit), or under a
102
+ * transaction opened for the node's own in-flight refetch (the guess is
103
+ * that flight's observer — A17, "visible until its own fetch settles"). No
104
+ * parent: the guess is dropped. The truth is untouched; readers are
105
+ * dirtied for the next round. */
106
+ /** A guess's own truth is in flight: the node's own refetch — or, a store
107
+ * leaf's, its family's derive (the slot's flight; store/optimistic.ts
108
+ * installs the resolver). A17: the guess stands in for the flight. */ function inFlight(e) {
109
+ return (e.S & STATUS_PENDING) !== 0 || (e.i & CONFIG_SLOT_NODE) !== 0 && GlobalQueue.C?.(e) === true;
110
+ }
111
+
112
+ function applyGuesses(e) {
113
+ let n = null;
114
+ for (let t = 0; t < pendingGuesses.length; t += 3) {
115
+ const u = pendingGuesses[t];
116
+ const l = pendingGuesses[t + 1];
117
+ let s = true;
118
+ if (u.i & CONFIG_OVERRIDE) {
119
+ // A lane's node already: a guess re-asked, or a derivation guessed
120
+ // over (its staging is void — the guess is the value now). Two
121
+ // suggestions for one slot cannot finish apart (A34 (1)): the frames
122
+ // entangle. The same value re-asked renews the question; nothing to
123
+ // notify.
124
+ s = !u.ye || !u.ye(laneValueOf(u), l);
125
+ if (!(u.i & CONFIG_GUESS)) {
126
+ u.Oe = NOT_PENDING;
127
+ u.i |= CONFIG_GUESS;
128
+ }
129
+ u.m.B = l;
130
+ const n = txOf(u)._parent;
131
+ if (e !== null && n !== null) merge(e, n);
132
+ } else {
133
+ let t;
134
+ if (u.i & CONFIG_HELD) t = newLane(txOf(u)); else {
135
+ if (e === null && inFlight(u)) e = newTransaction(false);
136
+ if (e === null) continue;
137
+ t = n ??= newLane(e);
138
+ }
139
+ // (A guess equal to a truth staged beneath it is confirmed at birth —
140
+ // A24 — and still re-derives its readers as the lane's: the truth's
141
+ // derivations are the transaction's world, the lane's are the
142
+ // screen's plus the guess (plan sec. 19) — a derivation reading a held write
143
+ // beside the guess must not show it. Two flights for one input, when
144
+ // the worlds coincide, is the price.)
145
+ ext(u).B = l;
146
+ u.i |= CONFIG_OVERRIDE | CONFIG_GUESS;
147
+ list(u, t);
148
+ }
149
+ ext(u)._e = pendingGuesses[t + 2];
150
+ if (s) {
151
+ // The lane's members re-derive as its work (REACTIVE_LANE_DIRTY): a
152
+ // blocked lane's re-guess does not re-run its render effects as stale
153
+ // readers republishing the committed view (#3460).
154
+ insertSubs(u);
155
+ laneDirty(u, txOf(u));
156
+ }
157
+ }
158
+ pendingGuesses.length = 0;
159
+ }
160
+
161
+ /** The running pass read lane `l`'s work as a derivation: it is `l`'s — or,
162
+ * already another lane's, the frame it computes derives from both guesses
163
+ * and cannot show one without the other (#3335, A15 for lanes): the two
164
+ * lanes are linked — one reveal unit, each blocked while any is — while
165
+ * their lifetimes stay their own (#2912: a guess reverts with its own
166
+ * action, not with the one it shares a reader with). A nested lane reading
167
+ * through an ancestor's guess stays its own (the screen plus its own
168
+ * guesses). */ function enterLane(e, n) {
169
+ n.R |= REACTIVE_LANE_READ;
170
+ const t = passLane;
171
+ if (t === null) {
172
+ setPassLane(e);
173
+ // The pass read a held write before its first lane read (it joined the
174
+ // frame's future as mainline would): lane work sees the screen — the
175
+ // seam re-derives it on the committed world next round (`stagedReaders`,
176
+ // the park's repair), as it does a lane pass that read a staging. Not a
177
+ // pass whose held reads were all of nodes born held (no staged read,
178
+ // `stagedRead`): it has no committed world to re-derive on (#3969).
179
+ if (n.R & REACTIVE_JOINED && n.R & REACTIVE_STAGED_READ) stagedRead(n);
180
+ return;
181
+ }
182
+ if (sameLane(t, e)) return setPassLane(e);
183
+ if (under(t, e)) return;
184
+ if (under(e, t)) return setPassLane(e);
185
+ linkLanes(t, e);
186
+ setPassLane(e);
187
+ }
188
+
189
+ /** Is `l` nested under `a` (an ancestor lane)? */ function under(e, n) {
190
+ for (let t = e._parent; t !== null && t.B; t = t._parent) if (t === n) return true;
84
191
  return false;
85
192
  }
86
193
 
87
- /**
88
- * Lanes mirror transitions (#3460): a render effect OFF a HELD lane that reads
89
- * a value the lane is revealing — an override, a `latest()` shadow — sees the
90
- * committed value, exactly as a stale reader of a held transaction does
91
- * (A15 reveal corollary): it publishes now, with the frame that is on screen
92
- * (the lane defers its own readers' runs, so the committed value is what is
93
- * visible), entangles nothing — a sync write is never held by a lane — and
94
- * re-derives at the release. The release re-run rides the lane's own render
95
- * queue, which runs when the lane reveals (runLaneEffects) or its transaction
96
- * commits (cleanupCompletedLanes). A reader ON the lane computes the lane's
97
- * reveal and takes the value as before.
98
- *
99
- * OFF the lane is provenance, not membership — the transaction mirror
100
- * exactly: a stale reader of a transaction is a pass that runs outside it. A
101
- * pass under the lane's own transaction is the lane's work — its write (lane
102
- * posture), or the landing of its async, which re-enters the transaction
103
- * (#3334) and runs a member with no ambient lane. Read as an outsider, that
104
- * pass published the committed view and queued a replay that revealed the
105
- * override beside its unready derivation at the release (`1:0` for an
106
- * optimistic frame that never became ready; #3479 review). Membership is the
107
- * wrong test the other way: a member re-run by a sibling's sync write is a
108
- * mainline pass and shows the committed view.
109
- */ function readsHeldCommitted(n, e) {
110
- const i = resolveLane(n);
111
- if (!i || !laneHeld(i)) return false;
112
- if (ownsLane(i, n)) return false;
113
- i.dn[0].push(() => e.oe & REACTIVE_DISPOSED || enqueueSub(e));
114
- return true;
194
+ /** One link group (a shared array) for both lanes' groups. */ function linkLanes(e, n) {
195
+ const t = e.nn ?? (e.nn = [ e ]);
196
+ const u = n.nn;
197
+ if (u === t) return;
198
+ if (u === null) {
199
+ t.push(n);
200
+ n.nn = t;
201
+ } else for (let e = 0; e < u.length; e++) {
202
+ t.push(u[e]);
203
+ u[e].nn = t;
204
+ }
115
205
  }
116
206
 
117
- /** The ownership relation for a lane hold (core `ownsHold`, §6 ruling 2): the
118
- * running pass owns `lane`'s hold if it runs under the transition that owns
119
- * the lane (the node's, resolved through override ownership and merges) or
120
- * inside the lane itself. */ function ownsLane(n, e) {
121
- if (activeTransition !== null) {
122
- const n = resolveTransition(e);
123
- if (n && ownsHold(n)) return true;
124
- }
125
- return currentOptimisticLane !== null && findLane(currentOptimisticLane) === n;
126
- }
127
-
128
- /**
129
- * Merge two lanes when their dependency graphs overlap.
130
- */ function mergeLanes(n, e) {
131
- n = findLane(n);
132
- e = findLane(e);
133
- if (n === e) return n;
134
- e.ei = n;
135
- // Move (not copy) the merged lane's work: after the merge all routing goes
136
- // through findLane() to the root, so anything left behind here is dead —
137
- // and anything *added* here later is a routing bug (INV-5).
138
- for (const i of e.Qe) n.Qe.add(i);
139
- e.Qe.clear();
140
- n.dn[0].push(...e.dn[0]);
141
- n.dn[1].push(...e.dn[1]);
142
- e.dn[0].length = 0;
143
- e.dn[1].length = 0;
144
- return n;
207
+ /** A linked lane blocked on its own account blocks the group — `blocked(k)`
208
+ * without the group recursion. (A guess in `k` whose own truth is in flight
209
+ * blocks `k`'s parent, not `k` — nor, through the link, `l`: the guess
210
+ * shows, A17.) */ function linkBlocked(e) {
211
+ const n = e.nn;
212
+ if (n !== null) for (let t = 0; t < n.length; t++) {
213
+ const u = n[t];
214
+ if (u !== e && (u.tt !== 0 || ownFlights(u) || nestedBlocked(u))) return true;
215
+ }
216
+ return false;
217
+ }
218
+
219
+ function unlink(e) {
220
+ const n = e.nn;
221
+ if (n === null) return;
222
+ const t = n.indexOf(e);
223
+ if (t !== -1) n.splice(t, 1);
224
+ e.nn = null;
225
+ }
226
+
227
+ /** Verdicts (maintainer, 2026-10-01): `isPending` and `latest` are
228
+ * optimistic state the system supplies — a verdict is a guess ("pending,
229
+ * until this lands"; "the proposal is the value") decided at the seam like
230
+ * a user's, and its readers break out of the hold the same way: work of a
231
+ * lane under the holder, shown now, re-derived at the landing, ending with
232
+ * it. Judged at the seam like any lane: blocked while a verdict reader's
233
+ * own derivation is in flight (lane rule 3), shown otherwise. */ function verdictLane(e) {
234
+ return e.xe ??= newLane(e);
235
+ }
236
+
237
+ /** A lane pass's node (core.ts `recompute`, before its staging; a pending
238
+ * propagation under a lane pass, async.ts): listed, carrying the lane's
239
+ * value from now (a derivation of a guess — its readers become lane work).
240
+ * Entering the lane supersedes a frame staging the node carried: this
241
+ * pass's answer replaces it, and the frame's hold on it is over. An
242
+ * effect's value slot is private (no lane value). A pass in a lane's seat
243
+ * that read none of the lane's world has left it (false): its result is the
244
+ * frame's — a derivation whose branch no longer reaches the guess — and no
245
+ * hold the lane took over from a transaction stays on it (#3698: lane work
246
+ * never makes its node transaction work; a born-held effect's hold went to
247
+ * the lane). A pass interrupted before it got there (pending, errored) did
248
+ * not leave (A30: it never got there). A first pass under a lane is the
249
+ * lane's (ruling A); a guess is written, not derived — it never leaves this
250
+ * way. `errored`: the pass has no answer — or, a lane pass's pending
251
+ * propagation (async.ts `propagateStatus`), the node gone pending. */ function laneStage(e, n, t, u) {
252
+ if (!(t || u || e.R & REACTIVE_LANE_READ || e.i & CONFIG_GUESS)) {
253
+ const n = e.m;
254
+ if (n !== null) {
255
+ const t = n.He;
256
+ // Cleared before equality, so a return to the committed value notifies
257
+ // nobody. The seam wakes it unless the frame is still held (#3892).
258
+ if (t?.Ze && !blocked(resolveTx(t._parent))) e.R |= LEFT_SHOWN;
259
+ if (t?.B) n.He = null;
260
+ n.B = NOT_PENDING;
261
+ }
262
+ e.i &= -1050881;
263
+ return false;
264
+ }
265
+ if (!e.u) {
266
+ if (!(e.i & CONFIG_OVERRIDE)) {
267
+ e.Oe = NOT_PENDING;
268
+ e.i = e.i & -1048833 | CONFIG_OVERRIDE;
269
+ ext(e);
270
+ }
271
+ // A written guess whose own pass is the lane's work — its source is a
272
+ // derivation of another guess (a guess over `config().courier` under a
273
+ // country guess) — is confirmed or corrected by the lane: a derivation
274
+ // of the lane from here (its value the lane's, its fate the lane's), no
275
+ // longer a written guess. A pass with no answer (pending, errored)
276
+ // leaves the guess.
277
+ if (!u) e.i &= ~CONFIG_GUESS;
278
+ }
279
+ // A leaf has no lane value to seat it (`recompute`): one left waiting on
280
+ // the lane's flight runs its next pass as the lane's — the landing that
281
+ // wakes it is the lane's re-staging (A31), and the lane holds its render
282
+ // effects until its derivations land (A17; #3766, F5). Not a leaf whose
283
+ // seat is its frame's, reached by a propagation from a node the screen has
284
+ // a value of: one a transaction holds (born held — its frame waits on it,
285
+ // A29), or one whose own mainline pass is running (it pulled the node;
286
+ // `laneRead` decides — its frame holds). Its pending is the frame's: queued
287
+ // for the commit sweep as mainline's (async.ts). A node born in the lane
288
+ // has nothing on screen: its leaf waits as the lane's.
289
+ else if (u) {
290
+ if (u !== true && !(u.S & STATUS_UNINITIALIZED) && (e.i & CONFIG_HELD || e.R & REACTIVE_RECOMPUTING_DEPS) && !e.m?.He?.B) {
291
+ queuePendingNode(e);
292
+ return false;
293
+ }
294
+ e.R |= REACTIVE_LANE_DIRTY;
295
+ }
296
+ list(e, n);
297
+ return true;
145
298
  }
146
299
 
147
- /**
148
- * Resolve a node's lane: follow union-find chain, verify active, clear if stale.
149
- */ function resolveLane(n) {
150
- const e = n.o?.me;
151
- if (!e) return undefined;
152
- const i = findLane(e);
153
- if (activeLanes.has(i)) return i;
154
- if (n.o !== null) n.o.me = undefined;
155
- return undefined;
156
- }
157
-
158
- function resolveTransition(n) {
159
- // An active override answers with its owner, not its lane: lanes are
160
- // scheduling affinity and a shared subscriber merges them across
161
- // transactions (#2912) — the merged root's _transition would hand this
162
- // node's override to whichever action wrote last through the shared
163
- // reader. Chase merge chains; a dead owner settled through another path.
164
- if (hasActiveOverride(n) && n.o?.Ln) {
165
- const e = ext(n).Ln = currentTransition(n.o?.Ln);
166
- if (e.Rn !== true) return e;
167
- if (n.o !== null) n.o.Ln = null;
168
- }
169
- return resolveLane(n)?.we ?? n.we;
170
- }
171
-
172
- /**
173
- * Assign or merge a lane onto a node. At convergence points (node already has
174
- * a different active lane), merge unless the node has an active override.
175
- */ function assignOrMergeLane(n, e) {
176
- const i = findLane(e);
177
- const t = n.o?.me;
300
+ function supersede(e, n, t) {
301
+ const u = txOf(e);
302
+ // Resolved: the parent may have merged into another transaction since the
303
+ // lane opened (two actions guessing one slot entangle, A34 (1)) — the
304
+ // truth is held by the transaction that lands, not the merged-away one.
305
+ const l = resolveTx(u._parent ?? u);
306
+ // A store row answered by a new object the store would reconcile into
307
+ // the guessed one unchanged is an echo, not a correction (#3898): the
308
+ // server's object never matches the guess by reference.
309
+ if (t && e.i & CONFIG_SLOT_NODE && GlobalQueue.tn?.(e.m.B, n)) t = false;
178
310
  if (t) {
179
- // A merged lane is followed to its root like any other: the root is where
180
- // the subscriber's affinity lives now. Replacing it with the source lane
181
- // outright (as this once did) skipped the parent/child check below — an
182
- // isPending reader of two async siblings had their two companion lanes
183
- // merge, and the next parent-lane notification then moved it onto the
184
- // held parent, where its verdict waited on the async it reports (#3409).
185
- const r = findLane(t);
186
- if (activeLanes.has(r)) {
187
- // A WRITTEN override is its own lane's source and merges nothing
188
- // through it; a derived one (lanes stage, #3479) is a plain member —
189
- // the shared reader that merges two writers' lanes carries one.
190
- if (r !== i && (!hasActiveOverride(n) || n.C & CONFIG_DERIVED_OVERRIDE)) {
191
- // Parent-child lanes stay independent so isPending resolves without
192
- // waiting for the parent's async. The child keeps ownership.
193
- if (i.ii && findLane(i.ii) === r) {
194
- ext(n).me = e;
195
- n.C |= CONFIG_HAS_LANE;
196
- } else if (r.ii && findLane(r.ii) === i) ; else mergeLanes(i, r);
311
+ dissolveLane(u, l, e);
312
+ // What the screen showed stays the screen until the parent lands (A18
313
+ // (c): display and untracked reads keep the override until the commit).
314
+ if (u.Ze) e.Ae = e.m.B;
315
+ e.i &= -10241;
316
+ e.m.B = NOT_PENDING;
317
+ holdNode(e, l);
318
+ if (e.t !== null) insertSubs(e);
319
+ } else {
320
+ e.i |= CONFIG_HELD;
321
+ // A confirmation is silent (A17); only truth readers are told.
322
+ GlobalQueue.un?.(u);
323
+ }
324
+ e.Oe = n;
325
+ joinFuture(l);
326
+ }
327
+
328
+ /** Truth readers (`until`, `refresh`; CONFIG_AUTHORITATIVE) — pay-for-use:
329
+ * the first one installs these on GlobalQueue (signals.ts `watch`).
330
+ *
331
+ * A truth reader's read of a lane node: the lane's value when it is the
332
+ * truth (#3943), else the truth staged beneath a guess, else the committed
333
+ * value. */ function truthRead(e) {
334
+ return truth(e) ? laneValueOf(e) : e.i & CONFIG_GUESS && e.Oe !== NOT_PENDING ? e.Oe : e.Ae;
335
+ }
336
+
337
+ /** A guess confirmed: its lane's truth readers re-read — of the lane's
338
+ * derivations too, which may be the truth now (#3943). */ function truthConfirmed(e) {
339
+ for (let n = 0; n < e.ln.length; n++) for (let t = e.ln[n].t; t !== null; t = t.o) if (t.l.i & CONFIG_AUTHORITATIVE) enqueueSub(t.l);
340
+ }
341
+
342
+ /** A lane node's value is the truth when every guess beneath it is
343
+ * confirmed — its source staged a value equal to the guess — and nothing
344
+ * beneath it is held in the parent: same inputs, same value. */ function truth(e) {
345
+ if (e.i & CONFIG_GUESS) return e.Oe !== NOT_PENDING && e.ye && e.ye(e.m.B, e.Oe);
346
+ if (e.Oe !== NOT_PENDING) return;
347
+ if (e.i & CONFIG_OVERRIDE) for (let n = e.p; n; n = n._) if (!truth(n.I)) return;
348
+ return 1;
349
+ }
350
+
351
+ /** A lane's end, two ways. `into === null`: the parent landed — the lane's
352
+ * values are the truth now: a guess lands the truth staged beneath it or
353
+ * reverts to the one it covered (`_value`, untouched by the guess); a
354
+ * derivation's latest value commits (its frame with it); what the screen
355
+ * showed and changes notifies. Otherwise the lane dissolves into `into`
356
+ * (the parent, on a correction): its values are void — what it showed stays
357
+ * the screen (`_value` takes it, so the parent's re-derivation compares
358
+ * against what is seen), a truth staged beneath a guess is the parent's to
359
+ * land, and the runs it held (showing the void guess) are dropped: the
360
+ * parent's re-derivation makes the runs that show. */ function dissolveLane(e, n, t) {
361
+ const u = lanes.indexOf(e);
362
+ if (u !== -1) lanes.splice(u, 1);
363
+ unlink(e);
364
+ // Its verdicts end with it (a correction's dissolution reaches here before
365
+ // `endLanes` would): the readers re-derive from the truth's notification.
366
+ const l = e.xe;
367
+ if (l !== null) {
368
+ e.xe = null;
369
+ if (lanes.indexOf(l) !== -1) dissolveLane(l, null);
370
+ }
371
+ for (let u = 0; u < e.ln.length; u++) {
372
+ const l = e.ln[u];
373
+ const s = l.m;
374
+ if (l === t || s.He !== e) continue;
375
+ const r = l.u;
376
+ const i = l.i & CONFIG_GUESS;
377
+ const o = s.B;
378
+ // What the screen shows of it (NOT_PENDING: nothing — a lane pass that
379
+ // errored or pends staged no value), and the lane's latest.
380
+ const E = e.Ze && !r ? o : l.Ae;
381
+ const f = laneValueOf(l);
382
+ s.B = NOT_PENDING;
383
+ l.i &= -10241;
384
+ if (n === null) {
385
+ // A derivation the revert re-derives (dirtied by the guess's
386
+ // notification — listed before it), or one still in flight, shows the
387
+ // lane's answer beside inputs that are the truth now: a fresh reader
388
+ // of its flight observes it (#3648, #3651; #3305's commit beneath a
389
+ // flight).
390
+ s.He = null;
391
+ if (!r && !i) l.Oe = f;
392
+ commitPendingNode(l);
393
+ if (!r) {
394
+ if (l.R & (REACTIVE_IN_HEAP | REACTIVE_DIRTY | REACTIVE_CHECK) || l.S & STATUS_PENDING) l.i |= CONFIG_INPUTS_PUBLISHED;
395
+ if (E !== NOT_PENDING && (!l.ye || !l.ye(E, l.Ae))) insertSubs(l);
396
+ }
397
+ } else if (i) {
398
+ // A guess of a dissolving lane: its truth — a landing held beneath it,
399
+ // else the value it covered — is the parent's to land, and its readers
400
+ // re-derive from it there. What the screen showed stays the screen
401
+ // until then (A18 (c)).
402
+ if (l.Oe === NOT_PENDING) l.Oe = covered(l);
403
+ if (e.Ze) l.Ae = o;
404
+ holdNode(l, n);
405
+ insertSubs(l);
406
+ } else {
407
+ // A correction: the lane's derivations are void. Shown, what the
408
+ // screen showed stays the screen (committed, inputs published — every
409
+ // one re-derives); never shown, nothing of it reached the screen (a
410
+ // node born in the lane stays uninitialized; its frame goes). One in
411
+ // flight is asking the void world's question: its landing is nobody's
412
+ // answer — it re-asks from the truth (whose notification may not reach
413
+ // it: an input's truth equal to its committed value is silent).
414
+ s.He = null;
415
+ if (!r) {
416
+ if (E !== NOT_PENDING && e.Ze) l.Oe = E;
417
+ if (l.S & STATUS_PENDING) {
418
+ s.Te = null;
419
+ enqueueSub(l);
420
+ }
421
+ }
422
+ if (e.Ze) {
423
+ commitPendingNode(l);
424
+ if (!r) l.i |= CONFIG_INPUTS_PUBLISHED;
425
+ } else {
426
+ if (s.Qe !== null || s.ve !== null) GlobalQueue.Fe(l, false, true);
427
+ l.i &= -1048961;
197
428
  }
198
- return;
199
429
  }
200
430
  }
201
- ext(n).me = e;
202
- n.C |= CONFIG_HAS_LANE;
431
+ // The parent landed: the runs the lane held (blocked on its own judgment
432
+ // alone — a zombie it could not dispose) are the landing's. A correction
433
+ // of a SHOWN lane keeps its runs too: "what it showed stays the screen"
434
+ // means the runs this round's lane passes queued (the body-end seam judges
435
+ // before the lane seam would have released them) must reach the screen —
436
+ // their derivations' values are the committed ones now, and a
437
+ // re-derivation that lands on the same value notifies nobody (a mapArray
438
+ // whose rows the lane pass already built). A never-shown lane's runs are
439
+ // void: nothing of it reached the screen. So are the runs a blocked lane
440
+ // parked: they show a re-guess the seam never revealed, beside derivations
441
+ // that keep what the screen showed.
442
+ if (n === null || e.Ze && !e.sn) releaseQueues(e); else e.rn[0].length = e.rn[1].length = 0;
203
443
  }
204
444
 
205
- export { activeLanes, assignOrMergeLane, findLane, getOrCreateLane, hasActiveOverride, laneHeld, mergeLanes, ownsLane, readsHeldCommitted, resolveLane, resolveTransition, signalLanes };
445
+ /** Lanes. A lane's node is read by its reader's kind: an authoritative
446
+ * reader (`until`) sees the truth — staged beneath a guess, else committed
447
+ * — and is no lane's; an untracked read sees the lane's latest value (A17:
448
+ * "direct read shows optimistic"; A28); a children-forbidden reader sees
449
+ * the frame (A32). A render effect in the frame's seat reading a lane the
450
+ * seam found blocked, or a member whose own flight is up (held or not — the
451
+ * lane-membership ruling, 2026-10-05), sees the screen, re-derived at the
452
+ * reveal (#3460's stale reader) — or, the node a
453
+ * flight that has never shown (nothing to show), waits on it: its own frame
454
+ * holds (A15, #3334), not the lane's parent. Any other tracked reader is
455
+ * the lane's work from this read — a derivation; a leaf reading a lane that
456
+ * has shown, or one the seam has not judged yet (its run waits on the
457
+ * verdict: released if the lane shows, held if it blocks) — and sees the
458
+ * lane's latest. NOT_PENDING falls through: lane work's read of a pending
459
+ * member throws like any. */ function laneRead(e, n) {
460
+ const t = n.i & CONFIG_GUESS;
461
+ if (e !== null && e.i & CONFIG_AUTHORITATIVE) return GlobalQueue.En(n);
462
+ if (e === null) return laneValueOf(n);
463
+ const u = txOf(n);
464
+ const l = n.S;
465
+ if (!tracking || e.i & CONFIG_CHILDREN_FORBIDDEN) {
466
+ // An untracked read inside lane work derives from the lane like a
467
+ // tracked one, minus the subscription — `untrack` is about
468
+ // dependencies, not about which world a pass derives from (a mapper's
469
+ // row reads under its root, store/map): the pass enters the lane (two
470
+ // lanes read by one pass link, as for tracked reads). Outside lane
471
+ // work, the screen.
472
+ if (passLane === null || e.i & CONFIG_CHILDREN_FORBIDDEN) return display(n);
473
+ enterLane(u, e);
474
+ if (!t && l & STATUS_PENDING) return NOT_PENDING;
475
+ return laneValueOf(n);
476
+ }
477
+ if (e.u === EFFECT_RENDER && (passLane === null || !sameLane(passLane, u))) {
478
+ if (!t) {
479
+ // A flight whose value has never shown: nothing to show — the leaf
480
+ // waits on it, and its own frame holds (A15, #3334), not the lane's
481
+ // parent. The landing lands the frame: its own pass (the flush
482
+ // joined its transaction) reads the answer it waited on — the lane's
483
+ // staging, revealed at this seam.
484
+ if (l & STATUS_PENDING && n.m.B === NOT_PENDING) return NOT_PENDING;
485
+ if (n.Oe !== NOT_PENDING && e.i & CONFIG_HELD && flushTransaction !== null && resolveTx(flushTransaction) === txOf(e)) return n.Oe;
486
+ }
487
+ if (u.sn || !t && l & STATUS_PENDING) {
488
+ if (!t && !u.Ze && l & STATUS_UNINITIALIZED) throw new NotReadyError(null);
489
+ // Re-derived at the reveal; once per pass (the pass may also be a stale
490
+ // reader of a transaction, REACTIVE_FRAME_READ — both reruns apply).
491
+ if (!(e.R & REACTIVE_SCREEN_READ)) {
492
+ e.R |= REACTIVE_FRAME_READ | REACTIVE_SCREEN_READ;
493
+ u.fn.push(e);
494
+ }
495
+ return display(n);
496
+ }
497
+ }
498
+ enterLane(u, e);
499
+ if (!t && l & STATUS_PENDING) return NOT_PENDING;
500
+ return laneValueOf(n);
501
+ }
502
+
503
+ /** The value a guess covered: the node's committed value — a store slot's
504
+ * asked of the store (a chained link follows the inner store's commits). */ function covered(e) {
505
+ return e.i & CONFIG_SLOT_NODE && GlobalQueue.Nn !== undefined ? GlobalQueue.Nn(e) : e.Ae;
506
+ }
507
+
508
+ /** A guess in `l` whose own truth is in flight (its refetch — authoritative:
509
+ * the landing supersedes, not the body's end). */ function guessFlights(e) {
510
+ for (let n = 0; n < e.ln.length; n++) {
511
+ const t = e.ln[n];
512
+ if (t.i & CONFIG_GUESS && t.m.He === e && inFlight(t)) return true;
513
+ }
514
+ return false;
515
+ }
516
+
517
+ /** The seam's verdict on a lane. Blocked — its own flight is up — nothing
518
+ * moves: the screen keeps what it shows, the lane's runs wait. Unblocked,
519
+ * the lane shows: its values are the screen from now (`_shown`), the
520
+ * staging its passes made since the last reveal is promoted, their frames
521
+ * (children) apply, the stale readers re-derive (#3460), its runs go. */
522
+ /** A18 body-end corollary (#3427), at the seam before the park decision
523
+ * (the guesses' own passes have run; a correction's re-derivations run in
524
+ * one more pure round and are the parent's flights before it is judged —
525
+ * #3409: the indicators clear together): the action body having returned,
526
+ * a guess whose own truth is not in flight has no answer coming — the truth
527
+ * beneath it is its truth, and the correction starts now rather than at the
528
+ * lane's flight. (A guess whose own refetch is up is superseded by its
529
+ * landing.) True when a lane was judged. */ function laneCorrections() {
530
+ let e = false;
531
+ const n = lanes.slice();
532
+ for (let t = 0; t < n.length; t++) {
533
+ const u = n[t];
534
+ if (lanes.indexOf(u) === -1) continue;
535
+ const l = resolveTx(u._parent);
536
+ if (!l.nt || l.tt !== 0 || l.B || ownFlights(l) || guessFlights(u)) continue;
537
+ e = true;
538
+ // Each guess's truth: the one beneath it (a landing held there), else
539
+ // the one it covered. (A correction dissolves the lane — the others are
540
+ // re-homed with theirs, `dissolveLane`.)
541
+ for (let e = 0; e < u.ln.length && lanes.indexOf(u) !== -1; e++) {
542
+ const n = u.ln[e];
543
+ if (n.i & CONFIG_GUESS && n.m.He === u) {
544
+ const e = n.Oe !== NOT_PENDING ? n.Oe : covered(n);
545
+ supersede(n, e, !n.ye || !n.ye(n.m.B, e));
546
+ }
547
+ }
548
+ }
549
+ return e;
550
+ }
551
+
552
+ function laneSeam(e, n) {
553
+ // Blocked — or one of its passes read a write the frame holds this seam:
554
+ // its runs wait, the pass re-derives on the screen next round.
555
+ if (n || blocked(e)) {
556
+ e.sn = true;
557
+ return;
558
+ }
559
+ e.sn = false;
560
+ e.Ze = true;
561
+ reruns(e);
562
+ for (let n = 0; n < e.ln.length; n++) {
563
+ const t = e.ln[n];
564
+ if (t.R & LEFT_SHOWN) {
565
+ t.R ^= LEFT_SHOWN;
566
+ insertSubs(t);
567
+ }
568
+ const u = t.m;
569
+ if (u.He !== e) continue;
570
+ if (!(t.i & CONFIG_GUESS) && !t.u && t.Oe !== NOT_PENDING) {
571
+ u.B = t.Oe;
572
+ t.Oe = NOT_PENDING;
573
+ }
574
+ // The frame this pass built is the screen's now; the one it replaced
575
+ // goes (as `commitPendingNode` retires a committed pass's).
576
+ if (u.Qe !== null || u.ve !== null) GlobalQueue.Fe(t, false, true);
577
+ t.i &= ~CONFIG_STAGED;
578
+ }
579
+ releaseQueues(e);
580
+ }
581
+
582
+ /** The parent landed: its lanes end, nested first. (None is blocked: a
583
+ * blocked lane blocks its parent.) */ function endLanes(e) {
584
+ for (let n = lanes.length - 1; n >= 0; n--) {
585
+ const t = lanes[n];
586
+ if (resolveTx(t._parent) !== e) continue;
587
+ endLanes(t);
588
+ dissolveLane(t, null);
589
+ }
590
+ }
591
+
592
+ /** A blocked lane blocks its parent (maintainer, 2026-10-01): the lane's
593
+ * pending work derives from the frame's write through the guess, so the
594
+ * frame is not complete without it (A15) — landing it would commit the write
595
+ * beside a derivation still showing the old one. A guess whose own flight is
596
+ * up likewise: the question was asked in this frame. */ function lanesBlocked(e) {
597
+ return e.B && linkBlocked(e) || nestedBlocked(e);
598
+ }
599
+
600
+ /** The lanes under `t` (its own; a link group's are each other's). */ function nestedBlocked(e) {
601
+ for (let n = 0; n < lanes.length; n++) {
602
+ const t = lanes[n];
603
+ if (resolveTx(t._parent) !== e) continue;
604
+ if (blocked(t) || guessFlights(t)) return true;
605
+ }
606
+ return false;
607
+ }
608
+
609
+ /** A write landing on a lane's node (core.ts `setSignal`: a user's write, an
610
+ * async landing). On a guess it is its truth (A18 — an async guess's own
611
+ * landing), judged against the guess. On a derivation it is the lane's
612
+ * latest: its staging once the lane has shown (promoted at the next
613
+ * reveal), its slot before; the lane's members re-derive as its work. */ function laneWrite(e, n) {
614
+ if (e.i & CONFIG_GUESS) {
615
+ // Provenance (A18, #3331; Q-D, plan sec. 39): a write asking an OLDER
616
+ // question than the guess's — another action's landing beneath it —
617
+ // is not its answer: held beneath (the truth for the commit; the
618
+ // guess's own question judges), and nothing moves. The writer's
619
+ // question is the one being asked (`question`: a slice's, a derive's
620
+ // continuation's — the flight's); unstamped writes and mainline are
621
+ // current.
622
+ if (stale(e, question)) {
623
+ e.Oe = n;
624
+ e.i |= CONFIG_HELD;
625
+ GlobalQueue.an?.(e, n);
626
+ schedule();
627
+ return n;
628
+ }
629
+ supersede(e, n, !e.ye || !e.ye(e.m.B, n));
630
+ } else {
631
+ const t = txOf(e);
632
+ if (e.ye && e.ye(laneValueOf(e), n)) return n;
633
+ if (t.Ze) e.Oe = n; else e.m.B = n;
634
+ if (e.ee !== undefined) e.Ie = clock;
635
+ insertSubs(e);
636
+ laneDirty(e, t);
637
+ }
638
+ schedule();
639
+ return n;
640
+ }
641
+
642
+ /** A written guess's own pass finished: its source recomputed it — the
643
+ * truth (A18: "the source is whatever recomputes the node"), authoritative
644
+ * or the lane's own derivation (a guess over `config().courier` under a
645
+ * country guess: the lane's config landing confirms or corrects it). An
646
+ * errored pass stages nothing. Provenance (A18, #3331): "the source" is the
647
+ * guess's own question or a newer one; an older action's answer landing
648
+ * over a newer guess (the two entangled when the newer guess was written)
649
+ * is stale — a slow source leaking back in over the user's latest intent.
650
+ * It is staged beneath the guess, for the commit like any landing, and
651
+ * nothing moves: no downstream re-ask, no pending flip on the guess's
652
+ * readers (`isPending` of the guess itself says the held truth differs,
653
+ * A24). The guess's own question answering supersedes as usual. */ function laneOutcome(e, n, t) {
654
+ if (t) return true;
655
+ if (stale(e, answered(e))) {
656
+ e.Oe = n;
657
+ e.i |= CONFIG_HELD;
658
+ return true;
659
+ }
660
+ supersede(e, n, !e.ye || !e.ye(e.m.B, n));
661
+ return true;
662
+ }
663
+
664
+ /** THE provenance test, for a derivation's pass and a write alike: an
665
+ * answer to question `q` landing on a guess is stale when `q` is older
666
+ * than the guess's own; unstamped (0) and mainline are current. */ function stale(e, n) {
667
+ return n !== 0 && n < e.m._e;
668
+ }
669
+
670
+ /** The question a derivation's pass answered: the newest among the stamped
671
+ * sources that changed this round (a flight's landing carries the question
672
+ * that started it); 0 when none is stamped. */ function answered(e) {
673
+ let n = 0;
674
+ for (let t = e.p; t !== null; t = t._) {
675
+ const e = t.I;
676
+ if (e.m !== null && e.m._e > n && e.Ie === clock) n = e.m._e;
677
+ }
678
+ return n;
679
+ }
680
+
681
+ GlobalQueue.rt = laneRead;
682
+
683
+ GlobalQueue.W = laneStage;
684
+
685
+ GlobalQueue.We = laneOutcome;
686
+
687
+ GlobalQueue.Nt = laneWrite;
688
+
689
+ /** The lanes alive before this seam's guesses opened theirs (a prefix of
690
+ * `lanes`; nothing dissolves one between here and the seam loop): a lane
691
+ * born at the seam has no work to judge yet (its passes run next round) —
692
+ * it is neither shown nor blocked until it has. */ let judged = 0;
693
+
694
+ GlobalQueue.In = e => {
695
+ judged = lanes.length;
696
+ if (pendingGuesses.length !== 0) applyGuesses(e);
697
+ };
698
+
699
+ GlobalQueue._n = e => {
700
+ // Passes that read a write the parked frame holds as the screen
701
+ // (`stagedReaders`: lane work, a verdict reader before the verdict): they
702
+ // re-derive on the committed world next round (and register as stale
703
+ // readers of the transaction there); a lane's runs wait that round — a
704
+ // lane sees the screen plus its own guesses.
705
+ const n = [];
706
+ if (e !== null) for (let t = 0; t < e.length; t++) {
707
+ const u = e[t];
708
+ const l = u.m?.He;
709
+ // A verdict reader a later read of the same pass routed into a verdict
710
+ // lane answered for itself: it re-derives at the holder's landing, not
711
+ // now (one run — #3322, #3540). Other verdict-lane work re-derives only
712
+ // if the frame stays parked: a transaction landing at this seam makes
713
+ // what it read the screen (one run).
714
+ if (u.R & REACTIVE_DISPOSED || l != null && l._parent?.xe === l && (u.i & CONFIG_VERDICT ? !(u.R & REACTIVE_PROBE_UNANSWERED) : !blocked(l._parent))) continue;
715
+ // A leaked effect re-derives seated in its lane from its first read: it
716
+ // carries no lane value (`laneStage`), so without this its pass starts
717
+ // as mainline, joins the parked frame on its first held read and reads
718
+ // the staging, then re-enters the lane at its guess read and leaks
719
+ // again — every round (#4014). A computed is already seated by its
720
+ // override, and a written guess's own pass stays the frame's.
721
+ if (l != null && l.B && u.u) u.R |= REACTIVE_LANE_DIRTY;
722
+ enqueueSub(u);
723
+ if (l != null && l.B && n.indexOf(l) === -1) n.push(l);
724
+ }
725
+ for (let e = Math.min(judged, lanes.length) - 1; e >= 0; e--) laneSeam(lanes[e], n.indexOf(lanes[e]) !== -1);
726
+ };
727
+
728
+ GlobalQueue.cn = () => lanes.length !== 0 && laneCorrections();
729
+
730
+ GlobalQueue.Gn = endLanes;
731
+
732
+ GlobalQueue.On = lanesBlocked;
733
+
734
+ GlobalQueue.$ = verdictLane;
735
+
736
+ export { display, enterLane, guessedValueOf, laneRead, laneStage, laneValueOf, optimisticWrite, pendingGuessOf, supersede, truthConfirmed, truthRead, verdictLane };