@solidjs/signals 2.0.0-rc.13 → 2.0.0-rc.14
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.
- package/dist/dev-shared.js +2000 -3768
- package/dist/dev.attribution.js +132 -79
- package/dist/dev.js +7226 -8488
- package/dist/observe/affects.js +125 -104
- package/dist/observe/boundaries.js +458 -665
- package/dist/observe/core/action.js +63 -66
- package/dist/observe/core/async.js +240 -383
- package/dist/observe/core/attribution-queries.js +1 -1
- package/dist/observe/core/attribution.js +240 -183
- package/dist/observe/core/constants.js +115 -187
- package/dist/observe/core/context.js +3 -3
- package/dist/observe/core/core.js +840 -1438
- package/dist/observe/core/dev.js +3 -3
- package/dist/observe/core/effect.js +75 -86
- package/dist/observe/core/external.js +5 -5
- package/dist/observe/core/graph.js +61 -70
- package/dist/observe/core/heap.js +75 -98
- package/dist/observe/core/invariants.js +1 -34
- package/dist/observe/core/lanes.js +704 -181
- package/dist/observe/core/owner.js +80 -101
- package/dist/observe/core/scheduler.js +708 -1351
- package/dist/observe/core/verdict.js +302 -621
- package/dist/observe/flatten.js +79 -0
- package/dist/observe/index.js +15 -13
- package/dist/observe/map.js +232 -235
- package/dist/observe/reveal.js +212 -0
- package/dist/observe/signals.js +133 -215
- package/dist/observe/store/affects.js +135 -0
- package/dist/observe/store/index.js +29 -24
- package/dist/observe/store/optimistic.js +538 -0
- package/dist/observe/store/projection.js +302 -0
- package/dist/observe/store/reconcile.js +257 -0
- package/dist/observe/store/store.js +1945 -277
- package/dist/observe/store/storePath.js +1 -1
- package/dist/{prod/store/next → observe/store}/target.js +17 -18
- package/dist/observe/store/types.js +73 -0
- package/dist/observe/store/utils.js +1 -13
- package/dist/prod/affects.js +127 -106
- package/dist/prod/boundaries.js +442 -654
- package/dist/prod/core/action.js +71 -74
- package/dist/prod/core/async.js +307 -442
- package/dist/prod/core/constants.js +112 -186
- package/dist/prod/core/context.js +3 -3
- package/dist/prod/core/core.js +852 -1458
- package/dist/prod/core/effect.js +88 -99
- package/dist/prod/core/external.js +5 -5
- package/dist/prod/core/graph.js +61 -70
- package/dist/prod/core/heap.js +75 -98
- package/dist/prod/core/invariants.js +1 -32
- package/dist/prod/core/lanes.js +666 -181
- package/dist/prod/core/owner.js +75 -96
- package/dist/prod/core/scheduler.js +677 -1332
- package/dist/prod/core/verdict.js +297 -621
- package/dist/prod/flatten.js +77 -0
- package/dist/prod/index.js +15 -13
- package/dist/prod/map.js +143 -146
- package/dist/prod/reveal.js +212 -0
- package/dist/prod/signals.js +144 -226
- package/dist/prod/store/affects.js +135 -0
- package/dist/prod/store/index.js +28 -19
- package/dist/prod/store/optimistic.js +533 -0
- package/dist/prod/store/projection.js +295 -0
- package/dist/prod/store/reconcile.js +257 -0
- package/dist/prod/store/store.js +1840 -272
- package/dist/prod/store/storePath.js +1 -1
- package/dist/{observe/store/next → prod/store}/target.js +13 -17
- package/dist/prod/store/types.js +73 -0
- package/dist/prod/store/utils.js +1 -11
- package/dist/types/affects.d.ts +11 -30
- package/dist/types/boundaries.d.ts +62 -176
- package/dist/types/carved.d.ts +1 -0
- package/dist/types/core/action.d.ts +5 -6
- package/dist/types/core/async.d.ts +10 -5
- package/dist/types/core/attribution-hooks.d.ts +20 -1
- package/dist/types/core/attribution.d.ts +20 -9
- package/dist/types/core/constants.d.ts +125 -180
- package/dist/types/core/core.d.ts +104 -264
- package/dist/types/core/dev.d.ts +2 -2
- package/dist/types/core/effect.d.ts +0 -7
- package/dist/types/core/graph.d.ts +7 -1
- package/dist/types/core/heap.d.ts +5 -7
- package/dist/types/core/index.d.ts +5 -5
- package/dist/types/core/invariants.d.ts +0 -29
- package/dist/types/core/lanes.d.ts +65 -87
- package/dist/types/core/owner.d.ts +3 -3
- package/dist/types/core/scheduler.d.ts +249 -331
- package/dist/types/core/types.d.ts +51 -85
- package/dist/types/core/verdict.d.ts +3 -0
- package/dist/types/flatten.d.ts +8 -0
- package/dist/types/index.d.ts +6 -4
- package/dist/types/reveal.d.ts +19 -0
- package/dist/types/signals.d.ts +35 -91
- package/dist/types/store/affects.d.ts +1 -0
- package/dist/types/store/index.d.ts +35 -15
- package/dist/types/store/optimistic.d.ts +23 -0
- package/dist/types/store/projection.d.ts +18 -0
- package/dist/types/store/reconcile.d.ts +3 -0
- package/dist/types/store/store.d.ts +165 -143
- package/dist/types/store/storePath.d.ts +1 -1
- package/dist/types/store/target.d.ts +151 -0
- package/dist/types/store/types.d.ts +84 -0
- package/package.json +1 -1
- package/dist/observe/core/optimistic.js +0 -669
- package/dist/observe/store/next/optimistic.js +0 -717
- package/dist/observe/store/next/projection.js +0 -266
- package/dist/observe/store/next/reconcile.js +0 -375
- package/dist/observe/store/next/store.js +0 -2608
- package/dist/prod/core/optimistic.js +0 -658
- package/dist/prod/store/next/optimistic.js +0 -710
- package/dist/prod/store/next/projection.js +0 -257
- package/dist/prod/store/next/reconcile.js +0 -373
- package/dist/prod/store/next/store.js +0 -2484
- package/dist/types/core/optimistic.d.ts +0 -6
- package/dist/types/store/next/optimistic.d.ts +0 -25
- package/dist/types/store/next/projection.d.ts +0 -27
- package/dist/types/store/next/reconcile.d.ts +0 -10
- package/dist/types/store/next/store.d.ts +0 -145
- package/dist/types/store/next/target.d.ts +0 -196
|
@@ -1,205 +1,728 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CONFIG_GUESS, NOT_PENDING, CONFIG_OVERRIDE, REACTIVE_DISPOSED, CONFIG_VERDICT, REACTIVE_PROBE_UNANSWERED, 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, REACTIVE_LANE_DIRTY, CONFIG_STAGED, REACTIVE_JOINED, CONFIG_SLOT_NODE, REACTIVE_IN_HEAP, REACTIVE_DIRTY, REACTIVE_CHECK, CONFIG_INPUTS_PUBLISHED } from "./constants.js";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { attrHooks } from "./attribution-hooks.js";
|
|
4
|
+
|
|
5
|
+
import { tracking, ext, stagedRead } from "./core.js";
|
|
6
|
+
|
|
7
|
+
import { NotReadyError } from "./error.js";
|
|
4
8
|
|
|
5
9
|
import { enqueueSub } from "./heap.js";
|
|
6
10
|
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
//
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
11
|
+
import { schedule, question, nextQuestion, GlobalQueue, blocked, resolveTx, txOf, passLane, sameLane, flushTransaction, queuePendingNode, list, clock, insertSubs, laneDirty, merge, newTransaction, reruns, releaseQueues, ownFlights, setPassLane, holdNode, joinFuture, commitPendingNode } from "./scheduler.js";
|
|
12
|
+
|
|
13
|
+
// Lanes (plan sec. 28 replay, 2026-10-02; maintainer rulings 2026-10-01/02). A lane
|
|
14
|
+
// is "a new base of a transition": the sub-frame an optimistic write opens
|
|
15
|
+
// in the transition of the frame it is made in. It sees the screen plus its
|
|
16
|
+
// own guesses (plan sec. 19), breaks out of the parent's hold — its effects run now —
|
|
17
|
+
// and holds itself if its own derivations hit async (and, blocked, holds its
|
|
18
|
+
// parent). It ends when the parent lands: a guess reverts to the truth it
|
|
19
|
+
// covered, or lands as the truth that superseded it. A frame that does not
|
|
20
|
+
// park has nothing to be optimistic over: the write is void.
|
|
21
|
+
// Three places per node, each meaning one thing always: `_value` is the
|
|
22
|
+
// committed truth, `_pendingValue` a transaction's staging (the future), and
|
|
23
|
+
// `_x._lane` the lane's value — a written guess or a lane pass's derivation.
|
|
24
|
+
// The lane carries the state machine: `_shown` once it has revealed. The
|
|
25
|
+
// screen shows a lane's value once the lane has shown (`display`); a direct
|
|
26
|
+
// read sees it throughout (A17); an authoritative reader (`until`) sees the
|
|
27
|
+
// truth beneath it (Q3, 2026-10-02: "optimistic overrides are intentionally
|
|
28
|
+
// not part of authoritative truth").
|
|
29
|
+
// The seat of a pass is its node's (core.ts `recompute`): a node carrying a
|
|
30
|
+
// lane's derived value runs as the lane's whoever dirtied it; a derivation's
|
|
31
|
+
// tracked read of a lane's value moves its pass into the lane (`enterLane`);
|
|
32
|
+
// a leaf's never does — it reads the screen, a stale reader of a lane that
|
|
33
|
+
// has not shown (#3460). Lane work's values go to the lane slot (or, once
|
|
34
|
+
// the lane has shown, to its staging for the next reveal), its runs to the
|
|
35
|
+
// lane's queues.
|
|
36
|
+
// This module is the lane engine, installed on `GlobalQueue` when something
|
|
37
|
+
// imports it (`createOptimistic`, or verdict.ts for its verdict lanes). The
|
|
38
|
+
// core keeps only bit tests and `passLane`: a program with no optimism
|
|
39
|
+
// carries none of this.
|
|
40
|
+
/** Live lanes (parented). Scanned at every seam while non-empty. */
|
|
41
|
+
const lanes = [];
|
|
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.u & CONFIG_GUESS) && e.Ae !== NOT_PENDING) return e.Ae;
|
|
53
|
+
const n = e.m.Z;
|
|
54
|
+
return n !== NOT_PENDING ? n : e.pe;
|
|
47
55
|
}
|
|
48
56
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
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.xn === n && !t.qn) t.qn = 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.Z;
|
|
60
|
+
return e.m._t.Tt && n !== NOT_PENDING ? n : e.pe;
|
|
57
61
|
}
|
|
58
62
|
|
|
59
|
-
/**
|
|
60
|
-
*
|
|
61
|
-
|
|
62
|
-
|
|
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.u & CONFIG_OVERRIDE ? laneValueOf(e) : e.pe;
|
|
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.tn && e.tn(t, n) && !(e.u & CONFIG_GUESS)) return n;
|
|
92
|
+
pendingGuesses.push(e, n, question || nextQuestion());
|
|
93
|
+
schedule();
|
|
63
94
|
return n;
|
|
64
95
|
}
|
|
65
96
|
|
|
66
|
-
/**
|
|
67
|
-
*
|
|
68
|
-
* under
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
for (
|
|
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.G & STATUS_PENDING) !== 0 || (e.u & CONFIG_SLOT_NODE) !== 0 && GlobalQueue.F?.(e) === true;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function applyGuesses(e) {
|
|
113
|
+
let n = null;
|
|
114
|
+
for (let t = 0; t < pendingGuesses.length; t += 3) {
|
|
115
|
+
const s = pendingGuesses[t];
|
|
116
|
+
const l = pendingGuesses[t + 1];
|
|
117
|
+
let u = true;
|
|
118
|
+
if (s.u & 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
|
+
u = !s.tn || !s.tn(laneValueOf(s), l);
|
|
125
|
+
if (!(s.u & CONFIG_GUESS)) {
|
|
126
|
+
s.Ae = NOT_PENDING;
|
|
127
|
+
s.u |= CONFIG_GUESS;
|
|
128
|
+
}
|
|
129
|
+
s.m.Z = l;
|
|
130
|
+
const n = txOf(s)._parent;
|
|
131
|
+
if (e !== null && n !== null) merge(e, n);
|
|
132
|
+
} else {
|
|
133
|
+
let t;
|
|
134
|
+
if (s.u & CONFIG_HELD) t = newLane(txOf(s)); else {
|
|
135
|
+
if (e === null && inFlight(s)) 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(s).Z = l;
|
|
146
|
+
s.u |= CONFIG_OVERRIDE | CONFIG_GUESS;
|
|
147
|
+
list(s, t);
|
|
148
|
+
}
|
|
149
|
+
ext(s).Oe = pendingGuesses[t + 2];
|
|
150
|
+
if (u) {
|
|
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(s);
|
|
155
|
+
laneDirty(s, txOf(s));
|
|
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.
|
|
177
|
+
if (n.R & REACTIVE_JOINED) stagedRead(n);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (sameLane(t, e)) return setPassLane(e);
|
|
181
|
+
if (under(t, e)) return;
|
|
182
|
+
if (under(e, t)) return setPassLane(e);
|
|
183
|
+
linkLanes(t, e);
|
|
184
|
+
setPassLane(e);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** Is `l` nested under `a` (an ancestor lane)? */ function under(e, n) {
|
|
188
|
+
for (let t = e._parent; t !== null && t.Z; t = t._parent) if (t === n) return true;
|
|
84
189
|
return false;
|
|
85
190
|
}
|
|
86
191
|
|
|
87
|
-
/**
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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.It[0].push(() => e.oe & REACTIVE_DISPOSED || enqueueSub(e));
|
|
114
|
-
return true;
|
|
192
|
+
/** One link group (a shared array) for both lanes' groups. */ function linkLanes(e, n) {
|
|
193
|
+
const t = e.un ?? (e.un = [ e ]);
|
|
194
|
+
const s = n.un;
|
|
195
|
+
if (s === t) return;
|
|
196
|
+
if (s === null) {
|
|
197
|
+
t.push(n);
|
|
198
|
+
n.un = t;
|
|
199
|
+
} else for (let e = 0; e < s.length; e++) {
|
|
200
|
+
t.push(s[e]);
|
|
201
|
+
s[e].un = t;
|
|
202
|
+
}
|
|
115
203
|
}
|
|
116
204
|
|
|
117
|
-
/**
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
n
|
|
132
|
-
|
|
133
|
-
if (
|
|
134
|
-
e.
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
return
|
|
205
|
+
/** A linked lane blocked on its own account blocks the group — `blocked(k)`
|
|
206
|
+
* without the group recursion. (A guess in `k` whose own truth is in flight
|
|
207
|
+
* blocks `k`'s parent, not `k` — nor, through the link, `l`: the guess
|
|
208
|
+
* shows, A17.) */ function linkBlocked(e) {
|
|
209
|
+
const n = e.un;
|
|
210
|
+
if (n !== null) for (let t = 0; t < n.length; t++) {
|
|
211
|
+
const s = n[t];
|
|
212
|
+
if (s !== e && (s.tt !== 0 || ownFlights(s) || nestedBlocked(s))) return true;
|
|
213
|
+
}
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function unlink(e) {
|
|
218
|
+
const n = e.un;
|
|
219
|
+
if (n === null) return;
|
|
220
|
+
const t = n.indexOf(e);
|
|
221
|
+
if (t !== -1) n.splice(t, 1);
|
|
222
|
+
e.un = null;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/** Verdicts (maintainer, 2026-10-01): `isPending` and `latest` are
|
|
226
|
+
* optimistic state the system supplies — a verdict is a guess ("pending,
|
|
227
|
+
* until this lands"; "the proposal is the value") decided at the seam like
|
|
228
|
+
* a user's, and its readers break out of the hold the same way: work of a
|
|
229
|
+
* lane under the holder, shown now, re-derived at the landing, ending with
|
|
230
|
+
* it. Judged at the seam like any lane: blocked while a verdict reader's
|
|
231
|
+
* own derivation is in flight (lane rule 3), shown otherwise. */ function verdictLane(e) {
|
|
232
|
+
return e.rt ??= newLane(e);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** A lane pass's node (core.ts `recompute`, before its staging; a pending
|
|
236
|
+
* propagation under a lane pass, async.ts): listed, carrying the lane's
|
|
237
|
+
* value from now (a derivation of a guess — its readers become lane work).
|
|
238
|
+
* Entering the lane supersedes a frame staging the node carried: this
|
|
239
|
+
* pass's answer replaces it, and the frame's hold on it is over. An
|
|
240
|
+
* effect's value slot is private (no lane value). A pass in a lane's seat
|
|
241
|
+
* that read none of the lane's world has left it (false): its result is the
|
|
242
|
+
* frame's — a derivation whose branch no longer reaches the guess — and no
|
|
243
|
+
* hold the lane took over from a transaction stays on it (#3698: lane work
|
|
244
|
+
* never makes its node transaction work; a born-held effect's hold went to
|
|
245
|
+
* the lane). A pass interrupted before it got there (pending, errored) did
|
|
246
|
+
* not leave (A30: it never got there). A first pass under a lane is the
|
|
247
|
+
* lane's (ruling A); a guess is written, not derived — it never leaves this
|
|
248
|
+
* way. `errored`: the pass has no answer — or, a lane pass's pending
|
|
249
|
+
* propagation (async.ts `propagateStatus`), the node gone pending. */ function laneStage(e, n, t, s) {
|
|
250
|
+
if (!(t || s || e.R & REACTIVE_LANE_READ || e.u & CONFIG_GUESS)) {
|
|
251
|
+
if (e.m !== null) {
|
|
252
|
+
if (e.m._t?.Z) e.m._t = null;
|
|
253
|
+
e.m.Z = NOT_PENDING;
|
|
254
|
+
}
|
|
255
|
+
e.u &= -2305;
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
if (!e.i) {
|
|
259
|
+
if (!(e.u & CONFIG_OVERRIDE)) {
|
|
260
|
+
e.Ae = NOT_PENDING;
|
|
261
|
+
e.u = e.u & ~CONFIG_HELD | CONFIG_OVERRIDE;
|
|
262
|
+
ext(e);
|
|
263
|
+
}
|
|
264
|
+
// A written guess whose own pass is the lane's work — its source is a
|
|
265
|
+
// derivation of another guess (a guess over `config().courier` under a
|
|
266
|
+
// country guess) — is confirmed or corrected by the lane: a derivation
|
|
267
|
+
// of the lane from here (its value the lane's, its fate the lane's), no
|
|
268
|
+
// longer a written guess. A pass with no answer (pending, errored)
|
|
269
|
+
// leaves the guess.
|
|
270
|
+
if (!s) e.u &= ~CONFIG_GUESS;
|
|
271
|
+
}
|
|
272
|
+
// A leaf has no lane value to seat it (`recompute`): one left waiting on
|
|
273
|
+
// the lane's flight runs its next pass as the lane's — the landing that
|
|
274
|
+
// wakes it is the lane's re-staging (A31), and the lane holds its render
|
|
275
|
+
// effects until its derivations land (A17; #3766, F5). Not a leaf whose
|
|
276
|
+
// seat is its frame's, reached by a propagation from a node the screen has
|
|
277
|
+
// a value of: one a transaction holds (born held — its frame waits on it,
|
|
278
|
+
// A29), or one whose own mainline pass is running (it pulled the node;
|
|
279
|
+
// `laneRead` decides — its frame holds). Its pending is the frame's: queued
|
|
280
|
+
// for the commit sweep as mainline's (async.ts). A node born in the lane
|
|
281
|
+
// has nothing on screen: its leaf waits as the lane's.
|
|
282
|
+
else if (s) {
|
|
283
|
+
if (s !== true && !(s.G & STATUS_UNINITIALIZED) && (e.u & CONFIG_HELD || e.R & REACTIVE_RECOMPUTING_DEPS) && !e.m?._t?.Z) {
|
|
284
|
+
queuePendingNode(e);
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
e.R |= REACTIVE_LANE_DIRTY;
|
|
288
|
+
}
|
|
289
|
+
list(e, n);
|
|
290
|
+
return true;
|
|
145
291
|
}
|
|
146
292
|
|
|
147
|
-
/**
|
|
148
|
-
*
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
//
|
|
160
|
-
//
|
|
161
|
-
//
|
|
162
|
-
|
|
163
|
-
// reader. Chase merge chains; a dead owner settled through another path.
|
|
164
|
-
if (hasActiveOverride(n) && n.o?.Vt) {
|
|
165
|
-
const e = ext(n).Vt = currentTransition(n.o?.Vt);
|
|
166
|
-
if (e.Dt !== true) return e;
|
|
167
|
-
if (n.o !== null) n.o.Vt = null;
|
|
168
|
-
}
|
|
169
|
-
return resolveLane(n)?.me ?? n.me;
|
|
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?.Ce;
|
|
293
|
+
/** The truth arrived for a written guess (A18): a correction dissolves the
|
|
294
|
+
* lane — the guess and everything derived from it is void, the truth is
|
|
295
|
+
* the parent's held write and the graph re-derives from it there, one frame
|
|
296
|
+
* at the parent's landing — while the display keeps what it shows until
|
|
297
|
+
* then. A confirmation is silent (A17): the truth stays staged beneath the
|
|
298
|
+
* guess for the parent's commit, the guess stays the value; only a reader
|
|
299
|
+
* of the truth (CONFIG_AUTHORITATIVE) is told its view changed. */
|
|
300
|
+
/** Observe: the correction round is replacing a guess with the value it
|
|
301
|
+
* covered (no landing beneath it) — `optimisticReverted`'s "reverted". */ let reverting = false;
|
|
302
|
+
|
|
303
|
+
function supersede(e, n, t) {
|
|
304
|
+
const s = txOf(e);
|
|
305
|
+
// Resolved: the parent may have merged into another transaction since the
|
|
306
|
+
// lane opened (two actions guessing one slot entangle, A34 (1)) — the
|
|
307
|
+
// truth is held by the transaction that lands, not the merged-away one.
|
|
308
|
+
const l = resolveTx(s._parent ?? s);
|
|
178
309
|
if (t) {
|
|
179
|
-
//
|
|
180
|
-
//
|
|
181
|
-
//
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
//
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
310
|
+
// Observe: a displayed guess is being replaced by a differing truth — a
|
|
311
|
+
// landing's (superseded), or the value it covered (reverted: the body
|
|
312
|
+
// ended with nothing coming true).
|
|
313
|
+
if (s.Tt && attrHooks !== null) attrHooks.optimisticReverted(e, e.m.Z, n, reverting ? "reverted" : "superseded");
|
|
314
|
+
dissolveLane(s, l, e);
|
|
315
|
+
// What the screen showed stays the screen until the parent lands (A18
|
|
316
|
+
// (c): display and untracked reads keep the override until the commit).
|
|
317
|
+
if (s.Tt) e.pe = e.m.Z;
|
|
318
|
+
e.u &= -10241;
|
|
319
|
+
e.m.Z = NOT_PENDING;
|
|
320
|
+
e.Ae = n;
|
|
321
|
+
holdNode(e, l);
|
|
322
|
+
joinFuture(l);
|
|
323
|
+
if (e.t !== null) insertSubs(e);
|
|
324
|
+
} else {
|
|
325
|
+
e.Ae = n;
|
|
326
|
+
e.u |= CONFIG_HELD;
|
|
327
|
+
joinFuture(l);
|
|
328
|
+
for (let n = e.t; n !== null; n = n.l) if (n.o.u & CONFIG_AUTHORITATIVE) enqueueSub(n.o);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/** A lane's end, two ways. `into === null`: the parent landed — the lane's
|
|
333
|
+
* values are the truth now: a guess lands the truth staged beneath it or
|
|
334
|
+
* reverts to the one it covered (`_value`, untouched by the guess); a
|
|
335
|
+
* derivation's latest value commits (its frame with it); what the screen
|
|
336
|
+
* showed and changes notifies. Otherwise the lane dissolves into `into`
|
|
337
|
+
* (the parent, on a correction): its values are void — what it showed stays
|
|
338
|
+
* the screen (`_value` takes it, so the parent's re-derivation compares
|
|
339
|
+
* against what is seen), a truth staged beneath a guess is the parent's to
|
|
340
|
+
* land, and the runs it held (showing the void guess) are dropped: the
|
|
341
|
+
* parent's re-derivation makes the runs that show. */ function dissolveLane(e, n, t) {
|
|
342
|
+
const s = lanes.indexOf(e);
|
|
343
|
+
if (s !== -1) lanes.splice(s, 1);
|
|
344
|
+
unlink(e);
|
|
345
|
+
// Its verdicts end with it (a correction's dissolution reaches here before
|
|
346
|
+
// `endLanes` would): the readers re-derive from the truth's notification.
|
|
347
|
+
const l = e.rt;
|
|
348
|
+
if (l !== null) {
|
|
349
|
+
e.rt = null;
|
|
350
|
+
if (lanes.indexOf(l) !== -1) dissolveLane(l, null);
|
|
351
|
+
}
|
|
352
|
+
for (let s = 0; s < e.nn.length; s++) {
|
|
353
|
+
const l = e.nn[s];
|
|
354
|
+
const u = l.m;
|
|
355
|
+
if (l === t || u._t !== e) continue;
|
|
356
|
+
const r = l.i;
|
|
357
|
+
const i = l.u & CONFIG_GUESS;
|
|
358
|
+
const o = u.Z;
|
|
359
|
+
// What the screen shows of it (NOT_PENDING: nothing — a lane pass that
|
|
360
|
+
// errored or pends staged no value), and the lane's latest.
|
|
361
|
+
const f = e.Tt && !r ? o : l.pe;
|
|
362
|
+
const E = laneValueOf(l);
|
|
363
|
+
u.Z = NOT_PENDING;
|
|
364
|
+
l.u &= -10241;
|
|
365
|
+
if (n === null) {
|
|
366
|
+
// The parent landed: a guess lands the truth beneath it or reverts to
|
|
367
|
+
// the one it covered; a derivation's latest commits (its frame with
|
|
368
|
+
// it); what the screen showed and changes notifies. Observe: a
|
|
369
|
+
// displayed guess that lifts to something else — the truth staged
|
|
370
|
+
// beneath it (superseded by a landing held there) or the value it
|
|
371
|
+
// covered (reverted: nothing came true).
|
|
372
|
+
if (i && e.Tt && attrHooks !== null) {
|
|
373
|
+
const e = l.Ae !== NOT_PENDING ? l.Ae : l.pe;
|
|
374
|
+
if (e !== o) attrHooks.optimisticReverted(l, o, e, l.Ae !== NOT_PENDING ? "superseded" : "reverted");
|
|
375
|
+
}
|
|
376
|
+
// A derivation the revert re-derives (dirtied by the guess's
|
|
377
|
+
// notification — listed before it), or one still in flight, shows the
|
|
378
|
+
// lane's answer beside inputs that are the truth now: a fresh reader
|
|
379
|
+
// of its flight observes it (#3648, #3651; #3305's commit beneath a
|
|
380
|
+
// flight).
|
|
381
|
+
u._t = null;
|
|
382
|
+
if (!r && !i) l.Ae = E;
|
|
383
|
+
commitPendingNode(l);
|
|
384
|
+
if (!r) {
|
|
385
|
+
if (l.R & (REACTIVE_IN_HEAP | REACTIVE_DIRTY | REACTIVE_CHECK) || l.G & STATUS_PENDING) l.u |= CONFIG_INPUTS_PUBLISHED;
|
|
386
|
+
if (f !== NOT_PENDING && (!l.tn || !l.tn(f, l.pe))) insertSubs(l);
|
|
387
|
+
}
|
|
388
|
+
} else if (i) {
|
|
389
|
+
// A guess of a dissolving lane: its truth — a landing held beneath it,
|
|
390
|
+
// else the value it covered — is the parent's to land, and its readers
|
|
391
|
+
// re-derive from it there. What the screen showed stays the screen
|
|
392
|
+
// until then (A18 (c)).
|
|
393
|
+
if (l.Ae === NOT_PENDING) l.Ae = covered(l);
|
|
394
|
+
if (e.Tt) l.pe = o;
|
|
395
|
+
holdNode(l, n);
|
|
396
|
+
insertSubs(l);
|
|
397
|
+
} else {
|
|
398
|
+
// A correction: the lane's derivations are void. Shown, what the
|
|
399
|
+
// screen showed stays the screen (committed, inputs published — every
|
|
400
|
+
// one re-derives); never shown, nothing of it reached the screen (a
|
|
401
|
+
// node born in the lane stays uninitialized; its frame goes). One in
|
|
402
|
+
// flight is asking the void world's question: its landing is nobody's
|
|
403
|
+
// answer — it re-asks from the truth (whose notification may not reach
|
|
404
|
+
// it: an input's truth equal to its committed value is silent).
|
|
405
|
+
u._t = null;
|
|
406
|
+
if (!r) {
|
|
407
|
+
if (f !== NOT_PENDING && e.Tt) l.Ae = f;
|
|
408
|
+
if (l.G & STATUS_PENDING) {
|
|
409
|
+
u.De = null;
|
|
410
|
+
enqueueSub(l);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
if (e.Tt) {
|
|
414
|
+
commitPendingNode(l);
|
|
415
|
+
if (!r) l.u |= CONFIG_INPUTS_PUBLISHED;
|
|
416
|
+
} else {
|
|
417
|
+
if (u.St !== null || u.ct !== null) GlobalQueue.st(l, false, true);
|
|
418
|
+
l.u &= -385;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
// The parent landed: the runs the lane held (blocked on its own judgment
|
|
423
|
+
// alone — a zombie it could not dispose) are the landing's. A correction
|
|
424
|
+
// of a SHOWN lane keeps its runs too: "what it showed stays the screen"
|
|
425
|
+
// means the runs this round's lane passes queued (the body-end seam judges
|
|
426
|
+
// before the lane seam would have released them) must reach the screen —
|
|
427
|
+
// their derivations' values are the committed ones now, and a
|
|
428
|
+
// re-derivation that lands on the same value notifies nobody (a mapArray
|
|
429
|
+
// whose rows the lane pass already built). A never-shown lane's runs are
|
|
430
|
+
// void: nothing of it reached the screen. So are the runs a blocked lane
|
|
431
|
+
// parked: they show a re-guess the seam never revealed, beside derivations
|
|
432
|
+
// that keep what the screen showed.
|
|
433
|
+
if (n === null || e.Tt && !e.fn) releaseQueues(e); else e.En[0].length = e.En[1].length = 0;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/** Lanes. A lane's node is read by its reader's kind: an authoritative
|
|
437
|
+
* reader (`until`) sees the truth — staged beneath a guess, else committed
|
|
438
|
+
* — and is no lane's; an untracked read sees the lane's latest value (A17:
|
|
439
|
+
* "direct read shows optimistic"; A28); a children-forbidden reader sees
|
|
440
|
+
* the frame (A32). A render effect in the frame's seat reading a lane the
|
|
441
|
+
* seam found blocked, or a member whose own flight is up (held or not — the
|
|
442
|
+
* lane-membership ruling, 2026-10-05), sees the screen, re-derived at the
|
|
443
|
+
* reveal (#3460's stale reader) — or, the node a
|
|
444
|
+
* flight that has never shown (nothing to show), waits on it: its own frame
|
|
445
|
+
* holds (A15, #3334), not the lane's parent. Any other tracked reader is
|
|
446
|
+
* the lane's work from this read — a derivation; a leaf reading a lane that
|
|
447
|
+
* has shown, or one the seam has not judged yet (its run waits on the
|
|
448
|
+
* verdict: released if the lane shows, held if it blocks) — and sees the
|
|
449
|
+
* lane's latest. NOT_PENDING falls through: lane work's read of a pending
|
|
450
|
+
* member throws like any. */ function laneRead(e, n) {
|
|
451
|
+
const t = n.u & CONFIG_GUESS;
|
|
452
|
+
if (e !== null && e.u & CONFIG_AUTHORITATIVE) return t && n.Ae !== NOT_PENDING ? n.Ae : n.pe;
|
|
453
|
+
if (e === null) return laneValueOf(n);
|
|
454
|
+
const s = txOf(n);
|
|
455
|
+
const l = n.G;
|
|
456
|
+
if (!tracking || e.u & CONFIG_CHILDREN_FORBIDDEN) {
|
|
457
|
+
// An untracked read inside lane work derives from the lane like a
|
|
458
|
+
// tracked one, minus the subscription — `untrack` is about
|
|
459
|
+
// dependencies, not about which world a pass derives from (a mapper's
|
|
460
|
+
// row reads under its root, store/map): the pass enters the lane (two
|
|
461
|
+
// lanes read by one pass link, as for tracked reads). Outside lane
|
|
462
|
+
// work, the screen.
|
|
463
|
+
if (passLane === null || e.u & CONFIG_CHILDREN_FORBIDDEN) return display(n);
|
|
464
|
+
enterLane(s, e);
|
|
465
|
+
if (!t && l & STATUS_PENDING) return NOT_PENDING;
|
|
466
|
+
return laneValueOf(n);
|
|
467
|
+
}
|
|
468
|
+
if (e.i === EFFECT_RENDER && (passLane === null || !sameLane(passLane, s))) {
|
|
469
|
+
if (!t) {
|
|
470
|
+
// A flight whose value has never shown: nothing to show — the leaf
|
|
471
|
+
// waits on it, and its own frame holds (A15, #3334), not the lane's
|
|
472
|
+
// parent. The landing lands the frame: its own pass (the flush
|
|
473
|
+
// joined its transaction) reads the answer it waited on — the lane's
|
|
474
|
+
// staging, revealed at this seam.
|
|
475
|
+
if (l & STATUS_PENDING && n.m.Z === NOT_PENDING) return NOT_PENDING;
|
|
476
|
+
if (n.Ae !== NOT_PENDING && e.u & CONFIG_HELD && flushTransaction !== null && resolveTx(flushTransaction) === txOf(e)) return n.Ae;
|
|
477
|
+
}
|
|
478
|
+
if (s.fn || !t && l & STATUS_PENDING) {
|
|
479
|
+
if (!t && !s.Tt && l & STATUS_UNINITIALIZED) throw new NotReadyError(null);
|
|
480
|
+
// Re-derived at the reveal; once per pass (the pass may also be a stale
|
|
481
|
+
// reader of a transaction, REACTIVE_FRAME_READ — both reruns apply).
|
|
482
|
+
if (!(e.R & REACTIVE_SCREEN_READ)) {
|
|
483
|
+
e.R |= REACTIVE_FRAME_READ | REACTIVE_SCREEN_READ;
|
|
484
|
+
s.an.push(e);
|
|
197
485
|
}
|
|
198
|
-
return;
|
|
486
|
+
return display(n);
|
|
199
487
|
}
|
|
200
488
|
}
|
|
201
|
-
|
|
202
|
-
|
|
489
|
+
enterLane(s, e);
|
|
490
|
+
if (!t && l & STATUS_PENDING) return NOT_PENDING;
|
|
491
|
+
return laneValueOf(n);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/** The value a guess covered: the node's committed value — a store slot's
|
|
495
|
+
* asked of the store (a chained link follows the inner store's commits). */ function covered(e) {
|
|
496
|
+
return e.u & CONFIG_SLOT_NODE && GlobalQueue.Nn !== undefined ? GlobalQueue.Nn(e) : e.pe;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/** A guess in `l` whose own truth is in flight (its refetch — authoritative:
|
|
500
|
+
* the landing supersedes, not the body's end). */ function guessFlights(e) {
|
|
501
|
+
for (let n = 0; n < e.nn.length; n++) {
|
|
502
|
+
const t = e.nn[n];
|
|
503
|
+
if (t.u & CONFIG_GUESS && t.m._t === e && inFlight(t)) return true;
|
|
504
|
+
}
|
|
505
|
+
return false;
|
|
203
506
|
}
|
|
204
507
|
|
|
205
|
-
|
|
508
|
+
/** The seam's verdict on a lane. Blocked — its own flight is up — nothing
|
|
509
|
+
* moves: the screen keeps what it shows, the lane's runs wait. Unblocked,
|
|
510
|
+
* the lane shows: its values are the screen from now (`_shown`), the
|
|
511
|
+
* staging its passes made since the last reveal is promoted, their frames
|
|
512
|
+
* (children) apply, the stale readers re-derive (#3460), its runs go. */
|
|
513
|
+
/** A18 body-end corollary (#3427), at the seam before the park decision
|
|
514
|
+
* (the guesses' own passes have run; a correction's re-derivations run in
|
|
515
|
+
* one more pure round and are the parent's flights before it is judged —
|
|
516
|
+
* #3409: the indicators clear together): the action body having returned,
|
|
517
|
+
* a guess whose own truth is not in flight has no answer coming — the truth
|
|
518
|
+
* beneath it is its truth, and the correction starts now rather than at the
|
|
519
|
+
* lane's flight. (A guess whose own refetch is up is superseded by its
|
|
520
|
+
* landing.) True when a lane was judged. */ function laneCorrections() {
|
|
521
|
+
let e = false;
|
|
522
|
+
const n = lanes.slice();
|
|
523
|
+
for (let t = 0; t < n.length; t++) {
|
|
524
|
+
const s = n[t];
|
|
525
|
+
if (lanes.indexOf(s) === -1) continue;
|
|
526
|
+
const l = resolveTx(s._parent);
|
|
527
|
+
if (!l.nt || l.tt !== 0 || l.Z || ownFlights(l) || guessFlights(s)) continue;
|
|
528
|
+
e = true;
|
|
529
|
+
// Each guess's truth: the one beneath it (a landing held there), else
|
|
530
|
+
// the one it covered. (A correction dissolves the lane — the others are
|
|
531
|
+
// re-homed with theirs, `dissolveLane`.)
|
|
532
|
+
for (let e = 0; e < s.nn.length && lanes.indexOf(s) !== -1; e++) {
|
|
533
|
+
const n = s.nn[e];
|
|
534
|
+
if (n.u & CONFIG_GUESS && n.m._t === s) {
|
|
535
|
+
const e = n.Ae !== NOT_PENDING ? n.Ae : covered(n);
|
|
536
|
+
reverting = n.Ae === NOT_PENDING;
|
|
537
|
+
supersede(n, e, !n.tn || !n.tn(n.m.Z, e));
|
|
538
|
+
reverting = false;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
return e;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
function laneSeam(e, n) {
|
|
546
|
+
// Blocked — or one of its passes read a write the frame holds this seam:
|
|
547
|
+
// its runs wait, the pass re-derives on the screen next round.
|
|
548
|
+
if (n || blocked(e)) {
|
|
549
|
+
e.fn = true;
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
e.fn = false;
|
|
553
|
+
e.Tt = true;
|
|
554
|
+
reruns(e);
|
|
555
|
+
for (let n = 0; n < e.nn.length; n++) {
|
|
556
|
+
const t = e.nn[n];
|
|
557
|
+
const s = t.m;
|
|
558
|
+
if (s._t !== e) continue;
|
|
559
|
+
if (!(t.u & CONFIG_GUESS) && !t.i && t.Ae !== NOT_PENDING) {
|
|
560
|
+
s.Z = t.Ae;
|
|
561
|
+
t.Ae = NOT_PENDING;
|
|
562
|
+
}
|
|
563
|
+
// The frame this pass built is the screen's now; the one it replaced
|
|
564
|
+
// goes (as `commitPendingNode` retires a committed pass's).
|
|
565
|
+
if (s.St !== null || s.ct !== null) GlobalQueue.st(t, false, true);
|
|
566
|
+
t.u &= ~CONFIG_STAGED;
|
|
567
|
+
}
|
|
568
|
+
releaseQueues(e);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/** The parent landed: its lanes end, nested first. (None is blocked: a
|
|
572
|
+
* blocked lane blocks its parent.) */ function endLanes(e) {
|
|
573
|
+
for (let n = lanes.length - 1; n >= 0; n--) {
|
|
574
|
+
const t = lanes[n];
|
|
575
|
+
if (resolveTx(t._parent) !== e) continue;
|
|
576
|
+
endLanes(t);
|
|
577
|
+
dissolveLane(t, null);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/** A blocked lane blocks its parent (maintainer, 2026-10-01): the lane's
|
|
582
|
+
* pending work derives from the frame's write through the guess, so the
|
|
583
|
+
* frame is not complete without it (A15) — landing it would commit the write
|
|
584
|
+
* beside a derivation still showing the old one. A guess whose own flight is
|
|
585
|
+
* up likewise: the question was asked in this frame. */ function lanesBlocked(e) {
|
|
586
|
+
return e.Z && linkBlocked(e) || nestedBlocked(e);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/** The lanes under `t` (its own; a link group's are each other's). */ function nestedBlocked(e) {
|
|
590
|
+
for (let n = 0; n < lanes.length; n++) {
|
|
591
|
+
const t = lanes[n];
|
|
592
|
+
if (resolveTx(t._parent) !== e) continue;
|
|
593
|
+
if (blocked(t) || guessFlights(t)) return true;
|
|
594
|
+
}
|
|
595
|
+
return false;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/** A write landing on a lane's node (core.ts `setSignal`: a user's write, an
|
|
599
|
+
* async landing). On a guess it is its truth (A18 — an async guess's own
|
|
600
|
+
* landing), judged against the guess. On a derivation it is the lane's
|
|
601
|
+
* latest: its staging once the lane has shown (promoted at the next
|
|
602
|
+
* reveal), its slot before; the lane's members re-derive as its work. */ function laneWrite(e, n) {
|
|
603
|
+
if (e.u & CONFIG_GUESS) {
|
|
604
|
+
// Provenance (A18, #3331; Q-D, plan sec. 39): a write asking an OLDER
|
|
605
|
+
// question than the guess's — another action's landing beneath it —
|
|
606
|
+
// is not its answer: held beneath (the truth for the commit; the
|
|
607
|
+
// guess's own question judges), and nothing moves. The writer's
|
|
608
|
+
// question is the one being asked (`question`: a slice's, a derive's
|
|
609
|
+
// continuation's — the flight's); unstamped writes and mainline are
|
|
610
|
+
// current.
|
|
611
|
+
if (stale(e, question)) {
|
|
612
|
+
e.Ae = n;
|
|
613
|
+
e.u |= CONFIG_HELD;
|
|
614
|
+
GlobalQueue.In?.(e, n);
|
|
615
|
+
schedule();
|
|
616
|
+
return n;
|
|
617
|
+
}
|
|
618
|
+
supersede(e, n, !e.tn || !e.tn(e.m.Z, n));
|
|
619
|
+
} else {
|
|
620
|
+
const t = txOf(e);
|
|
621
|
+
if (e.tn && e.tn(laneValueOf(e), n)) return n;
|
|
622
|
+
if (t.Tt) e.Ae = n; else e.m.Z = n;
|
|
623
|
+
if (e.re !== undefined) e.Ne = clock;
|
|
624
|
+
insertSubs(e);
|
|
625
|
+
laneDirty(e, t);
|
|
626
|
+
}
|
|
627
|
+
schedule();
|
|
628
|
+
return n;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/** A written guess's own pass finished: its source recomputed it — the
|
|
632
|
+
* truth (A18: "the source is whatever recomputes the node"), authoritative
|
|
633
|
+
* or the lane's own derivation (a guess over `config().courier` under a
|
|
634
|
+
* country guess: the lane's config landing confirms or corrects it). An
|
|
635
|
+
* errored pass stages nothing. Provenance (A18, #3331): "the source" is the
|
|
636
|
+
* guess's own question or a newer one; an older action's answer landing
|
|
637
|
+
* over a newer guess (the two entangled when the newer guess was written)
|
|
638
|
+
* is stale — a slow source leaking back in over the user's latest intent.
|
|
639
|
+
* It is staged beneath the guess, for the commit like any landing, and
|
|
640
|
+
* nothing moves: no downstream re-ask, no pending flip on the guess's
|
|
641
|
+
* readers (`isPending` of the guess itself says the held truth differs,
|
|
642
|
+
* A24). The guess's own question answering supersedes as usual. */ function laneOutcome(e, n, t) {
|
|
643
|
+
if (t) return true;
|
|
644
|
+
if (stale(e, answered(e))) {
|
|
645
|
+
e.Ae = n;
|
|
646
|
+
e.u |= CONFIG_HELD;
|
|
647
|
+
return true;
|
|
648
|
+
}
|
|
649
|
+
supersede(e, n, !e.tn || !e.tn(e.m.Z, n));
|
|
650
|
+
return true;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/** THE provenance test, for a derivation's pass and a write alike: an
|
|
654
|
+
* answer to question `q` landing on a guess is stale when `q` is older
|
|
655
|
+
* than the guess's own; unstamped (0) and mainline are current. */ function stale(e, n) {
|
|
656
|
+
return n !== 0 && n < e.m.Oe;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/** The question a derivation's pass answered: the newest among the stamped
|
|
660
|
+
* sources that changed this round (a flight's landing carries the question
|
|
661
|
+
* that started it); 0 when none is stamped. */ function answered(e) {
|
|
662
|
+
let n = 0;
|
|
663
|
+
for (let t = e._; t !== null; t = t.p) {
|
|
664
|
+
const e = t.I;
|
|
665
|
+
if (e.m !== null && e.m.Oe > n && e.Ne === clock) n = e.m.Oe;
|
|
666
|
+
}
|
|
667
|
+
return n;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
GlobalQueue.Zt = laneRead;
|
|
671
|
+
|
|
672
|
+
GlobalQueue.M = laneStage;
|
|
673
|
+
|
|
674
|
+
GlobalQueue.ft = laneOutcome;
|
|
675
|
+
|
|
676
|
+
GlobalQueue.Qt = laneWrite;
|
|
677
|
+
|
|
678
|
+
/** The lanes alive before this seam's guesses opened theirs (a prefix of
|
|
679
|
+
* `lanes`; nothing dissolves one between here and the seam loop): a lane
|
|
680
|
+
* born at the seam has no work to judge yet (its passes run next round) —
|
|
681
|
+
* it is neither shown nor blocked until it has. */ let judged = 0;
|
|
682
|
+
|
|
683
|
+
GlobalQueue.cn = e => {
|
|
684
|
+
judged = lanes.length;
|
|
685
|
+
if (pendingGuesses.length !== 0) applyGuesses(e);
|
|
686
|
+
};
|
|
687
|
+
|
|
688
|
+
GlobalQueue._n = e => {
|
|
689
|
+
// Passes that read a write the parked frame holds as the screen
|
|
690
|
+
// (`stagedReaders`: lane work, a verdict reader before the verdict): they
|
|
691
|
+
// re-derive on the committed world next round (and register as stale
|
|
692
|
+
// readers of the transaction there); a lane's runs wait that round — a
|
|
693
|
+
// lane sees the screen plus its own guesses.
|
|
694
|
+
const n = [];
|
|
695
|
+
if (e !== null) for (let t = 0; t < e.length; t++) {
|
|
696
|
+
const s = e[t];
|
|
697
|
+
const l = s.m?._t;
|
|
698
|
+
// A verdict reader a later read of the same pass routed into a verdict
|
|
699
|
+
// lane answered for itself: it re-derives at the holder's landing, not
|
|
700
|
+
// now (one run — #3322, #3540). Other verdict-lane work re-derives only
|
|
701
|
+
// if the frame stays parked: a transaction landing at this seam makes
|
|
702
|
+
// what it read the screen (one run).
|
|
703
|
+
if (s.R & REACTIVE_DISPOSED || l != null && l._parent?.rt === l && (s.u & CONFIG_VERDICT ? !(s.R & REACTIVE_PROBE_UNANSWERED) : !blocked(l._parent))) continue;
|
|
704
|
+
enqueueSub(s);
|
|
705
|
+
if (l != null && l.Z && n.indexOf(l) === -1) n.push(l);
|
|
706
|
+
}
|
|
707
|
+
for (let e = Math.min(judged, lanes.length) - 1; e >= 0; e--) laneSeam(lanes[e], n.indexOf(lanes[e]) !== -1);
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
GlobalQueue.Gn = () => lanes.length !== 0 && laneCorrections();
|
|
711
|
+
|
|
712
|
+
GlobalQueue.On = endLanes;
|
|
713
|
+
|
|
714
|
+
GlobalQueue.Je = e => {
|
|
715
|
+
const n = [];
|
|
716
|
+
for (let t = 0; t < lanes.length; t++) {
|
|
717
|
+
const s = lanes[t];
|
|
718
|
+
if (resolveTx(s._parent) !== e) continue;
|
|
719
|
+
for (let e = 0; e < s.nn.length; e++) if (s.nn[e].u & CONFIG_GUESS && s.nn[e].m._t === s) n.push(s.nn[e]);
|
|
720
|
+
}
|
|
721
|
+
return n;
|
|
722
|
+
};
|
|
723
|
+
|
|
724
|
+
GlobalQueue.Tn = lanesBlocked;
|
|
725
|
+
|
|
726
|
+
GlobalQueue.ne = verdictLane;
|
|
727
|
+
|
|
728
|
+
export { display, enterLane, guessedValueOf, laneRead, laneStage, laneValueOf, optimisticWrite, pendingGuessOf, supersede, verdictLane };
|