@abide/abide 0.123.2 → 0.124.0

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 (150) hide show
  1. package/ABIDE.md +8 -5
  2. package/CHANGELOG.md +58 -0
  3. package/bin/abide.ts +36 -65
  4. package/docs/REGISTRY.md +45 -12
  5. package/docs/RULEBOOK.md +24 -14
  6. package/docs/abide.md +999 -459
  7. package/package.json +1 -1
  8. package/src/compiler/ARRAY_MUTATORS.ts +20 -0
  9. package/src/compiler/Diagnostics.ts +198 -0
  10. package/src/compiler/KeptChecker.ts +97 -0
  11. package/src/compiler/LoweredFile.ts +609 -0
  12. package/src/compiler/Lowering.ts +18 -1
  13. package/src/compiler/PositionedRefusal.ts +1 -1
  14. package/src/compiler/SHARED_NAMES.ts +2 -0
  15. package/src/compiler/ShadowHost.ts +670 -0
  16. package/src/compiler/ShadowMap.ts +1 -1
  17. package/src/compiler/TypeSession.ts +76 -1743
  18. package/src/compiler/appLayout.ts +28 -20
  19. package/src/compiler/appLints.ts +109 -0
  20. package/src/compiler/argsDefaultsIn.ts +1 -1
  21. package/src/compiler/checkApp.ts +64 -68
  22. package/src/compiler/checkedShadow.ts +2 -2
  23. package/src/compiler/classifyRead.ts +16 -1
  24. package/src/compiler/compileApp.ts +102 -71
  25. package/src/compiler/declaredExports.ts +46 -21
  26. package/src/compiler/diagnoseSources.ts +232 -0
  27. package/src/compiler/emitClient.ts +1 -1
  28. package/src/compiler/formatAbide.ts +7 -8
  29. package/src/compiler/handlersUnder.ts +32 -63
  30. package/src/compiler/lineOf.ts +0 -19
  31. package/src/compiler/matchersOf.ts +3 -3
  32. package/src/compiler/mountsOf.ts +3 -3
  33. package/src/compiler/reactiveReads.ts +235 -0
  34. package/src/compiler/reactiveTypes.ts +13 -0
  35. package/src/compiler/readSources.ts +16 -18
  36. package/src/compiler/readsIn.ts +181 -82
  37. package/src/compiler/routesDeclaration.ts +46 -0
  38. package/src/compiler/scaffold.ts +7 -2
  39. package/src/compiler/serveLanguage.ts +46 -74
  40. package/src/compiler/sharedModuleWrites.ts +1 -1
  41. package/src/compiler/splitImports.ts +2 -2
  42. package/src/compiler/templateWarnings.ts +1 -2
  43. package/src/compiler/trackingWarnings.ts +1 -1
  44. package/src/server/CLIENT_BUILD.ts +4 -32
  45. package/src/server/DesktopSession.ts +213 -0
  46. package/src/server/Followers.ts +399 -0
  47. package/src/server/MODULE_QUERIES.ts +6 -2
  48. package/src/server/PageRender.ts +201 -0
  49. package/src/server/RESUME_MILLISECONDS.ts +2 -0
  50. package/src/server/abideModules.ts +7 -7
  51. package/src/server/answerFailure.ts +3 -2
  52. package/src/server/answerRequest.ts +16 -369
  53. package/src/server/answerRpc.ts +48 -302
  54. package/src/server/answerSocket.ts +41 -490
  55. package/src/server/appBuild.ts +377 -0
  56. package/src/server/appKit.ts +1 -1
  57. package/src/server/appPlugins.ts +15 -17
  58. package/src/server/appTree.ts +6 -5
  59. package/src/server/argsContract.ts +209 -0
  60. package/src/server/bridgeRelay.ts +153 -65
  61. package/src/server/claudeCode.ts +30 -127
  62. package/src/server/config.ts +6 -7
  63. package/src/server/createApp.ts +38 -66
  64. package/src/server/csp.ts +1 -1
  65. package/src/server/deferredBuilds.ts +3 -16
  66. package/src/server/devWorker.ts +11 -15
  67. package/src/server/faceOf.ts +1 -1
  68. package/src/server/generatedSurfaces.ts +2 -1
  69. package/src/server/handlerFileMount.ts +40 -0
  70. package/src/server/index.ts +3 -3
  71. package/src/server/installServer.ts +5 -9
  72. package/src/server/invokeHandler.ts +230 -0
  73. package/src/server/mountHandlers.ts +184 -0
  74. package/src/server/openDesktopWindow.ts +308 -0
  75. package/src/server/packageDirectory.ts +14 -0
  76. package/src/server/preload.ts +21 -2
  77. package/src/server/principal.ts +5 -4
  78. package/src/server/remote.ts +2 -2
  79. package/src/server/render.ts +31 -59
  80. package/src/server/requestScope.ts +5 -36
  81. package/src/server/runCompiled.ts +1 -1
  82. package/src/server/runDesktop.ts +20 -448
  83. package/src/server/seedBuffer.ts +12 -12
  84. package/src/server/serveDev.ts +24 -58
  85. package/src/server/servedApp.ts +390 -0
  86. package/src/server/shell.ts +1 -1
  87. package/src/server/signInChanged.ts +20 -0
  88. package/src/server/surfaceOf.ts +3 -2
  89. package/src/server/versionOf.ts +7 -16
  90. package/src/shared/RPC_SERVER.ts +27 -31
  91. package/src/shared/Schema.ts +1 -2
  92. package/src/shared/applyPatch.ts +1 -1
  93. package/src/shared/index.ts +1 -1
  94. package/src/shared/{note.ts → issueReport.ts} +22 -0
  95. package/src/shared/loadCall.ts +66 -0
  96. package/src/shared/muxFrames.ts +1 -1
  97. package/src/shared/reactive/Keyed.ts +24 -16
  98. package/src/shared/reactive/Reactive.ts +37 -991
  99. package/src/shared/reactive/argsContract.ts +131 -4
  100. package/src/shared/reactive/byOf.ts +2 -5
  101. package/src/shared/reactive/callLoad.ts +8 -14
  102. package/src/shared/reactive/cellShape.ts +734 -0
  103. package/src/shared/reactive/index.ts +12 -23
  104. package/src/shared/reactive/pairReactive.ts +5 -3
  105. package/src/shared/reactive/patchLog.ts +79 -0
  106. package/src/shared/reactive/patchMarks.ts +34 -0
  107. package/src/shared/reactive/producer.ts +121 -0
  108. package/src/shared/reactive/recordWrites.ts +11 -14
  109. package/src/shared/reactive/scoped.ts +3 -2
  110. package/src/shared/reactive/selections.ts +209 -0
  111. package/src/shared/reactive/share.ts +4 -3
  112. package/src/shared/reactive/watch.ts +3 -4
  113. package/src/shared/rpc.ts +20 -24
  114. package/src/shared/validateJson.ts +1 -2
  115. package/src/shared/writePath.ts +29 -0
  116. package/src/ui/ArmRegion.ts +10 -4
  117. package/src/ui/Level.ts +11 -20
  118. package/src/ui/LevelChain.ts +272 -0
  119. package/src/ui/Router.ts +106 -313
  120. package/src/ui/Scope.ts +17 -3
  121. package/src/ui/TryRegion.ts +22 -23
  122. package/src/ui/bindSpread.ts +2 -4
  123. package/src/ui/listenForRoutes.ts +3 -10
  124. package/src/ui/outboxQueue.ts +23 -11
  125. package/src/ui/outcomeOf.ts +120 -0
  126. package/src/ui/reconcile.ts +4 -6
  127. package/src/ui/routing.ts +2 -1
  128. package/src/ui/rows.ts +2 -2
  129. package/src/ui/setAttribute.ts +12 -3
  130. package/src/ui/socketWire.ts +28 -13
  131. package/src/ui/wire.ts +9 -10
  132. package/src/compiler/Finding.ts +0 -2
  133. package/src/compiler/Refusals.ts +0 -65
  134. package/src/compiler/formatDiagnosis.ts +0 -20
  135. package/src/server/appDirectories.ts +0 -9
  136. package/src/server/argsFor.ts +0 -39
  137. package/src/server/buildDirectory.ts +0 -10
  138. package/src/server/coerceArgs.ts +0 -109
  139. package/src/server/derivedArgs.ts +0 -26
  140. package/src/server/runBuild.ts +0 -24
  141. package/src/server/serveBuild.ts +0 -144
  142. package/src/server/testBuild.ts +0 -220
  143. package/src/shared/LOAD_OFFLINE.ts +0 -15
  144. package/src/shared/LOAD_SIGNAL.ts +0 -10
  145. package/src/shared/issuesOf.ts +0 -18
  146. package/src/shared/reactive/ENTRY_LIVES.ts +0 -7
  147. package/src/shared/reactive/FOLLOWED.ts +0 -8
  148. package/src/shared/reactive/PATCHES.ts +0 -11
  149. package/src/shared/reactive/PATCH_SINKS.ts +0 -26
  150. package/src/shared/reactive/canonicalKey.ts +0 -95
