footprintjs 9.28.0 → 9.30.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 (44) hide show
  1. package/CLAUDE.md +8 -6
  2. package/dist/esm/lib/engine/handlers/SubflowExecutor.js +41 -2
  3. package/dist/esm/lib/memory/EventLog.d.ts +6 -0
  4. package/dist/esm/lib/memory/EventLog.js +10 -4
  5. package/dist/esm/lib/memory/SharedMemory.d.ts +18 -4
  6. package/dist/esm/lib/memory/SharedMemory.js +42 -11
  7. package/dist/esm/lib/memory/StageContext.d.ts +45 -18
  8. package/dist/esm/lib/memory/StageContext.js +82 -27
  9. package/dist/esm/lib/memory/TransactionBuffer.d.ts +256 -86
  10. package/dist/esm/lib/memory/TransactionBuffer.js +497 -273
  11. package/dist/esm/lib/memory/admission.d.ts +81 -0
  12. package/dist/esm/lib/memory/admission.js +152 -0
  13. package/dist/esm/lib/memory/borrowedMutation.d.ts +9 -0
  14. package/dist/esm/lib/memory/borrowedMutation.js +18 -1
  15. package/dist/esm/lib/memory/deltaEncoding.d.ts +66 -0
  16. package/dist/esm/lib/memory/deltaEncoding.js +122 -0
  17. package/dist/esm/lib/memory/pathOps.d.ts +63 -0
  18. package/dist/esm/lib/memory/pathOps.js +150 -1
  19. package/dist/esm/lib/memory/utils.d.ts +47 -16
  20. package/dist/esm/lib/memory/utils.js +119 -24
  21. package/dist/esm/lib/runner/FlowChartExecutor.d.ts +7 -5
  22. package/dist/esm/lib/runner/FlowChartExecutor.js +8 -6
  23. package/dist/lib/engine/handlers/SubflowExecutor.js +41 -2
  24. package/dist/lib/memory/EventLog.js +9 -3
  25. package/dist/lib/memory/SharedMemory.js +40 -9
  26. package/dist/lib/memory/StageContext.js +81 -26
  27. package/dist/lib/memory/TransactionBuffer.js +495 -271
  28. package/dist/lib/memory/admission.js +158 -0
  29. package/dist/lib/memory/borrowedMutation.js +20 -2
  30. package/dist/lib/memory/deltaEncoding.js +128 -0
  31. package/dist/lib/memory/pathOps.js +159 -2
  32. package/dist/lib/memory/utils.js +122 -25
  33. package/dist/lib/runner/FlowChartExecutor.js +8 -6
  34. package/dist/types/lib/memory/EventLog.d.ts +6 -0
  35. package/dist/types/lib/memory/SharedMemory.d.ts +18 -4
  36. package/dist/types/lib/memory/StageContext.d.ts +45 -18
  37. package/dist/types/lib/memory/TransactionBuffer.d.ts +256 -86
  38. package/dist/types/lib/memory/admission.d.ts +81 -0
  39. package/dist/types/lib/memory/borrowedMutation.d.ts +9 -0
  40. package/dist/types/lib/memory/deltaEncoding.d.ts +66 -0
  41. package/dist/types/lib/memory/pathOps.d.ts +63 -0
  42. package/dist/types/lib/memory/utils.d.ts +47 -16
  43. package/dist/types/lib/runner/FlowChartExecutor.d.ts +7 -5
  44. package/package.json +2 -1
@@ -32,10 +32,45 @@
32
32
  * `set` path — detaches that value first ({@link detachHeldAncestors}), so
33
33
  * `workingCopy` and `overwritePatch` never share a container the engine
34
34
  * mutates on one side only.