@@ -8,7 +8,7 @@
8
8
  // holds one per row — and copying the shared ones onto each instance instead was 87% of
9
9
  // what a value cost to construct. See `MEMBER_PROTOTYPE`.
10
10
  //
11
- // Every field `Cell` declares is written in its constructor, in one order, `undefined`
11
+ // Every field `Cell` (`cellShape.ts`) declares is written in its constructor, in one order, `undefined`
12
12
  // included — a shape that grows a field on a later path is two hidden classes and every
13
13
  // read downstream of it deoptimizes.
14
14
 
@@ -19,19 +19,38 @@ import { type Found, runSchema, type Schema } from '../Schema.ts'
19
19
  import { UNEXPECTED } from '../UNEXPECTED.ts'
20
20
  import { WORK } from '../WORK.ts'
21
21
  import { CELL } from './CELL.ts'
22
+ import {
23
+ type Adoption,
24
+ type Callable,
25
+ type Cap,
26
+ Cell,
27
+ EMPTY_RING,
28
+ newStream,
29
+ OWES_ABOVE,
30
+ OWES_NOTHING,
31
+ OWES_RELOAD,
32
+ type Persisted,
33
+ simpleShape,
34
+ type Stream,
35
+ } from './cellShape.ts'
22
36
  import { CAUGHT_UP, Cursor, hasCursorBehind, keepPlaces } from './Cursor.ts'
23
- import { ENTRY_LIVES } from './ENTRY_LIVES.ts'
24
- import { armTimer, type Expiry, expiryFor } from './Expiry.ts'
25
- import { FOLLOWED } from './FOLLOWED.ts'
37
+ import { armTimer, type Expiry } from './Expiry.ts'
26
38
  import { isReactive } from './isReactive.ts'
27
39
  import { isThenable } from './isThenable.ts'
28
- import { MUTATION } from './MUTATION.ts'
29
40
  import { NO_INITIAL } from './NO_INITIAL.ts'
30
41
  import { NotLanded } from './NotLanded.ts'
31
- import { PATCH_SINKS, type PatchOp } from './PATCH_SINKS.ts'
42
+ import { logOf, PatchLog, type PatchOp, sendInvalidate } from './patchLog.ts'
32
43
  import { REACTIVE_BRAND } from './REACTIVE_BRAND.ts'
33
44
  import { recordWrites } from './recordWrites.ts'
34
- import { currentScope, runInScope, type Scope } from './scoping.ts'
45
+ import { runInScope } from './scoping.ts'
46
+ import {
47
+ EVERY_PRODUCER,
48
+ fileProducer,
49
+ inReach,
50
+ markSignals,
51
+ tagCell,
52
+ trackSignal,
53
+ } from './selections.ts'
35
54
  import { STREAMING } from './STREAMING.ts'
36
55
  import {
37
56
  CHECK,
@@ -40,7 +59,6 @@ import {
40
59
  DIRTY,
41
60
  dropProbeReader,
42
61
  newSubscriber,
43
- newTracked,
44
62
  RELEASING,
45
63
  revive,
46
64
  type Subscriber,
@@ -271,228 +289,13 @@ export type Reactive<
271
289
  finally(onSettled: () => void): Promise<Stored>
272
290
  }
273
291
 
274
- /** The standing adoption: what is adopted, and the way to stop mirroring it. */
275
- type Adoption = { source: Cell; stop: () => void }
276
-
277
- /**
278
- * The window a `throttle` or a `debounce` holds open, allocated only where one is declared.
279
- *
280
- * THE WINDOW A `throttle` OR A `debounce` HOLDS OPEN (RULEBOOK 5.8). One field on the
281
- * cell rather than one per window field, allocated only where a value declared one — the
282
- * shape `adoption` already uses, and for the same reason.
283
- *
284
- * WHAT A WINDOW CAPS IS THE WAKE, NEVER THE PRODUCTION (5.9). Every write still mints and
285
- * the ordinal moves. What waits is the value a READER sees and the cascade that tells it so,
286
- * which is the whole of 5.8's "how often a value changes for a reader".
287
- *
288
- * WHAT IT COSTS EVERY VALUE THAT NEVER CAPS: one field load and one branch on the write
289
- * path, plus `serve` as a frame rather than five stores inline. Measured at 0.99x -> 1.08x
290
- * against the hand-written arm on the since-removed `publish into a capped ring` case, consistent across three
291
- * runs over a 0.7% floor — about 1.3 ns on a 14.7 ns op. Moving the comparison target
292
- * behind the gate did not recover it, so it is the frame and the branch rather than a
293
- * wasted load. Inlining `serve` into the uncapped arm would buy it back for a second copy
294
- * of the reader-visible transition, and this file has already paid for one of those: the
295
- * trade is stated rather than taken, 1.3 ns being nowhere near perception.
296
- */
297
- type Cap = {
298
- /**
299
- * True for a throttle, which lets the leading change through; false for a debounce.
300
- *
301
- * 5.12 against 5.13, and the only difference between the two mechanisms: a throttle
302
- * lets the leading change through and holds what follows, a debounce holds everything
303
- * until the changes stop.
304
- */
305
- leading: boolean
306
- ms: number
307
- timer: ReturnType<typeof setTimeout> | null
308
- /**
309
- * The production the window is holding back, while `holding` is set.
310
- *
311
- * The production the window is holding back. `holding` is a field rather than a test
312
- * against `held`, because `undefined` is a value an app can write and so cannot carry
313
- * the absence.
314
- */
315
- held: unknown
316
- holding: boolean
317
- /**
318
- * The last production minted, which the identity gate compares against.
319
- *
320
- * WHAT THE IDENTITY GATE COMPARES AGAINST. On every uncapped value that is `cell.value`
321
- * and the two are one thing; a window moves the last production MINTED apart from the
322
- * last one RELEASED, and comparing against the released one would collapse a production
323
- * 5.9 forbids dropping — A, B, A inside one window is three productions, and only the
324
- * third's own predecessor makes it a repeat.
325
- */
326
- minted: unknown
327
- /**
328
- * Whether the window is holding back a body run.
329
- *
330
- * A BODY RUN THE WINDOW IS HOLDING BACK (5.11), against `holding`'s production. The two
331
- * are separate flags because they can stand together: a stream has a body AND tells its
332
- * chunks through the window (5.17), so one close can owe a run and a telling at once.
333
- */
334
- owed: boolean
335
- /**
336
- * Whether the window is holding back a refresh, started when it closes.
337
- *
338
- * 5.24 — A RELOAD THE WINDOW IS HOLDING BACK: a refresh made inside it, started when it closes.
339
- * Started there rather than owed like a run, because 7.11 reloads whether or not anything reads
340
- * and an owed run waits for a read to pull it.
341
- */
342
- reloading: boolean
343
- }
344
-
345
- /**
346
- * A value's store and the state of its writes, allocated only where a `store` was declared.
347
- *
348
- * A VALUE'S STORE AND WHAT ITS WRITES ARE DOING, allocated only where a `store` was declared.
349
- *
350
- * 8.10: ONE WRITE IN FLIGHT AND ONE PENDING. A production arriving while a write is out replaces
351
- * the pending value rather than queueing behind it: a slow store handed every intermediate is doing
352
- * work nobody can observe, and a queue is how it grows without bound behind a fast writer.
353
- */
354
- type Persisted = {
355
- store: Store<unknown>
356
- /** The value's own `ttl`, taken once, and infinity where it declares none (8.13). */
357
- ttl: number
358
- /**
359
- * Set while a restore mints its production, so what was just read is not written back (8.8).
360
- */
361
- restoring: boolean
362
- writing: boolean
363
- pending: boolean
364
- /**
365
- * The newest value handed to the store and not yet confirmed.
366
- *
367
- * THE NEWEST VALUE THE APP HAS HANDED THE STORE, standing until the store confirms it. It is
368
- * what `pending` sends next, and what 8.18 serves a re-read in place of calling `get`.
369
- */
370
- unconfirmed: unknown
371
- /** What stops the store's `watch`, where it has one (8.21). */
372
- unwatch: (() => void) | null
373
- }
374
-
375
- /**
376
- * A streaming producer's own state; `null` on every value whose body is not an async generator.
377
- *
378
- * A STREAMING PRODUCER'S OWN STATE (9.1, 9.2, 9.6), and `null` on every value whose body is
379
- * not an async generator — the shape `cap` and `adoption` already use.
380
- *
381
- * THE ACCUMULATION IS PUSHED INTO AND MATERIALIZED ON THE READ. A chunk is one push and one
382
- * cascade; the copy a reader is handed is taken by the read that follows, so a hundred
383
- * chunks between two reads are one copy rather than a hundred (9.2). The copy is FRESH per
384
- * chunk count and has to be: a reader holding an earlier snapshot still holds what it read,
385
- * and a value derived from this one compares by reference — the live buffer handed out would
386
- * be collapsed at every derived identity gate after the first chunk.
387
- *
388
- * WHAT THAT COSTS WHERE A READ FOLLOWS EVERY CHUNK is a copy of the accumulation per read,
389
- * and a reader woken per chunk made that a copy per chunk: twenty thousand chunks landing in
390
- * one task took 61 ms against 1.9 ms for the hand-written arm. 9.9 is what bounds it — the
391
- * wake is held to one per task, which is the unit a browser paints between, so the reads it
392
- * drops were never visible. A reader that reads per chunk on its own, unwoken, is still a
393
- * copy per read.
394
- */
395
- type Stream = {
396
- /**
397
- * The accumulation of the run being served — and the same array as `ring`, so a cursor
398
- * walks the chunks this holds rather than a second copy of them.
399
- */
400
- chunks: unknown[]
401
- /** The accumulation's version: moves on every release, patch and new run. */
402
- version: number
403
- /**
404
- * Which accumulation `value` stands for, as a `version` rather than a chunk count.
405
- *
406
- * A version rather than a chunk count because a patch changes the accumulation without
407
- * changing its length (9.13), and a write stands at the version it was made at until the
408
- * accumulation moves past it (9.11). -1 where nothing has been materialized.
409
- */
410
- materializedAt: number
411
- /**
412
- * Whether `value` is a write rather than a materialization.
413
- *
414
- * WHETHER `value` IS A WRITE rather than a materialization, while `materializedAt` stands. A value
415
- * forwarding this stream serves the write the way it would have served a production (11.59).
416
- */
417
- written: boolean
418
- /**
419
- * How many chunks a reader has been told of.
420
- *
421
- * HOW MANY CHUNKS A READER HAS BEEN TOLD OF. Every chunk as it lands, without a cap; with one,
422
- * only what the window has released (5.18) — the rest are in `chunks` for a cursor (5.10) and
423
- * out of what a read materializes until the release.
424
- */
425
- visible: number
426
- /** The run in flight, told to return when a newer run supersedes it. */
427
- iterator: AsyncIterator<unknown> | null
428
- /**
429
- * Which run is current; only a new run moves it.
430
- *
431
- * WHICH RUN IS CURRENT, and only a new run moves it. Apart from `generation`, which every
432
- * write moves so that a load it overtook lands nowhere — a write over a stream stands beside
433
- * the stream (9.11) rather than superseding it, and sharing the counter stopped the stream.
434
- */
435
- run: number
436
- /**
437
- * Whether a wake is already held for this task, so the next chunk only pushes.
438
- *
439
- * 9.9: chunks have landed that the readers have not been told about, and the value is
440
- * already in `WAKING` — so the next chunk in this task pushes and does nothing else.
441
- */
442
- waking: boolean
443
- /**
444
- * A probe moved under the held wake — the first chunk making the value ready, or one
445
- * clearing a standing error — and the wake owes it to the guards as well.
446
- */
447
- probesOwed: boolean
448
- /**
449
- * The stream this one forwards, and `null` on a value that produces its own.
450
- *
451
- * THE STREAM THIS ONE FORWARDS (11.15), and `null` on a value that produces its own. A
452
- * value adopting a stream IS that stream to a cursor, a guard and an await, so it holds
453
- * the adopted value's buffer and ring rather than copies — and this is what stops a
454
- * trigger on it starting its body as though the body were the generator.
455
- */
456
- source: Cell | null
457
- /**
458
- * How far the forwarding value's ordinals run ahead of the adopted value's, fixed when
459
- * the forwarding begins so the adopter's cursor positions go on from its own.
460
- */
461
- ordinalOffset: number
462
- /**
463
- * Whether what is served is a run that closed.
464
- *
465
- * WHETHER WHAT IS SERVED IS A RUN THAT CLOSED, which is the only accumulation a deadline
466
- * reaches (6.10). A run in flight has minted nothing, so `expiry.at` says nothing about it —
467
- * without this the standing arm reads `at` as 0 and drops the value on its first read.
468
- */
469
- closed: boolean
470
- }
471
-
472
- function newStream(source: Cell | null): Stream {
473
- return {
474
- chunks: EMPTY_RING,
475
- version: 0,
476
- visible: 0,
477
- materializedAt: -1,
478
- written: false,
479
- iterator: null,
480
- run: 0,
481
- waking: false,
482
- probesOwed: false,
483
- source,
484
- ordinalOffset: 0,
485
- closed: false,
486
- }
487
- }
488
-
489
292
  /**
490
293
  * The stream `cell` produces itself, or `null`: it has none, or the one it has is forwarded (11.15).
491
294
  *
492
295
  * THE ONE DISCRIMINATOR between following and forwarding. An own stream's `adoption` is a write it
493
296
  * follows (9.11), and a forwarding value's is the stream it forwards.
494
297
  */
495
- function ownStream(cell: Cell): Stream | null {
298
+ export function ownStream(cell: Cell): Stream | null {
496
299
  const stream = cell.stream
497
300
  return stream !== null && stream.source === null ? stream : null
498
301
  }
@@ -551,480 +354,6 @@ export function isStreamBody(body: (args: never) => unknown): boolean {
551
354
  return Object.getPrototypeOf(body) === ASYNC_GENERATOR_FUNCTION
552
355
  }
553
356
 
554
- /**
555
- * A value's internal state record, apart from the callable an app holds.
556
- *
557
- * THE INTERNAL FACE, AND A SECOND OBJECT. With the fields on the callable itself, every
558
- * one was a property added to a FUNCTION at construction, and that was most of what a
559
- * value cost to make: moving them here took `construct a value` from 123 ns to 87 under
560
- * JSC and from 101 to 83 under V8, and a derived value's construction, a chain and a
561
- * layered DAG 7-13% with it. Nothing measured moved the other way. The callable captures
562
- * its record, so a read is one context load — the hand-written arm's one captured
563
- * variable — and a member reaches the record through `CELL`, one load ahead of what it
564
- * did before.
565
- *
566
- * THE FIELD COUNT SITS ON A VM BOUNDARY AND IT IS NOT A LEVER. Both engines give an
567
- * object a fixed inline slot budget and spill the rest to an out-of-line store, and this
568
- * record is over it — so the count moves numbers that have nothing to do with the work.
569
- * Two independent measurements say the same thing from opposite ends. Taking `Cell` to
570
- * 38 is worth ~11% of `construct a value` and ~6-9% of the derived case, and it does not
571
- * matter HOW the four go: a consolidation into one record and four fields simply deleted
572
- * buy the same number, so the consolidation is not what pays. Going the other way,
573
- * 42 -> 46, is FREE — above the budget the out-of-line store already exists. And dropping
574
- * ONE field moved chain 20 and both layered DAGs +4.2% under V8 while moving nothing
575
- * under JSC; adding a DEAD boolean back put all three within 0.6%, which is the proof it
576
- * was layout and not work — that same dead boolean then cost the probe walk 6-7%.
577
- *
578
- * Above the budget is not free under JSC, though: three fields more (the dead-reader
579
- * counts and `probeCursor`) moved `construct a value` and the derived case +6-8% there,
580
- * and three UNUSED fields on the old record moved them the same — layout, not work.
581
- *
582
- * So the boundary is worth KNOWING and not worth engineering around. A field costs a few
583
- * ns of construction; getting under costs a structural change that the next field added here
584
- * silently undoes, and it re-rolls in a different direction for every row. If
585
- * construction ever needs that 11%, shed fields — do not build machinery to shed them.
586
- * And when a V8-only move of this size shows up on a graph row, the first thing to check
587
- * is whether the field count changed.
588
- */
589
- class Cell {
590
- /**
591
- * Who reads this value, on the value edge.
592
- *
593
- * ARRAYS, not sets. The mark walk walks this per write and a set's iterator
594
- * allocates. A disposed reader is left in place and counted rather than found — see
595
- * `dropFrom` in `tracking.ts` — so a walk over this skips `!alive`.
596
- */
597
- declare readers: Subscriber[]
598
- declare deadReaders: number
599
- /**
600
- * Who asked about this value's PROBES — a different edge from `readers`, and see
601
- * `markProbes` for what that buys.
602
- */
603
- declare probeReaders: Subscriber[]
604
- declare deadProbeReaders: number
605
- declare sources: Cell[]
606
- /**
607
- * The values whose PROBES this body asked about — a `Cell` is a `Subscriber`, so it
608
- * carries the reader half of the probe edge as well as the source half.
609
- */
610
- declare probeSources: Cell[]
611
- declare probeCursor: number
612
- declare cursor: number
613
- /** See `Subscriber.seen`. */
614
- declare seen: Set<Cell> | null
615
- declare seenThrough: number
616
- declare scanningFrom: number
617
- declare label: string
618
- declare body: ((args: unknown) => unknown) | null
619
- declare args: unknown
620
- declare value: unknown
621
- declare landed: boolean
622
- /**
623
- * Whether a read may answer with `value`.
624
- *
625
- * WHETHER A READ MAY ANSWER WITH `value`. Implies `landed`, and is false over a landed value
626
- * a trigger, an abort or an adoption has stopped serving — which is the state `landed`
627
- * alone cannot say.
628
- */
629
- declare servable: boolean
630
- /**
631
- * Whether a read can return `value` straight, without going a frame in.
632
- *
633
- * `state === CLEAN && servable` — the whole of "this read can return the field",
634
- * maintained rather than recomputed. A read is the hottest path in the design and it
635
- * was three loads and three branches to decide.
636
- *
637
- * THE INVARIANT IS ONE-DIRECTIONAL and that is what makes it safe to maintain by
638
- * hand: `true` is written only where all three are known to hold, and every
639
- * transition that can break one of them writes `false`. So a site that forgets to
640
- * set it true costs a frame on the reads that follow and cannot serve a wrong value,
641
- * which is the opposite of how a maintained flag usually fails.
642
- */
643
- declare direct: boolean
644
- declare loading: boolean
645
- declare failure: unknown
646
- /**
647
- * The compiled `identity` comparator.
648
- *
649
- * `null` IS the default — see `comparatorFor`.
650
- */
651
- declare identityFn: ((next: unknown, previous: unknown) => boolean) | null
652
- /**
653
- * The comparator this value DECLARED, which `identityFn` returns to when an adoption ends.
654
- *
655
- * 11.17 inherits the adopted value's `identity` only where the outer declared none, and only
656
- * for as long as it adopts: kept on `identityFn` alone, the inherited comparator outlived the
657
- * adoption and gated the outer's own productions — `flag() ? inner : count()` with `inner`
658
- * keyed on `.id` read every number as the same `undefined` and never woke again.
659
- */
660
- declare declaredIdentityFn:
661
- ((next: unknown, previous: unknown) => boolean) | null
662
- declare transform: ((value: unknown) => unknown) | null
663
- /**
664
- * `null` on every value that declares no `schema`, which keeps the gate off the write
665
- * path of everything that did not ask for one.
666
- */
667
- declare schema: Schema<unknown> | null
668
- /**
669
- * A streaming producer's chunk buffer, for a cursor to walk (2.6); `EMPTY_RING` on every
670
- * other value.
671
- */
672
- declare ring: unknown[]
673
- /**
674
- * The ordinal before `ring[0]`, so `ring[index]` carries ordinal `ringBase + index + 1` and a
675
- * cursor finds its place from the ordinal it holds.
676
- */
677
- declare ringBase: number
678
- /**
679
- * `null` on every value that declares no `ttl`, and on every value 6.2 makes it inert
680
- * for. Its presence is also what holds `direct` false — see `serve`.
681
- */
682
- declare expiry: Expiry | null
683
- declare ordinal: number
684
- declare generation: number
685
- declare alive: boolean
686
- declare isEffect: boolean
687
- declare isMirror: boolean
688
- declare adopter: Tracked | null
689
- /**
690
- * The mark: `CLEAN`, `CHECK` or `DIRTY`.
691
- *
692
- * `CLEAN`, `CHECK` or `DIRTY` — see `tracking.ts`. Stamped on every transitive
693
- * reader BEFORE anything runs, so a body that reaches a source which has not caught
694
- * up yet pulls it forward; `running` is what stops a body already on the stack being
695
- * re-entered.
696
- *
697
- * ONE RUN PER NODE PER WRITE is the contract, and the state carries it without a
698
- * cascade counter: a node that has run is `CLEAN`, and only a source PRODUCING can
699
- * mark it again — which a source it already read cannot do, because reading it is
700
- * what resolved it.
701
- */
702
- declare state: number
703
- declare running: boolean
704
- /**
705
- * Whether the last run aborted on a value that had not landed.
706
- *
707
- * 2.13: A RUN THAT ABORTED ON A VALUE THAT HAD NOT LANDED, and is owed the rest of itself
708
- * when that value arrives. Push-pull leaves a marked body for the read that wants it, and
709
- * that is right for a body which RAN — this one did not, so nothing downstream can pull it:
710
- * a reader guarding on `ready()` asks the probe edge and never the value, and the guard would
711
- * answer false for as long as nobody read through it.
712
- */
713
- declare aborted: boolean
714
- /**
715
- * The value this one adopted, or `null`.
716
- *
717
- * WHAT THIS VALUE'S BODY HANDED BACK, where it handed back another `Reactive`
718
- * (11.12). `null` on every value that is not adopting, which is nearly all of them —
719
- * one field rather than two, and the record is allocated only where there is one.
720
- */
721
- declare adoption: Adoption | null
722
- /**
723
- * `null` on every value declaring neither `throttle` nor `debounce`, which is nearly
724
- * all of them.
725
- */
726
- declare cap: Cap | null
727
- /**
728
- * `null` on every value declaring no `tags`, which keeps `markProbes` from looking up a
729
- * selection signal for any of them.
730
- */
731
- declare tags: string[] | null
732
- /** Whether `declare` built this value for a mutation, which a sweep invalidates (13.16). */
733
- declare mutation: boolean
734
- /**
735
- * Whether what is held was written here since the producer last produced (3.10).
736
- *
737
- * Only ever true on a value with a body: a value with no producer has nothing to be out of
738
- * step with (3.12). Moved by `writtenHere` and `producedAgain` alone, each owning its probe move.
739
- */
740
- declare local: boolean
741
- /** `null` on every value declaring no `store`, which is what keeps `serve` from persisting. */
742
- declare store: Persisted | null
743
- /**
744
- * The declared `by`.
745
- *
746
- * 5.22 — held as declared rather than as a function, so the property name is still there to send.
747
- */
748
- declare by: string | ((element: unknown) => unknown) | null
749
- /** The probe pass this cell was last visited in. See `walkBusy` and `walkReady`. */
750
- declare probePass: number
751
- /**
752
- * `OWES_NOTHING`, `OWES_ABOVE` or `OWES_RELOAD` — what an `invalidate` left for the next read
753
- * to do. See `invalidateOne`.
754
- */
755
- declare owes: number
756
- /** The value this record is the state of — what `NotLanded` names as its source. */
757
- declare callable: Reactive<unknown> | null
758
- /** `null` on every value whose body is not an async generator, which is nearly all. */
759
- declare stream: Stream | null
760
- /**
761
- * Whether a read may ever take the field straight, fixed at construction.
762
- *
763
- * WHETHER A READ MAY EVER TAKE THE FIELD STRAIGHT, fixed at construction: no expiry to
764
- * check and no accumulation to materialize. `setDirect` reads this one field where it
765
- * would otherwise read one per mechanism that needs the read to go a frame in.
766
- */
767
- declare plain: boolean
768
- /**
769
- * Whether a settled write goes straight to `produce`, past no gate.
770
- *
771
- * NOTHING STANDS BETWEEN A SETTLED WRITE AND `produce`: no `schema`, no `transform`, and no
772
- * stream whose writes stand apart from its chunks (9.11, 9.12). One field where the write and
773
- * the recompute each tested two, maintained where a forwarded stream comes and goes.
774
- */
775
- declare bareWrite: boolean
776
- /**
777
- * Whether a gated write can take `SIMPLE_PROTOTYPE`'s short path.
778
- *
779
- * EVERYTHING A GATED WRITE WOULD OTHERWISE ASK, IN ONE FIELD: no cap holding the
780
- * production back, no expiry, no store to persist through, no
781
- * declared `identity`, and `bareWrite`'s own three. A value carrying none of them has a
782
- * `produce` -> `serve` -> `cascade` that reduces to three stores and a mark — which is
783
- * what `SIMPLE_PROTOTYPE.set` spells out rather than calls.
784
- *
785
- * IT SELECTS A PROTOTYPE AND IS NOT READ ON THE WRITE PATH. See `SIMPLE_PROTOTYPE`.
786
- *
787
- * MAINTAINED, NOT FIXED: three of the fields under it move after construction —
788
- * `bareWrite` and `plain` where a forwarded stream comes and goes, `identityFn` where an
789
- * adoption takes the inner value's. `simpleShape` is called at each of those.
790
- */
791
- declare simple: boolean
792
- /**
793
- * The scope this value was built in, and so the one its body runs under.
794
- *
795
- * 11.32 — THE SCOPE THIS VALUE WAS BUILT IN, and so the one its body runs under. `undefined` in a
796
- * browser, and on a server for a value built outside any request.
797
- */
798
- declare scope: Scope | undefined
799
- /**
800
- * Whether this value is one for the whole process, in every scope.
801
- *
802
- * 11.34, 13.13 — one value for the process, and so inside every scope a selection is made in. An
803
- * entry of a `global` keyed value is one too, whichever request first reached it.
804
- */
805
- declare global: boolean
806
- /**
807
- * The one weak handle every selection index holds this value by, or `null` where none does.
808
- *
809
- * 13.1 AND 13.6: a value filed for the bare sweep or carrying `tags` is findable by one, and
810
- * every index holds the same handle, so an eviction drops it from all of them at once.
811
- */
812
- declare ref: WeakRef<Cell> | null
813
- /**
814
- * Whether this value is filed for the bare selection — once, where it first becomes a load.
815
- *
816
- * See `fileProducer`. Not cleared by an eviction: dropping `ref` is what takes an evicted entry
817
- * out, and this staying set is what keeps its next load from filing it again.
818
- */
819
- declare filed: boolean
820
- /**
821
- * Whether what this value was built in has stopped — the setup or the request that owned it.
822
- *
823
- * 12.14. Set by `orphan`; the value lets go of its sources once nothing
824
- * reads it (`releaseOrphan`), which may be at once or when the last reader outside its owner leaves.
825
- */
826
- declare orphaned: boolean
827
-
828
- constructor(
829
- label: string,
830
- body: ((args: unknown) => unknown) | null,
831
- args: unknown,
832
- options: ReactiveOptions<unknown, unknown, never> | undefined,
833
- streaming: boolean,
834
- ) {
835
- // Every field, in one order, `undefined` included.
836
- this.readers = []
837
- this.deadReaders = 0
838
- this.probeReaders = []
839
- this.deadProbeReaders = 0
840
- this.sources = []
841
- this.probeSources = []
842
- this.probeCursor = 0
843
- this.cursor = 0
844
- this.seen = null
845
- this.seenThrough = 0
846
- this.scanningFrom = -1
847
- this.label = label
848
- this.body = body
849
- this.args = args
850
- this.value = undefined
851
- this.landed = false
852
- this.servable = false
853
- this.direct = false
854
- this.loading = false
855
- this.failure = undefined
856
- this.identityFn = comparatorFor(
857
- options?.identity as Identity<unknown> | undefined,
858
- )
859
- this.declaredIdentityFn = this.identityFn
860
- this.transform = (options?.transform ?? null) as
861
- ((value: unknown) => unknown) | null
862
- this.schema = (options?.schema ?? null) as Schema<unknown> | null
863
- this.ring = EMPTY_RING
864
- this.ringBase = 0
865
- // 6.2 DECIDED ONCE, here rather than per production: a body is what makes a value a
866
- // producer, and a plain state is the one this must not reach. See `expiryFor`.
867
- this.expiry = expiryFor(
868
- options?.ttl,
869
- // A store is a producer too (8.2): there is somewhere to get the value back from, so
870
- // `ttl` on a value holding one drops rather than being inert.
871
- body !== null || options?.store !== undefined,
872
- )
873
- this.ordinal = 0
874
- this.generation = 0
875
- this.alive = true
876
- this.state = CLEAN
877
- this.running = false
878
- this.aborted = false
879
- this.adoption = null
880
- this.cap = capFor(label, options?.throttle, options?.debounce)
881
- const tags = options?.tags
882
- this.tags =
883
- tags === undefined
884
- ? null
885
- : typeof tags === 'function'
886
- ? tags(args as never)
887
- : tags
888
- this.mutation =
889
- (options as { [MUTATION]?: true } | undefined)?.[MUTATION] === true
890
- this.local = false
891
- const store = options?.store
892
- this.store =
893
- store === undefined
894
- ? null
895
- : {
896
- store: (typeof store === 'function'
897
- ? store(args as never)
898
- : store) as Store<unknown>,
899
- ttl: options?.ttl ?? Number.POSITIVE_INFINITY,
900
- restoring: false,
901
- writing: false,
902
- pending: false,
903
- unconfirmed: undefined,
904
- unwatch: null,
905
- }
906
- this.by = (options?.by ?? null) as
907
- string | ((element: unknown) => unknown) | null
908
- this.probePass = 0
909
- this.owes = OWES_NOTHING
910
- this.isEffect = false
911
- this.isMirror = false
912
- this.adopter = null
913
- this.callable = null
914
- this.stream = streaming ? newStream(null) : null
915
- this.plain = this.expiry === null && this.stream === null
916
- this.bareWrite =
917
- this.schema === null && this.transform === null && !streaming
918
- this.simple = false
919
- this.scope = currentScope()
920
- this.global = options?.global === true
921
- this.ref = null
922
- this.filed = false
923
- this.orphaned = false
924
- simpleShape(this)
925
- }
926
-
927
- notify(): void {
928
- run(this)
929
- }
930
- }
931
-
932
- /** What a member's `this` is, and the one way from the value an app holds to its record. */
933
- type Callable = { [CELL]: Cell }
934
-
935
- /**
936
- * Throws where a value declares both `throttle` and `debounce`.
937
- *
938
- * 5.14 is a BUILD error and there is no build yet, so it lands at construction — the
939
- * earliest moment that exists, and the one the app still has a stack for. Naming the value
940
- * is the clause's own requirement; without it a page declaring both on one of forty values
941
- * says only that something did. One statement for both producers of a window: a value's
942
- * (5.8) and a keyed value's, which caps starts rather than wakes (5.19).
943
- */
944
- export function refuseBothCaps(
945
- label: string,
946
- throttle: number | undefined,
947
- debounce: number | undefined,
948
- ): void {
949
- if (throttle !== undefined && debounce !== undefined)
950
- throw new Error(
951
- `${label} declares both throttle and debounce. A value is capped one way or the other.`,
952
- )
953
- }
954
-
955
- function capFor(
956
- label: string,
957
- throttle: number | undefined,
958
- debounce: number | undefined,
959
- ): Cap | null {
960
- refuseBothCaps(label, throttle, debounce)
961
- const ms = throttle ?? debounce
962
- if (ms === undefined) return null
963
- return {
964
- leading: throttle !== undefined,
965
- ms,
966
- timer: null,
967
- held: undefined,
968
- holding: false,
969
- minted: undefined,
970
- owed: false,
971
- reloading: false,
972
- }
973
- }
974
-
975
- /**
976
- * Compiles `identity` into a comparator, or `null` for the default `Object.is`.
977
- *
978
- * THE DEFAULT IS THE REFERENCE, and `structural` is exported for an app to pass.
979
- *
980
- * THE CASE FOR A STRUCTURAL DEFAULT IS REAL: a reload that fetched an equal
981
- * payload builds a FRESH object, so a reference compare never fires and every reader
982
- * wakes on a value that did not change. What decides it against that is the cost on
983
- * the shape an app actually holds — a compare walks the whole value on EVERY write,
984
- * where the wake it avoids is paid only when the payload really is equal. A grid of
985
- * rows re-assembled per recompute pays the deep walk every time and collapses never.
986
- *
987
- * So the framework takes the cheap, predictable default — `===` is what JavaScript
988
- * means by "the same value" — and the app names `identity: structural` on the values
989
- * where re-materialization is the common case. 5.5's "not equal wherever it cannot
990
- * decide" is unchanged; it is just no longer the default reading.
991
- *
992
- * `identity` is discriminated by ARITY (5.3), once, at construction — not per compare.
993
- *
994
- * NULL IS THE DEFAULT, not a function that implements it. `produce` compares against
995
- * `null` and calls `Object.is` directly, which takes an INDIRECT call off the write path:
996
- * the site is polymorphic across the default, a projection closure and whatever an app
997
- * passed, so it is not one an engine can speculate through. The saving is the indirection
998
- * rather than the comparison — `Object.is` is itself the fastest spelling of it.
999
- */
1000
- function comparatorFor(
1001
- identity: Identity<unknown> | undefined,
1002
- ): ((next: unknown, previous: unknown) => boolean) | null {
1003
- if (identity === undefined) return null
1004
- if (identity.length >= 2)
1005
- return identity as (next: unknown, previous: unknown) => boolean
1006
- const project = identity as (value: unknown) => unknown
1007
- return (next, previous) => project(next) === project(previous)
1008
- }
1009
-
1010
- /**
1011
- * Recomputes `simple` and re-seats the callable on the matching prototype.
1012
- *
1013
- * `simple` IN ONE PLACE. A second copy of this conjunction is the drift that would let one of the
1014
- * sites go on reading `true` after the field under it moved — and what the short write would then
1015
- * skip is a cap, a ring or a declared `identity`, silently. The prototype that goes with it is
1016
- * `seat`'s, taken where the transition that moved a field under it ends.
1017
- */
1018
- function simpleShape(cell: Cell): void {
1019
- cell.simple =
1020
- cell.bareWrite &&
1021
- // `plain` carries `expiry === null` and `stream === null` already.
1022
- cell.plain &&
1023
- cell.cap === null &&
1024
- cell.store === null &&
1025
- cell.identityFn === null
1026
- }
1027
-
1028
357
  /**
1029
358
  * The prototype a value's state calls for: its own stream's writes (9.11), an adoption's (11.59),
1030
359
  * the short write of a `simple` value, or the members alone.
@@ -1340,7 +669,7 @@ function markProbes(cell: Cell, pass: number): void {
1340
669
  markAsked(cell.probeReaders)
1341
670
  // 13.3: a guard over a tag selection asked the SELECTION, so it hears through the selection's
1342
671
  // signal rather than through this value's own probe readers.
1343
- if (cell.tags !== null) markSignals(cell.tags)
672
+ if (cell.tags !== null) markSignals(cell.tags, markAsked)
1344
673
  // The bare selection's guard hears every filed value's floor move; one load where nothing asks.
1345
674
  if (EVERY_PRODUCER.probeReaders.length !== 0 && cell.filed)
1346
675
  markAsked(EVERY_PRODUCER.probeReaders)
@@ -2457,6 +1786,12 @@ function run(cell: Cell): void {
2457
1786
  absorb(cell, produced, true)
2458
1787
  }
2459
1788
 
1789
+ // A CELL'S WAKE IS ITS RUN — on the prototype, where the class method stood, so `reader.notify()`
1790
+ // reaches it the way it always did; `cellShape.ts` cannot import `run` and stay off the cycle.
1791
+ Cell.prototype.notify = function notify(this: Cell): void {
1792
+ run(this)
1793
+ }
1794
+
2460
1795
  /**
2461
1796
  * Leaves a run that read a value which had not landed owing the rest of itself (2.13).
2462
1797
  *
@@ -3101,13 +2436,6 @@ function readIndirect(cell: Cell): unknown {
3101
2436
  return cell.value
3102
2437
  }
3103
2438
 
3104
- /**
3105
- * Every value that is not streaming shares this as its `ring`. The field stays monomorphically an
3106
- * Array — CLAUDE.md's shape rule — and only a stream's own chunk buffer is ever pushed to. Frozen so
3107
- * that if anything ever does push here, it says so rather than corrupting every other value at once.
3108
- */
3109
- const EMPTY_RING = Object.freeze([]) as unknown as unknown[]
3110
-
3111
2439
  /**
3112
2440
  * The current probe pass, stamped on each cell a probe walk visits.
3113
2441
  *
@@ -3410,11 +2738,6 @@ export function refuseInto(value: Reactive<unknown>, failure: unknown): void {
3410
2738
  refused((value as unknown as Callable)[CELL], failure)
3411
2739
  }
3412
2740
 
3413
- /** Whether `value` holds what was written here, without subscribing — for a caller that is not a reader. */
3414
- export function writtenLocally(value: Reactive<unknown>): boolean {
3415
- return (value as unknown as Callable)[CELL].local
3416
- }
3417
-
3418
2741
  /**
3419
2742
  * A promise of the value once it is servable and not busy, or of its failure.
3420
2743
  *
@@ -3522,7 +2845,7 @@ function patchCell(cell: Cell, mutate: (value: unknown) => void): void {
3522
2845
  // served: patching the served one overwrote the held production with it, and the write
3523
2846
  // the window held was never seen.
3524
2847
  const head = cap?.holding && cell.body === null ? cap.held : cell.value
3525
- recordWrites(head, mutate, PATCH_SINKS.get(cell))
2848
+ recordWrites(head, mutate, logOf(cell))
3526
2849
  // 5.7: REPLACES THE HEAD PRODUCTION RATHER THAN APPENDING ONE, so the ordinal does not
3527
2850
  // move: the follow's version tells a patch from a production by exactly that, and sends a
3528
2851
  // patch as its writes (18.11). A cursor reads the change off the object's patch epoch
@@ -3542,10 +2865,8 @@ function patchCell(cell: Cell, mutate: (value: unknown) => void): void {
3542
2865
  const before = stream.chunks.length
3543
2866
  // A CURSOR BEHIND needs where the patch wrote, which its ops say: the follow's own sink, or one
3544
2867
  // of this patch's alone where nothing follows the value.
3545
- const followed = PATCH_SINKS.get(cell)
3546
2868
  const sink =
3547
- followed ??
3548
- (hasCursorBehind(cell) ? { ops: [], lost: false } : undefined)
2869
+ logOf(cell) ?? (hasCursorBehind(cell) ? new PatchLog() : undefined)
3549
2870
  const from = sink === undefined ? 0 : sink.ops.length
3550
2871
  recordWrites(stream.chunks, mutate, sink)
3551
2872
  // 5.7 AS THE VALUE BRANCH KEEPS IT: a patch mints no ordinal, so an accumulation it grew or
@@ -3597,20 +2918,6 @@ function wakePatched(cell: Cell, head: unknown): void {
3597
2918
  }
3598
2919
  }
3599
2920
 
3600
- /**
3601
- * What an `invalidate` leaves behind: nothing owed, a look above, or a reload.
3602
- *
3603
- * WHAT AN INVALIDATE LEAVES BEHIND, and it is a debt rather than a mark. The mark walk's states
3604
- * are the wrong tool: a node marked `CHECK` or `DIRTY` without its effects queued is one a later
3605
- * write's walk stops at — `state >= wanted` — and the effects below it are never woken for a
3606
- * change that really happened. So nothing in the graph's state moves; the invalidated value OWES
3607
- * A RELOAD, the values built from it OWE A LOOK ABOVE, and none of them is directly servable, so
3608
- * the read that reaches any of them goes a frame in and settles the debt first (7.12, 7.13).
3609
- */
3610
- const OWES_NOTHING: number = 0
3611
- const OWES_ABOVE: number = 1
3612
- const OWES_RELOAD: number = 2
3613
-
3614
2921
  /**
3615
2922
  * Visits a value and each value down its adoption chain.
3616
2923
  *
@@ -3681,8 +2988,7 @@ function reloadOwed(cell: Cell): void {
3681
2988
  */
3682
2989
  function invalidateOne(cell: Cell): void {
3683
2990
  // 7.6 — sent on to the browsers following it whether or not there is a producer to mark.
3684
- const followed = FOLLOWED.get(cell)
3685
- if (followed !== undefined) for (const sendOn of followed) sendOn()
2991
+ sendInvalidate(cell)
3686
2992
  if (!reloads(cell)) return
3687
2993
  // Not directly servable, so the next read goes a frame in and settles the debt.
3688
2994
  cell.direct = false
@@ -4108,193 +3414,6 @@ function storeWritten(cell: Cell, persisted: Persisted): void {
4108
3414
 
4109
3415
  // ── Selections over `tags`, and the bare sweep ──────────────────────────────────────────
4110
3416
 
4111
- /**
4112
- * Each tag to the values carrying it, held weakly.
4113
- *
4114
- * THE INDEX HOLDS VALUES WEAKLY. A tag is a way to find a value, never a reason to keep one, and a
4115
- * strong index would hold every tagged value a page ever made for the life of the process. A
4116
- * collected value is pruned from its sets by the next sweep that finds it gone.
4117
- */
4118
- const TAGGED = new Map<string, Set<WeakRef<Cell>>>()
4119
-
4120
- /**
4121
- * Every value whose producer is a LOAD, held weakly — what a bare selection sweeps.
4122
- *
4123
- * 13.6: A BARE SWEEP REACHES PRODUCERS, and of those it files the ones that LOAD: a value holding
4124
- * a `store`, filed where it is built, and a body the first time it starts a load — a pending
4125
- * answer or a stream (`beginLoad`). A synchronous body is a derivation: reloading it recomputes
4126
- * what its sources already say, and whatever load it reads is filed on its own. And filing is
4127
- * what every filed value pays — a weak handle measured ~230 ns a value under V8 against ~20 under
4128
- * JSC — so a value with nothing to load never pays it: a derivation per cell per row stays at
4129
- * what it cost before, and a load pays it beside the promise it already allocates.
4130
- *
4131
- * Held weakly for `TAGGED`'s reason. AN ARRAY, COMPACTED, RATHER THAN A `Set`: a `Set` of weak
4132
- * handles measured ~120 ns a filing under JSC against ~10 for a push. What a `Set` bought was an
4133
- * O(1) delete on eviction; here an evicted value drops its `ref` instead, and a handle whose value
4134
- * no longer points back at it is dead, the same as one whose value was collected. Because a bare
4135
- * sweep may never run, the filing that finds the array past `compactProducersAt` compacts it, and
4136
- * the bar doubles past what survives, so the walk is amortized over the filings between two.
4137
- */
4138
- let filedProducers: WeakRef<Cell>[] = []
4139
- let compactProducersAt = 1024
4140
-
4141
- /**
4142
- * The probe signal a guard over a selection subscribes to.
4143
- *
4144
- * 13.3 AND 13.9: ONE SIGNAL PER SELECTION, keyed by its canonical tags. A guard over a selection
4145
- * subscribes to this, never to each entry — the probe edge `trackProbe` makes, from a node that
4146
- * is nothing but that edge.
4147
- */
4148
- const SIGNALS = new Map<string, Tracked>()
4149
- const SIGNALS_BY_TAG = new Map<string, Tracked[]>()
4150
- /**
4151
- * The bare selection's one signal. Not a key in `SIGNALS`: `{ tags: [] }` canonicalizes to the
4152
- * empty set and matches nothing, where the bare selection matches every filed load in reach.
4153
- */
4154
- const EVERY_PRODUCER = newTracked()
4155
-
4156
- function refOf(cell: Cell): WeakRef<Cell> {
4157
- let ref = cell.ref
4158
- if (ref === null) {
4159
- ref = new WeakRef(cell)
4160
- cell.ref = ref
4161
- }
4162
- return ref
4163
- }
4164
-
4165
- function tagCell(cell: Cell): void {
4166
- const ref = refOf(cell)
4167
- for (const tag of cell.tags as string[]) {
4168
- let carrying = TAGGED.get(tag)
4169
- if (carrying === undefined) {
4170
- carrying = new Set()
4171
- TAGGED.set(tag, carrying)
4172
- }
4173
- carrying.add(ref)
4174
- }
4175
- }
4176
-
4177
- function fileProducer(cell: Cell): void {
4178
- cell.filed = true
4179
- filedProducers.push(refOf(cell))
4180
- if (filedProducers.length > compactProducersAt) {
4181
- filedProducers = liveProducers()
4182
- compactProducersAt = Math.max(1024, filedProducers.length * 2)
4183
- }
4184
- }
4185
-
4186
- /** The handles whose value is still standing and still filed — neither collected nor evicted. */
4187
- function liveProducers(): WeakRef<Cell>[] {
4188
- const live: WeakRef<Cell>[] = []
4189
- for (let index = 0; index < filedProducers.length; index += 1) {
4190
- const ref = filedProducers[index] as WeakRef<Cell>
4191
- if (ref.deref()?.ref === ref) live.push(ref)
4192
- }
4193
- return live
4194
- }
4195
-
4196
- /**
4197
- * Removes an evicted value from every selection index.
4198
- *
4199
- * What an eviction calls: an entry out of its `Keyed` is out of every selection with it, rather
4200
- * than reachable by a sweep until a collection happens to run.
4201
- */
4202
- export function leaveSelections(value: unknown): void {
4203
- const cell = (value as Callable)[CELL]
4204
- const ref = cell.ref
4205
- if (ref === null) return
4206
- // What takes it out of `filedProducers`: a handle its value no longer points back at is dead.
4207
- cell.ref = null
4208
- if (cell.tags === null) return
4209
- for (const tag of cell.tags) {
4210
- const carrying = TAGGED.get(tag)
4211
- if (carrying === undefined) continue
4212
- carrying.delete(ref)
4213
- if (carrying.size === 0) TAGGED.delete(tag)
4214
- }
4215
- }
4216
-
4217
- /**
4218
- * Takes every value filed so far out of the bare selection, each filed again by its next load.
4219
- *
4220
- * A TEST'S SEAM, with no caller in the framework — `bareSelection.test.ts` calls it before its
4221
- * first case: a page's process ends with the page, and a test process runs every file before this
4222
- * one in it. What those files left held — a module's `global`
4223
- * value, a follow the page keeps for its life — is in reach of a bare sweep (13.13), and a bare
4224
- * `refresh()` reloads it and reads `busy()` true while it asks.
4225
- */
4226
- export function unfileProducers(): void {
4227
- for (let index = 0; index < filedProducers.length; index += 1) {
4228
- const cell = (filedProducers[index] as WeakRef<Cell>).deref()
4229
- if (cell !== undefined) cell.filed = false
4230
- }
4231
- filedProducers = []
4232
- }
4233
-
4234
- /**
4235
- * The values a selection reaches in the current scope, `global` values included: those carrying
4236
- * any of `tags`, or every filed load where `tags` is `null` — the bare selection.
4237
- *
4238
- * 13.8 — A SELECTION IS SCOPE-BOUNDED, and a tag with it, so a selection inside one request never
4239
- * reaches the values another request filed. 13.13 — a `global` value is in every scope, so every
4240
- * selection reaches it, and 13.10 is the bare case of that. In a browser every cell's scope is
4241
- * `undefined`, and so is this.
4242
- */
4243
- function inReach(tags: string[] | null): Cell[] {
4244
- const scope = currentScope()
4245
- if (tags === null) {
4246
- filedProducers = liveProducers()
4247
- const found: Cell[] = []
4248
- for (let index = 0; index < filedProducers.length; index += 1) {
4249
- const cell = (
4250
- filedProducers[index] as WeakRef<Cell>
4251
- ).deref() as Cell
4252
- if (cell.scope === scope || cell.global) found.push(cell)
4253
- }
4254
- return found
4255
- }
4256
- const found = new Set<Cell>()
4257
- for (const tag of tags) {
4258
- const refs = TAGGED.get(tag)
4259
- if (refs === undefined) continue
4260
- for (const ref of refs) {
4261
- const cell = ref.deref()
4262
- if (cell === undefined) refs.delete(ref)
4263
- else if (cell.scope === scope || cell.global) found.add(cell)
4264
- }
4265
- }
4266
- return [...found]
4267
- }
4268
-
4269
- function trackSignal(tags: string[] | null): void {
4270
- const reader = TRACKING.reader
4271
- if (reader === null) return
4272
- if (tags === null) {
4273
- trackProbe(EVERY_PRODUCER, reader)
4274
- return
4275
- }
4276
- const key = JSON.stringify([...new Set(tags)].sort())
4277
- let signal = SIGNALS.get(key)
4278
- if (signal === undefined) {
4279
- signal = newTracked()
4280
- SIGNALS.set(key, signal)
4281
- for (const tag of tags) {
4282
- const signals = SIGNALS_BY_TAG.get(tag)
4283
- if (signals === undefined) SIGNALS_BY_TAG.set(tag, [signal])
4284
- else signals.push(signal)
4285
- }
4286
- }
4287
- trackProbe(signal, reader)
4288
- }
4289
-
4290
- function markSignals(tags: string[]): void {
4291
- for (const tag of tags) {
4292
- const signals = SIGNALS_BY_TAG.get(tag)
4293
- if (signals === undefined) continue
4294
- for (const signal of signals) markAsked(signal.probeReaders)
4295
- }
4296
- }
4297
-
4298
3417
  /**
4299
3418
  * Whether any value in the selection is busy; a reader subscribes to the selection.
4300
3419
  *
@@ -4482,49 +3601,6 @@ const MEMBERS = {
4482
3601
  },
4483
3602
  }
4484
3603
 
4485
- /**
4486
- * The cell `value` serves from, through every adoption: its identity and its ordinal, and nothing
4487
- * else of it the server can reach.
4488
- *
4489
- * 11.12: an adopting value serves the adopted value's production, and an adoption of an adoption
4490
- * goes on down — so a follow's version (18.7) and its feed name the cell that actually produced.
4491
- */
4492
- export function servedCellOf(value: unknown): { readonly ordinal: number } {
4493
- return adoptedCellOf(value)
4494
- }
4495
-
4496
- /**
4497
- * When the production `value` serves stops being servable, as a wall-clock time.
4498
- *
4499
- * 21.8 — WHEN THE PRODUCTION A VALUE IS SERVING STOPS BEING SERVABLE, as a wall-clock time: its
4500
- * own `ttl` from when it was minted (6.5), or its entry's from when the entry last produced
4501
- * (11.45), through whatever it adopts. Infinity where neither bounds it.
4502
- */
4503
- export function deadlineOf(value: unknown): number {
4504
- const cell = adoptedCellOf(value)
4505
- if (cell.expiry !== null) return cell.expiry.at + cell.expiry.ms
4506
- const entry = ENTRY_LIVES.get(cell)
4507
- return entry === undefined ? Number.POSITIVE_INFINITY : entry.at + entry.ms
4508
- }
4509
-
4510
- /**
4511
- * The generation of the load `value` has in flight, or `undefined`.
4512
- *
4513
- * 16.48 — WHICH LOAD A VALUE HAS IN FLIGHT, as the generation that started it, or `undefined` where
4514
- * none is. Read off the cell rather than through `busy`, which is a probe and would subscribe the
4515
- * caller that asked (3.3).
4516
- *
4517
- * A WINDOW HOLDING A PRODUCTION IS BUSY AND IS NO LOAD (5.15): nothing is in flight for a call to end
4518
- * or time, and the window's close is its own bound. Told apart by the hold, which only a value with
4519
- * neither body nor stream makes — so a write's load taken in under a hold is not one a call times.
4520
- */
4521
- export function loadOf(value: unknown): number | undefined {
4522
- const cell = (value as Callable)[CELL]
4523
- if (!cell.loading) return undefined
4524
- if (cell.cap?.holding && cell.stream === null) return undefined
4525
- return cell.generation
4526
- }
4527
-
4528
3604
  // The cells a mutation's call has been answered from, so the next call knows the answer is spent.
4529
3605
  const ANSWERED = new WeakSet<object>()
4530
3606
 
@@ -4555,16 +3631,6 @@ export function dropAnswered(value: unknown): void {
4555
3631
  dropStanding(cell, expiry)
4556
3632
  }
4557
3633
 
4558
- /**
4559
- * The generation `value`'s past stands at, or `undefined` while a load is in flight.
4560
- *
4561
- * What 21.15's `Cached` compares across a call, read through adoption as `servedCellOf` is.
4562
- */
4563
- export function heldGenerationOf(value: unknown): number | undefined {
4564
- const cell = adoptedCellOf(value)
4565
- return cell.loading ? undefined : cell.generation
4566
- }
4567
-
4568
3634
  /**
4569
3635
  * Whether `value` stands on a failure the next reach runs again rather than serves.
4570
3636
  *
@@ -4604,26 +3670,6 @@ export function streamingOrSettled(value: unknown): Promise<unknown> {
4604
3670
  return settled((value as Callable)[CELL], true)
4605
3671
  }
4606
3672
 
4607
- /**
4608
- * Whether `value` is a streaming producer's `Reactive`.
4609
- *
4610
- * A streaming producer's own `Reactive` — a body declared as an async generator, or one whose run
4611
- * handed one back (9.6).
4612
- */
4613
- export function isStreaming(value: unknown): boolean {
4614
- if (!isReactive(value)) return false
4615
- const stream = (value as Partial<Callable>)[CELL]?.stream
4616
- return stream !== null && stream !== undefined
4617
- }
4618
-
4619
- function adoptedCellOf(value: unknown): Cell {
4620
- let cell = (value as Callable)[CELL]
4621
- // A stream's own `adoption` is a write it follows (9.11), and its past is its own.
4622
- while (cell.adoption !== null && ownStream(cell) === null)
4623
- cell = cell.adoption.source
4624
- return cell
4625
- }
4626
-
4627
3673
  /**
4628
3674
  * The keys of every `Reactive` member.
4629
3675
  *