35
+ *
36
+ * COPY-ON-WRITE (9.29.0 — docs/design/2026-10-copy-on-write-commit.md). The
37
+ * buffer no longer clones the committed state it starts from. `baseSnapshot`
38
+ * IS the committed generation the stage first touched (held by reference —
39
+ * committed state is immutable-after-swap), and `workingCopy` starts as a
40
+ * copy of its ROOT only: each write copies the containers on its own path
41
+ * ({@link ownSpine}), and the first READ after the stage's first write of a
42
+ * container still shared with committed state takes a private deep copy of
43
+ * it ({@link privatise}) — what the whole-state clone used to give every
44
+ * read, so an in-place edit of a read value stays private exactly as it did.
45
+ * A read the working copy cannot answer is served from live state by the
46
+ * caller, as before; the buffer then replaces that path of its diff base
47
+ * with a private copy ({@link detachBase}), as the clone had it.
48
+ *
49
+ * THE ADMITTED RECORD (9.30.0 — docs/design/2026-10-admitted-record.md). A
50
+ * commit is admitted only if its bundle folds back to the stage's
51
+ * read-your-writes view at every path the stage touched (and at every
52
+ * container its writes created on the way there, below the stage's address).
53
+ * Both encoders commit the value the stage read: a compact row — a `merge`
54
+ * delta, an `append` tail — is kept where it provably folds back; a family of
55
+ * rows that does not is recorded as `set` rows of the values the stage read
56
+ * ({@link admit}). Before 9.30.0 the one accumulated merge delta per path was
57
+ * replayed at every `merge` row of that path, which lied across a hard write
58
+ * (`$update(k,{x}); k = {y}; $update(k,{z})` committed `{y, x, z}` for a
59
+ * read-back of `{y, z}`), an `[]` clear, a kind change or an array union
60
+ * deduplicated by reference. Verified when the stage staged a `merge` or a
61
+ * nested op; a stage that staged only `set` / `delete` of keys directly under
62
+ * its address is coherent by construction — both trees receive the same
63
+ * write — and is admitted without the fold.
35
64
  */
36
65
  import type { CommitValuesMode, MemoryPatch, TraceEntry } from './types.js';
37
66
  export declare class TransactionBuffer {
38
- private readonly baseSnapshot;
67
+ /**
68
+ * The net-change diff base: the committed generation the stage first
69
+ * touched, by reference — except where {@link detachBase} replaced a path
70
+ * of it with a private copy (its root and the containers on the way are
71
+ * then copies too, owned by {@link baseOwned}).
72
+ */
73
+ private baseSnapshot;
39
74
  private workingCopy;
40
75
  private overwritePatch;
41
76
  private updatePatch;
@@ -57,11 +92,59 @@ export declare class TransactionBuffer {
57
92
  * keys tracked-read so far — the temporal-prefix attribution consumed by
58
93
  * causal slicing. Undefined (default) = zero cost, byte-identical ops. */
59
94
  private readonly readKeysProvider?;
60
- constructor(base: any, commitValues?: CommitValuesMode, readKeysProvider?: () => string[]);
95
+ /**
96
+ * The containers in `workingCopy` this buffer CREATED: its root copy, the
97
+ * path copies its writes made, the merge results it built, and every
98
+ * container of the private copies its reads took. A write edits these in
99
+ * place. Everything else in `workingCopy` is SHARED — with the committed
100
+ * generation the stage first touched, or with a value the stage staged —
101
+ * and is copied before a write passes through it ({@link ownSpine}).
102
+ */
103
+ private owned;
104
+ /**
105
+ * Container values the stage staged with {@link set} — its own objects,
106
+ * held by reference (9.23.0). A read hands them back as they are, exactly
107
+ * as the private working copy always did, and never privatises them: a
108
+ * private copy of a staged value would leave `workingCopy` and
109
+ * `overwritePatch` disagreeing about a value the stage wrote.
110
+ */
111
+ private staged;
112
+ /**
113
+ * Owned containers with no container still shared with committed state
114
+ * anywhere below them (a private deep copy, a merge result built on a
115
+ * private base, a path copy whose shared children were privatised). A read
116
+ * that lands on one needs no walk — see {@link privatiseBelow}.
117
+ */
118
+ private privateTrees;
119
+ /**
120
+ * The containers of {@link baseSnapshot} that {@link detachBase} created:
121
+ * its root copy and the copies on the way to a detached path. Allocated
122
+ * only by the first detach — the in-contract stage never pays for it.
123
+ */
124
+ private baseOwned?;
125
+ /**
126
+ * The private deep copies {@link detachBase} put into the diff base: nothing
127
+ * at or below one is committed state, so a later detach inside it is a no-op.
128
+ */
129
+ private detachedBase?;
130
+ /**
131
+ * Where the stage writes (9.30.0): `['runs', runId]` for a run-namespaced
132
+ * stage, `[]` otherwise. Its containers are the stage's ADDRESS, not a value
133
+ * the stage reads (every read it makes is a key below it), so a shell a
134
+ * write leaves there is no part of the read-back the record must hold.
135
+ */
136
+ private readonly address;
137
+ /** `merge` ops staged since the last commit — see {@link admit}. */
138
+ private stagedMerges;
139
+ /** Ops staged deeper than one key below the stage's address — see {@link admit}. */
140
+ private nestedOps;
141
+ constructor(base: any, commitValues?: CommitValuesMode, readKeysProvider?: () => string[], address?: readonly string[]);
61
142
  /** Stamp the current read prefix onto a staged op — only when the
62
143
  * provenance dial is on (provider present), so the default path allocates
63
144
  * nothing and commit bundles stay byte-identical. */
64
145
  private stampReadKeys;
146
+ /** Stage an op into `opTrace`, counting what decides whether {@link admit} must fold. */
147
+ private stage;
65
148
  /**
66
149
  * Hard overwrite at the specified path. Stores the REFERENCE in both trees
67
150
  * (9.23.0) — the record's copy is taken once, at commit; see the header.
@@ -101,7 +184,15 @@ export declare class TransactionBuffer {
101
184
  delete(path: (string | number)[], shouldRedact?: boolean): void;
102
185
  /** Deep union merge at the specified path. `deepSmartMerge` builds fresh
103
186
  * containers, so neither tree ever holds the merge INPUT by reference;
104
- * the nested-op detach guards the ancestor it writes INTO. */
187
+ * the nested-op detach guards the ancestor it writes INTO.
188
+ *
189
+ * The value merged INTO is made private first (`privatise`), as the
190
+ * whole-state clone made it before 9.29.0. Not only for the reads that
191
+ * follow: `deepSmartMerge` unions arrays BY REFERENCE, so whether an
192
+ * element the stage passes in is "already there" depends on which objects
193
+ * the base holds — a committed array would dedup an element the stage
194
+ * read from it before its first write, where the private copy (and
195
+ * 9.28.0) appends it. */
105
196
  merge(path: (string | number)[], value: any, shouldRedact?: boolean): void;
106
197
  /**
107
198
  * Field-level redaction (9.19.0): mark dot-paths INSIDE the value staged at
@@ -113,14 +204,99 @@ export declare class TransactionBuffer {
113
204
  * (see {@link survivingRedactedPaths}).
114
205
  */
115
206
  markRedactedFields(path: (string | number)[], fields: readonly string[]): void;
207
+ /**
208
+ * Does a redaction mark address an array ELEMENT right below `path`
209
+ * (`list.1.token`)? An `append` row re-bases the indices onto the tail, so
210
+ * such a path takes the whole-value `set` (`deltaEncoding · pushValueRow`).
211
+ * A mark by NAME below an array (`obj.y`) means the same thing on the tail
212
+ * as on the whole value, so the compact row stays (byte-identical).
213
+ */
214
+ private markedBelow;
116
215
  /**
117
216
  * The redacted paths that survive the net-change filter: a path survives
118
217
  * when it IS a surviving op path (a whole-key redaction) or sits UNDER one
119
218
  * (a field inside a surviving write). A dropped op takes its fields with it.
120
219
  */
121
220
  private survivingRedactedPaths;
122
- /** Read current value at path (includes uncommitted changes). */
221
+ /**
222
+ * Read current value at path (includes uncommitted changes). The value is
223
+ * the stage's own — private to it, as the whole-state clone made every read
224
+ * after the first write before 9.29.0 (`privatise`).
225
+ */
123
226
  get(path: (string | number)[], defaultValue?: any): any;
227
+ /**
228
+ * Read the working copy at `path` WITHOUT taking a private copy — for a
229
+ * reader that only compares (the dev-mode borrowed-mutation report in
230
+ * `StageContext.commit`), never for a value handed to a stage.
231
+ */
232
+ peek(path: (string | number)[]): unknown;
233
+ /**
234
+ * Keep the diff base exact under a read the working copy cannot answer.
235
+ *
236
+ * When `workingCopy` holds nothing at `path` — the stage deleted or unset
237
+ * it, or a write replaced a container above it — `StageContext ·
238
+ * readState` serves the read from LIVE committed state, exactly as 9.28.0
239
+ * did, so the value it hands out is committed state itself. On 9.28.0 the
240
+ * diff base was a whole-state clone taken at the stage's first write, and
241
+ * an in-place edit of that value (out of contract — reads are borrowed)
242
+ * could not move it: written back, the edit was recorded. Here the diff
243
+ * base IS a committed generation, and it very often holds that same
244
+ * container at `path` — the edit would move the base with it, and the
245
+ * write-back would commit no change. So before the value goes out, the
246
+ * base's value at `path` is replaced by a private deep copy (the base's
247
+ * root and the containers on the way copied shallowly) — what 9.28.0's
248
+ * base held there. The commit's net-change test compares against it and
249
+ * the delta encoder replays from it; the value handed out stays the live
250
+ * one, so whatever else an edit of it reaches (live state, the next
251
+ * generation) behaves as on 9.28.0 too.
252
+ *
253
+ * Not `privatise`: a private copy handed to the stage would also keep the
254
+ * edit out of live state, where 9.28.0 let it in — a run-namespaced read
255
+ * that falls back to a global key would then end differently (the
256
+ * differential's NESTED family fails within 100 programs that way).
257
+ *
258
+ * Copies nothing when the base holds no container at `path`, and nothing
259
+ * twice: a path at or below an earlier detach is already private. O(path)
260
+ * otherwise, plus O(value) once per detached path.
261
+ */
262
+ detachBase(path: (string | number)[]): void;
263
+ /**
264
+ * Private reads (9.29.0): make the value at `path` the stage's own before
265
+ * a read hands it out — so a read after the stage's first write behaves
266
+ * exactly as it did when the buffer began with a deep clone of the whole
267
+ * state. An in-place edit of what the read returned (out of contract —
268
+ * reads are borrowed) stays inside the buffer, and committed state is never
269
+ * touched. Whether the RECORD keeps it is the admitted record's law
270
+ * (9.30.0, owner ruling R1 — the record keeps what the stage read back): it
271
+ * is kept when the edited value lies at or below a path the stage wrote in
272
+ * this stage — set, merged or written back alike — and lost otherwise.
273
+ *
274
+ * Walking the path from the (owned) root:
275
+ * - a container still SHARED with committed state at the same position is
276
+ * replaced by a private deep copy when it is the value read, or by a
277
+ * shallow copy when it is a container on the way to it (so a read of
278
+ * `runs/<id>/k` copies `k`, not every run's namespace);
279
+ * - a container the stage STAGED (or anything else the buffer did not
280
+ * take from committed state) is handed back by reference, as before;
281
+ * - a container the buffer owns is walked on — and when it is the value
282
+ * read, its still-shared descendants are privatised
283
+ * ({@link privatiseBelow}).
284
+ *
285
+ * Cost: O(path) per read, plus O(value) ONCE per shared container a stage
286
+ * reads after its first write. A stage that never reads after writing pays
287
+ * nothing; a read before the first write never reaches the buffer.
288
+ */
289
+ private privatise;
290
+ /**
291
+ * An OWNED container is about to be read whole (a path copy a nested write
292
+ * made, say): its descendants still shared with committed state are
293
+ * replaced by private deep copies, so nothing the read hands out is
294
+ * committed state. Walks owned containers only; marks each one finished
295
+ * ({@link privateTrees}), so a container is scanned once per stage.
296
+ */
297
+ private privatiseBelow;
298
+ /** A private deep copy of a committed container — owned through and through. */
299
+ private privateCopyOf;
124
300
  /**
125
301
  * Did any staged op touch `path`, or a path above or below it?
126
302
  *
@@ -204,14 +380,14 @@ export declare class TransactionBuffer {
204
380
  * Paths are compared at the exact granularity they were written (each trace
205
381
  * entry's path), against `workingCopy` (final) vs `baseSnapshot` (start).
206
382
  * Surviving `set` paths copy their final value from `overwritePatch`;
207
- * surviving `merge` paths copy their accumulated delta from `updatePatch` —
208
- * preserving the set-vs-merge verb so replay ({@link applySmartMerge}) is
209
- * byte-for-byte identical to recording only the real changes.
383
+ * surviving `merge` paths copy their accumulated delta from `updatePatch`,
384
+ * keeping the set-vs-merge verb — and the result is ADMITTED ({@link admit}):
385
+ * a family of rows whose replay does not give back what the stage read is
386
+ * recorded as `set` rows of the read-back instead (9.30.0).
210
387
  *
211
- * This is the DEFAULT (`commitValues: 'full'`) payload — byte-identical to
212
- * the historical behavior, including flattening staged `delete` ops into
213
- * `set`-of-`undefined` trace entries. The delta encoding lives in
214
- * {@link toDeltaPayload}.
388
+ * This is the DEFAULT (`commitValues: 'full'`) payload, including the
389
+ * historical flattening of staged `delete` ops into `set`-of-`undefined`
390
+ * trace entries. The delta encoding lives in {@link toDeltaPayload}.
215
391
  *
216
392
  * Work, not bytes (9.22.1): the net-change verdict is paid once per PATH
217
393
  * and the clone once per CONSECUTIVE run of ops on a path, not once per op
@@ -222,6 +398,8 @@ export declare class TransactionBuffer {
222
398
  * place the record is detached from them.
223
399
  */
224
400
  private toChangeOnlyPayload;
401
+ /** The 'full' rows; a family in `lossy` is written as its read-back, at its last touch ({@link emitReadBack}). */
402
+ private changeOnlyRows;
225
403
  /**
226
404
  * Delta-encoded payload (`commitValues: 'delta'`, #13c-B) — same net-change
227
405
  * filter as {@link toChangeOnlyPayload}, three encoding differences:
@@ -240,40 +418,78 @@ export declare class TransactionBuffer {
240
418
  * the `'full'` flattening (`_set` of `undefined`) COERCES that parent
241
419
  * into an object; when they would disagree we keep the flattening;
242
420
  * - ONLY `'merge'` ops → `merge` with the accumulated `updatePatch`
243
- * delta (replaying the accumulated delta once ≡ the full mode's
244
- * k sequential replays — `deepSmartMerge` is reference-idempotent
245
- * within one replay pass);
246
- * - otherwise (`set`/mixed): the committed value is computed by
247
- * replaying the path's op sequence EXACTLY the way `applySmartMerge`
248
- * replays the full-mode bundle ({@link replayPathVerbs}) — for
249
- * pure-set paths that is simply the last set value; for mixed
250
- * set+merge interleavings it reproduces the full mode's quirk of
251
- * applying the ACCUMULATED merge delta at every merge position
252
- * (which can differ from the buffer's read-your-writes view; parity
253
- * with the `'full'` mode's committed state is the contract). If base
254
- * and that value are arrays and base is a STRICT PREFIX → `append`
255
- * storing only the tail; else `set` storing the full value.
421
+ * delta;
422
+ * - otherwise (`set`/mixed): the value the stage's 'full' rows give the
423
+ * path ({@link fullRowsValue}). If base and that value are arrays and
424
+ * base is a STRICT PREFIX → `append` storing only the tail; else `set`
425
+ * storing the full value.
256
426
  * 3. **OVERLAP FAMILIES take the full-value fallback.** `overwrite` /
257
427
  * `updates` are nested path TREES, so two surviving paths where one is
258
- * an ancestor of the other (`a` and `a.p`) share storage. The `'full'`
259
- * payload survives that because every entry stores the FULL value at its
260
- * path, drawn from one coherent tree — nested entries agree with their
261
- * ancestor by construction. Delta's per-path encodings do NOT: an
262
- * `append` ancestor stores only a TAIL (whose indices are shifted
263
- * relative to the whole array) and a `delete` ancestor stores
264
- * `undefined`, so whichever entry is written second silently destroys or
265
- * corrupts the other — the recorded write is LOST at replay. Therefore
266
- * every path that has a surviving ancestor/descendant is committed as a
267
- * plain `set` of the value it holds in the family's replayed value
268
- * ({@link replayFamilyVerbs}), and the family's shallowest path (whose
269
- * set covers the whole subtree) is emitted LAST. One coherent tree in,
270
- * one coherent tree out: entries can no longer clobber each other and
271
- * the replayed value is exact regardless of order.
428
+ * an ancestor of the other (`a` and `a.p`) share storage. Delta's
429
+ * per-path encodings would clobber each other there (an `append`
430
+ * ancestor stores only a TAIL, a `delete` ancestor `undefined`), so every
431
+ * path that has a surviving ancestor/descendant is committed as a plain
432
+ * `set` of the value the 'full' rows give it, and the family's
433
+ * shallowest path (whose set covers the whole subtree) is emitted LAST.
272
434
  *
273
- * Losslessness never depends on detection succeeding — every fallback is
274
- * today's full-value `set`.
435
+ * The result is ADMITTED ({@link admit}) like the 'full' payload: a compact
436
+ * row is kept only where the bundle provably folds back, and a family that
437
+ * does not is recorded as what the stage read. So both encodings commit the
438
+ * value the stage read; before 9.30.0 they shared a replay that did not
439
+ * (`replayPathVerbs` / `replayFamilyVerbs`, deleted).
275
440
  */
276
441
  private toDeltaPayload;
442
+ /** The delta rows; a family in `lossy` is written as its read-back, at its last touch ({@link emitReadBack}). */
443
+ private deltaRows;
444
+ /**
445
+ * THE ADMISSION — a commit is admitted only if its bundle folds back to the
446
+ * stage's read-your-writes view at every path the stage touched. `build`
447
+ * lays the rows out (one encoder: `'full'` or `'delta'`); the candidate is
448
+ * checked ({@link lossyFamilies}), and when some family's rows do not fold
449
+ * back the rows are laid out again with those families written as what the
450
+ * stage read ({@link emitReadBack}) — every other family's bytes exactly as
451
+ * the first layout made them.
452
+ */
453
+ private admit;
454
+ /**
455
+ * The families whose rows do not fold back to what the stage read —
456
+ * `undefined` when there are none (`admission.ts · lossyFamilies`: the
457
+ * candidate replayed onto the diff base by `dryFold`, every family of
458
+ * touched paths compared with the working copy at its root and on the way
459
+ * down to it).
460
+ *
461
+ * Without a fold, when the stage staged no `merge` and no nested op: its
462
+ * rows are `set` / `delete` of keys directly under its address, each
463
+ * writing the SAME value into `workingCopy` and `overwritePatch` — the
464
+ * record is the read-back by construction (the property's ROOT-ONLY arm
465
+ * pins this). That keeps the commit of the typed scope's root-key writes
466
+ * exactly as cheap as it was.
467
+ */
468
+ private lossyFamilies;
469
+ /**
470
+ * A family whose rows did not fold back, written as what the stage read:
471
+ * one `set` row per member that changed (descendants by last touch, each
472
+ * with its own read prefix), the ROOT last, and the root's read-back value
473
+ * in `overwrite` — one coherent tree, so no row can clobber another. The
474
+ * root's row is written even when the root itself did not change: it is the
475
+ * row that carries the family's read-back (and the containers L-1's dropped
476
+ * op left). A lone root under `'delta'` keeps the compact `append` when the
477
+ * value it read is its base plus a tail.
478
+ */
479
+ private emitReadBack;
480
+ /**
481
+ * The value the stage's 'full' rows give a path — what the delta encoder
482
+ * commits for a family member or a path with a `set` — read from ONE
483
+ * {@link dryFold} of those rows over the patch trees themselves, taken the
484
+ * first time it is asked. By reference, as the stage held them: an element
485
+ * a `set` and a `merge` of one path share stays one element. A stage that
486
+ * staged no `merge` and no nested op needs no fold — a path's value is its
487
+ * last staged value. (Before 9.30.0: two replicas of the verb law,
488
+ * `replayPathVerbs` and `replayFamilyVerbs`.)
489
+ */
490
+ private fullRowsValue;
491
+ /** The stage's 'full' rows: every op on a path the net-change filter keeps, a `delete` spelled `set`. */
492
+ private fullRows;
277
493
  /**
278
494
  * Did the stage change the value at `segments`? Base and final value are
279
495
  * fixed at commit, so this is the ONE net-change verdict both payload
@@ -290,40 +506,6 @@ export declare class TransactionBuffer {
290
506
  private opsByPath;
291
507
  /** The net-change filter — identical to 'full' ({@link changedSinceBase}). Survivors keep last-touch order. */
292
508
  private netChangeSurvivors;
293
- /** Replay each overlapping family ONCE, lazily — most commits have none, and pay nothing. */
294
- private memoisedFamilyValue;
295
- /**
296
- * Bucket the staged ops of every OVERLAPPING family by family root, in op
297
- * order — the input {@link replayFamilyVerbs} folds. Ops on paths the
298
- * net-change filter dropped are skipped (they are absent from `rootOf`),
299
- * exactly as the `'full'` payload drops them from its trace. One pass over
300
- * `opTrace`, and only when at least one family actually overlaps — commits
301
- * that write no nested path pay nothing.
302
- */
303
- private opsByFamily;
304
- /**
305
- * Replay ONE overlapping family's staged ops onto the family root's base
306
- * value — the multi-path generalisation of {@link replayPathVerbs}, and
307
- * byte-for-byte what `applySmartMerge` produces for the corresponding
308
- * `'full'`-mode entries: each `set`/`delete` position writes that path's
309
- * `overwritePatch` value, each `merge` position deep-merges that path's
310
- * accumulated `updatePatch` delta into the value replayed so far.
311
- *
312
- * (Both patches are single coherent trees, so a full-mode bundle's stored
313
- * value at any recorded path always reads back as its `overwritePatch` /
314
- * `updatePatch` value — which is why sourcing from them here reproduces the
315
- * full-mode replay exactly, including its intermediate-coercion quirks.)
316
- *
317
- * The value is held in a `{ v }` box so the root itself (relative path `[]`)
318
- * can be REPLACED by `_set` the same way `applySmartMerge` replaces it
319
- * inside the state tree — including `nativeSet`'s coercion of primitive
320
- * intermediates.
321
- *
322
- * A `set` op the next op sets again is skipped on the same law as
323
- * `applySmartMerge` ({@link supersededByNextSet}) — this is the delta
324
- * encoder's own replay loop, and it clones per op just as the fold does.
325
- */
326
- private replayFamilyVerbs;
327
509
  /**
328
510
  * May a staged `delete` at this path commit as the `'delete'` verb?
329
511
  *
@@ -335,16 +517,4 @@ export declare class TransactionBuffer {
335
517
  * so those (pathological) deletes keep the historical flattening.
336
518
  */
337
519
  private deleteReplaysAsFlattening;
338
- /**
339
- * Replay ONE path's op-verb sequence against its base value, exactly the
340
- * way `applySmartMerge` replays the corresponding full-mode bundle: every
341
- * `set`/`delete` position applies the LAST staged overwrite value (the
342
- * bag holds one value per path — last writer wins), every `merge`
343
- * position applies the ACCUMULATED `updatePatch` delta. This reproduces
344
- * the full mode's committed value for any interleaving — including the
345
- * mixed set+merge quirk where the accumulated delta re-applies pre-set
346
- * merge keys (full-mode replay semantics, kept for byte-parity across
347
- * modes; property-tested in delta-replay-equivalence).
348
- */
349
- private replayPathVerbs;
350
520
  }