@sovereignbase/sequencer 0.0.2 → 1.0.1
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/INTERNALS.md +897 -0
- package/LICENSE +201 -201
- package/README.md +146 -99
- package/dist/index.cjs +200 -113
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +143 -11
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +143 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +201 -114
- package/dist/index.js.map +1 -1
- package/package.json +23 -23
package/INTERNALS.md
ADDED
|
@@ -0,0 +1,897 @@
|
|
|
1
|
+
# How sequencer works
|
|
2
|
+
|
|
3
|
+
Sequencer keeps an ordered sequence synchronized between replicas.
|
|
4
|
+
|
|
5
|
+
Applications see a normal indexed sequence:
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
A B C D
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
with positions:
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
0 1 2 3
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Internally Sequencer cannot use those positions to describe replicated edits.
|
|
18
|
+
|
|
19
|
+
If another Frame is inserted before `B`:
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
A X B C D
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`B` moves from position `1` to position `2`.
|
|
26
|
+
|
|
27
|
+
Instead, when an edit is made, Sequencer finds the existing history around that position and records the edit relative to it.
|
|
28
|
+
|
|
29
|
+
## Projection and Structural Order
|
|
30
|
+
|
|
31
|
+
The **Projection** is the sequence the application currently sees.
|
|
32
|
+
|
|
33
|
+
For example:
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
A B C D
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
has four visible Frames:
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
A B C D
|
|
43
|
+
0 1 2 3
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Insertion positions are boundaries between Frames:
|
|
47
|
+
|
|
48
|
+
```text
|
|
49
|
+
| A | B | C | D |
|
|
50
|
+
0 1 2 3 4
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Behind the Projection is **Structural Order**.
|
|
54
|
+
|
|
55
|
+
Structural Order contains the Insertions that produced the sequence, including history that may no longer be visible.
|
|
56
|
+
|
|
57
|
+
A simple sequence might start as:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
Structural Order
|
|
61
|
+
|
|
62
|
+
[A B C D]
|
|
63
|
+
|
|
64
|
+
Projection
|
|
65
|
+
|
|
66
|
+
A B C D
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
After `B C` are removed, the Projection becomes:
|
|
70
|
+
|
|
71
|
+
```text
|
|
72
|
+
A D
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
but Structural Order still contains the original positive Insertion and the history describing the removal.
|
|
76
|
+
|
|
77
|
+
More history can later attach to those original coordinates, so hidden history may remain useful long after its Frames disappear from the Projection.
|
|
78
|
+
|
|
79
|
+
## Insertions
|
|
80
|
+
|
|
81
|
+
History is made of **Insertions**.
|
|
82
|
+
|
|
83
|
+
An Insertion has six coordinates:
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
anchorSession
|
|
87
|
+
anchorStart
|
|
88
|
+
anchorDiff
|
|
89
|
+
|
|
90
|
+
insertionSession
|
|
91
|
+
insertionStart
|
|
92
|
+
insertionDiff
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The first three describe where the Insertion belongs:
|
|
96
|
+
|
|
97
|
+
```text
|
|
98
|
+
(anchorSession, anchorStart, anchorDiff)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The next two identify the Insertion:
|
|
102
|
+
|
|
103
|
+
```text
|
|
104
|
+
(insertionSession, insertionStart)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
and `insertionDiff` describes its original Frame length and whether it adds or removes Frames.
|
|
108
|
+
|
|
109
|
+
A positive Insertion adds Frames:
|
|
110
|
+
|
|
111
|
+
```text
|
|
112
|
+
insertionDiff = 4
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
A reducing Insertion masks Frames:
|
|
116
|
+
|
|
117
|
+
```text
|
|
118
|
+
insertionDiff = -4
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Positive Insertions can also carry **Footage**, which contains the actual values.
|
|
122
|
+
|
|
123
|
+
Sequencer orders the Insertion. Footage is what eventually appears in the Projection.
|
|
124
|
+
|
|
125
|
+
## Frames and logical points
|
|
126
|
+
|
|
127
|
+
Suppose one Insertion contains:
|
|
128
|
+
|
|
129
|
+
```text
|
|
130
|
+
A B C
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
It has three Frames:
|
|
134
|
+
|
|
135
|
+
```text
|
|
136
|
+
A B C
|
|
137
|
+
0 1 2
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
and four logical points:
|
|
141
|
+
|
|
142
|
+
```text
|
|
143
|
+
| A | B | C |
|
|
144
|
+
0 1 2 3
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
An anchor points to one of these boundaries.
|
|
148
|
+
|
|
149
|
+
For example:
|
|
150
|
+
|
|
151
|
+
```text
|
|
152
|
+
anchorDiff = 2
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
refers to:
|
|
156
|
+
|
|
157
|
+
```text
|
|
158
|
+
A B | C
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
inside that original Insertion.
|
|
162
|
+
|
|
163
|
+
If later edits move `C` somewhere else in the Projection, this point is still point `2` of the same original Insertion.
|
|
164
|
+
|
|
165
|
+
## Anchoring an edit
|
|
166
|
+
|
|
167
|
+
Suppose the Projection contains:
|
|
168
|
+
|
|
169
|
+
```text
|
|
170
|
+
Hello world
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
and `big ` is inserted here:
|
|
174
|
+
|
|
175
|
+
```text
|
|
176
|
+
Hello | world
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Sequencer first finds which original Insertion owns that boundary.
|
|
180
|
+
|
|
181
|
+
If the boundary is point `6` of an Insertion identified by:
|
|
182
|
+
|
|
183
|
+
```text
|
|
184
|
+
(session 4, start 20)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
the new Insertion can anchor to:
|
|
188
|
+
|
|
189
|
+
```text
|
|
190
|
+
anchorSession = 4
|
|
191
|
+
anchorStart = 20
|
|
192
|
+
anchorDiff = 6
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Another replica might currently see:
|
|
196
|
+
|
|
197
|
+
```text
|
|
198
|
+
Well, Hello world
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The same anchor still refers to the point after `Hello ` in the original Insertion.
|
|
202
|
+
|
|
203
|
+
The Projection position is different, but the relationship is the same.
|
|
204
|
+
|
|
205
|
+
## Insertion identity
|
|
206
|
+
|
|
207
|
+
An Insertion is identified by:
|
|
208
|
+
|
|
209
|
+
```text
|
|
210
|
+
(insertionSession, insertionStart)
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
The anchor is not part of its identity.
|
|
214
|
+
|
|
215
|
+
If the same Insertion arrives twice, both copies have the same identity.
|
|
216
|
+
|
|
217
|
+
Sequencer can keep the first and ignore the duplicate instead of inserting the same content twice.
|
|
218
|
+
|
|
219
|
+
Fragments of an Insertion also keep this identity. Splitting an Insertion at runtime does not create new replicated history.
|
|
220
|
+
|
|
221
|
+
## Sessions
|
|
222
|
+
|
|
223
|
+
Insertions are authored inside **Sessions**.
|
|
224
|
+
|
|
225
|
+
A Session has its own logical time.
|
|
226
|
+
|
|
227
|
+
Suppose a Session creates a three-Frame Insertion starting at `0`.
|
|
228
|
+
|
|
229
|
+
Its Frame coordinates occupy:
|
|
230
|
+
|
|
231
|
+
```text
|
|
232
|
+
0 1 2
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
and its endpoint is:
|
|
236
|
+
|
|
237
|
+
```text
|
|
238
|
+
3
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
A new independent Insertion normally starts after another reserved logical point:
|
|
242
|
+
|
|
243
|
+
```text
|
|
244
|
+
0 1 2 | 3
|
|
245
|
+
↑
|
|
246
|
+
boundary
|
|
247
|
+
|
|
248
|
+
next start = 4
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
The gap gives the previous Insertion its own endpoint without making that endpoint the identity of the next independent Insertion.
|
|
252
|
+
|
|
253
|
+
Positive and reducing history use separate Sessions.
|
|
254
|
+
|
|
255
|
+
Session identifiers are also separate from Actor identifiers. Two replicas belonging to the same Actor can author their own Sessions without sharing one sequencing clock.
|
|
256
|
+
|
|
257
|
+
## Structural Order
|
|
258
|
+
|
|
259
|
+
Every materialized Insertion is placed into one Structural Order.
|
|
260
|
+
|
|
261
|
+
Suppose the original history is:
|
|
262
|
+
|
|
263
|
+
```text
|
|
264
|
+
A B
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
and a new Insertion anchors between them:
|
|
268
|
+
|
|
269
|
+
```text
|
|
270
|
+
A | B
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Structural Order can now represent:
|
|
274
|
+
|
|
275
|
+
```text
|
|
276
|
+
A X B
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
If another replica concurrently inserts `Y` at the same anchor, both new Insertions describe the same historical point:
|
|
280
|
+
|
|
281
|
+
```text
|
|
282
|
+
A | B
|
|
283
|
+
X
|
|
284
|
+
Y
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
They must get the same order on every replica even when they arrive in different orders.
|
|
288
|
+
|
|
289
|
+
Sequencer orders competing Insertions from the anchor outward by:
|
|
290
|
+
|
|
291
|
+
1. positive Insertions before reducing Insertions;
|
|
292
|
+
2. greater Session first;
|
|
293
|
+
3. within the same Session, greater start first.
|
|
294
|
+
|
|
295
|
+
So receiving:
|
|
296
|
+
|
|
297
|
+
```text
|
|
298
|
+
X
|
|
299
|
+
Y
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
or:
|
|
303
|
+
|
|
304
|
+
```text
|
|
305
|
+
Y
|
|
306
|
+
X
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
produces the same Structural Order once both are known.
|
|
310
|
+
|
|
311
|
+
## Causal subtrees
|
|
312
|
+
|
|
313
|
+
An Insertion can have more history attached to it.
|
|
314
|
+
|
|
315
|
+
Suppose two replicas start from an empty sequence.
|
|
316
|
+
|
|
317
|
+
One creates:
|
|
318
|
+
|
|
319
|
+
```text
|
|
320
|
+
Project notes
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
and continues editing it.
|
|
324
|
+
|
|
325
|
+
The other independently creates:
|
|
326
|
+
|
|
327
|
+
```text
|
|
328
|
+
Shopping list
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
and continues editing that.
|
|
332
|
+
|
|
333
|
+
The two initial Insertions compete at the root.
|
|
334
|
+
|
|
335
|
+
Their later edits are descendants of those roots:
|
|
336
|
+
|
|
337
|
+
```text
|
|
338
|
+
Project notes
|
|
339
|
+
├─ child
|
|
340
|
+
└─ child
|
|
341
|
+
|
|
342
|
+
Shopping list
|
|
343
|
+
├─ child
|
|
344
|
+
└─ child
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
When the roots are ordered, their descendants stay with them:
|
|
348
|
+
|
|
349
|
+
```text
|
|
350
|
+
[Project notes subtree]
|
|
351
|
+
[Shopping list subtree]
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
rather than becoming interleaved:
|
|
355
|
+
|
|
356
|
+
```text
|
|
357
|
+
part of Project notes
|
|
358
|
+
part of Shopping list
|
|
359
|
+
rest of Project notes
|
|
360
|
+
rest of Shopping list
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
When a competitor is inserted into Structural Order, its place is determined relative to the complete subtree of the competitors already there.
|
|
364
|
+
|
|
365
|
+
## History can arrive before its parent
|
|
366
|
+
|
|
367
|
+
Suppose one replica creates:
|
|
368
|
+
|
|
369
|
+
```text
|
|
370
|
+
Hello
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
and then inserts:
|
|
374
|
+
|
|
375
|
+
```text
|
|
376
|
+
world
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
after it.
|
|
380
|
+
|
|
381
|
+
The second Insertion anchors to the first.
|
|
382
|
+
|
|
383
|
+
Another replica may receive:
|
|
384
|
+
|
|
385
|
+
```text
|
|
386
|
+
world
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
before:
|
|
390
|
+
|
|
391
|
+
```text
|
|
392
|
+
Hello
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
There is not yet anything local that can resolve the anchor.
|
|
396
|
+
|
|
397
|
+
The Insertion waits.
|
|
398
|
+
|
|
399
|
+
When `Hello` arrives, its identity becomes available and the waiting Insertion can be placed:
|
|
400
|
+
|
|
401
|
+
```text
|
|
402
|
+
Hello world
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
The same thing can happen when the parent exists but has not yet grown far enough to contain the referenced logical point.
|
|
406
|
+
|
|
407
|
+
The relationship itself does not change while it waits.
|
|
408
|
+
|
|
409
|
+
## Author-time relationships
|
|
410
|
+
|
|
411
|
+
This allows edits to describe the sequence as it existed when they were authored without requiring another replica to pass through the same intermediate states.
|
|
412
|
+
|
|
413
|
+
For example, one replica may produce:
|
|
414
|
+
|
|
415
|
+
```text
|
|
416
|
+
world
|
|
417
|
+
Hello world
|
|
418
|
+
Well, Hello world
|
|
419
|
+
Well, actually Hello world
|
|
420
|
+
Now, Well, actually Hello world
|
|
421
|
+
Okay, Now, Well, actually Hello world
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
Another replica might receive the Insertions in this order:
|
|
425
|
+
|
|
426
|
+
```text
|
|
427
|
+
world
|
|
428
|
+
Hello
|
|
429
|
+
actually
|
|
430
|
+
Now
|
|
431
|
+
Well
|
|
432
|
+
Okay
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
`actually` is still attached to the historical Insertion it followed when it was authored.
|
|
436
|
+
|
|
437
|
+
Once the required history has arrived, the relationships can be resolved into:
|
|
438
|
+
|
|
439
|
+
```text
|
|
440
|
+
Okay, Now, Well, actually Hello world
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
## Strips
|
|
444
|
+
|
|
445
|
+
An Insertion does not always stay in one piece inside a running Projection.
|
|
446
|
+
|
|
447
|
+
Suppose an original Insertion contains:
|
|
448
|
+
|
|
449
|
+
```text
|
|
450
|
+
A B C D
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
An edit at the middle may split its runtime representation into:
|
|
454
|
+
|
|
455
|
+
```text
|
|
456
|
+
[A B] [C D]
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
These pieces are **Strips**.
|
|
460
|
+
|
|
461
|
+
Both Strips still belong to the same original Insertion.
|
|
462
|
+
|
|
463
|
+
The original coordinate space is still:
|
|
464
|
+
|
|
465
|
+
```text
|
|
466
|
+
| A | B | C | D |
|
|
467
|
+
0 1 2 3 4
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
The left Strip represents one part of that space and the right Strip represents another.
|
|
471
|
+
|
|
472
|
+
An operation authored earlier against point `3` can still find point `3` even though the original Insertion is no longer represented by one Strip.
|
|
473
|
+
|
|
474
|
+
Different replicas can also have different fragmentation.
|
|
475
|
+
|
|
476
|
+
One might currently have:
|
|
477
|
+
|
|
478
|
+
```text
|
|
479
|
+
[A B C D]
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
while another has:
|
|
483
|
+
|
|
484
|
+
```text
|
|
485
|
+
[A] [B C] [D]
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
They still agree on the original Insertion and its coordinates.
|
|
489
|
+
|
|
490
|
+
## Extending an Insertion
|
|
491
|
+
|
|
492
|
+
Consecutive editing often continues the Insertion that was just created.
|
|
493
|
+
|
|
494
|
+
Typing:
|
|
495
|
+
|
|
496
|
+
```text
|
|
497
|
+
H
|
|
498
|
+
He
|
|
499
|
+
Hel
|
|
500
|
+
Hell
|
|
501
|
+
Hello
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
does not need five unrelated canonical Insertions.
|
|
505
|
+
|
|
506
|
+
When the new content is a clean continuation of the latest local positive Insertion, its original extent can grow:
|
|
507
|
+
|
|
508
|
+
```text
|
|
509
|
+
H
|
|
510
|
+
↓
|
|
511
|
+
He
|
|
512
|
+
↓
|
|
513
|
+
Hel
|
|
514
|
+
↓
|
|
515
|
+
Hell
|
|
516
|
+
↓
|
|
517
|
+
Hello
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
The continuation starts at the old endpoint of the same Session, so another replica can recognize it as an extension of the existing Insertion.
|
|
521
|
+
|
|
522
|
+
This is only done while the old endpoint can safely grow.
|
|
523
|
+
|
|
524
|
+
If other history already depends on that endpoint in a way that would change its ordering, the new content becomes a normal separate Insertion instead.
|
|
525
|
+
|
|
526
|
+
An Insertion can also be extended after it has fragmented. The new suffix may need its own Strip, but it still belongs to the same canonical Insertion.
|
|
527
|
+
|
|
528
|
+
## Removal
|
|
529
|
+
|
|
530
|
+
Removal is represented by reducing Insertions.
|
|
531
|
+
|
|
532
|
+
Suppose one positive Insertion contains:
|
|
533
|
+
|
|
534
|
+
```text
|
|
535
|
+
A B C D
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
and `B C` are removed.
|
|
539
|
+
|
|
540
|
+
The removal anchors to the original positive Insertion and covers those original Frames:
|
|
541
|
+
|
|
542
|
+
```text
|
|
543
|
+
original
|
|
544
|
+
|
|
545
|
+
A B C D
|
|
546
|
+
└─┬─┘
|
|
547
|
+
removed
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
The Projection becomes:
|
|
551
|
+
|
|
552
|
+
```text
|
|
553
|
+
A D
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
The original coordinates still exist in Structural Order.
|
|
557
|
+
|
|
558
|
+
This becomes especially useful when insertion and removal happen concurrently.
|
|
559
|
+
|
|
560
|
+
Suppose both replicas start with:
|
|
561
|
+
|
|
562
|
+
```text
|
|
563
|
+
The old house
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
Replica A removes:
|
|
567
|
+
|
|
568
|
+
```text
|
|
569
|
+
old
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
and sees:
|
|
573
|
+
|
|
574
|
+
```text
|
|
575
|
+
The house
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
At the same time Replica B inserts:
|
|
579
|
+
|
|
580
|
+
```text
|
|
581
|
+
small
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
after `old `:
|
|
585
|
+
|
|
586
|
+
```text
|
|
587
|
+
The old small house
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
The removal authored by A refers to the original Frames of `old `.
|
|
591
|
+
|
|
592
|
+
It never referred to `small ` because those Frames did not exist in A's history.
|
|
593
|
+
|
|
594
|
+
After synchronization:
|
|
595
|
+
|
|
596
|
+
```text
|
|
597
|
+
The small house
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
The concurrent insertion survives.
|
|
601
|
+
|
|
602
|
+
## A removal can cross several Insertions
|
|
603
|
+
|
|
604
|
+
A visible range can contain Frames from several original Insertions.
|
|
605
|
+
|
|
606
|
+
For example, the Projection:
|
|
607
|
+
|
|
608
|
+
```text
|
|
609
|
+
Hello world
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
might have been built from:
|
|
613
|
+
|
|
614
|
+
```text
|
|
615
|
+
[Hello] [ ] [world]
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
Removing:
|
|
619
|
+
|
|
620
|
+
```text
|
|
621
|
+
lo wo
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
crosses all three.
|
|
625
|
+
|
|
626
|
+
Sequencer describes the removal against the original Frames of each Insertion it crosses.
|
|
627
|
+
|
|
628
|
+
The visible edit is one range, but its historical description can contain several reducing Insertions.
|
|
629
|
+
|
|
630
|
+
## Removal fragments
|
|
631
|
+
|
|
632
|
+
A reducing Insertion can also become fragmented.
|
|
633
|
+
|
|
634
|
+
Suppose an original positive Insertion contains:
|
|
635
|
+
|
|
636
|
+
```text
|
|
637
|
+
A B C D E F
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
and its current structural representation has already become:
|
|
641
|
+
|
|
642
|
+
```text
|
|
643
|
+
[A B] [C D] [E F]
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
A removal covering:
|
|
647
|
+
|
|
648
|
+
```text
|
|
649
|
+
B C D E
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
may need mask fragments at several places in Structural Order.
|
|
653
|
+
|
|
654
|
+
Those mask Strips still belong to one canonical reducing Insertion.
|
|
655
|
+
|
|
656
|
+
Its identity and original target coordinates do not change.
|
|
657
|
+
|
|
658
|
+
## Overlapping removals
|
|
659
|
+
|
|
660
|
+
Two replicas can remove some of the same original Frames.
|
|
661
|
+
|
|
662
|
+
Starting from:
|
|
663
|
+
|
|
664
|
+
```text
|
|
665
|
+
the brown fox jumps
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
one replica might remove:
|
|
669
|
+
|
|
670
|
+
```text
|
|
671
|
+
brown fox
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
while another removes:
|
|
675
|
+
|
|
676
|
+
```text
|
|
677
|
+
fox jumps
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
Both target the original Frames of `fox`.
|
|
681
|
+
|
|
682
|
+
When the second removal is integrated, those Frames may already be masked.
|
|
683
|
+
|
|
684
|
+
They cannot reduce the Projection again.
|
|
685
|
+
|
|
686
|
+
The reducing Insertion still describes the range it originally targeted, while its runtime effect is limited to original Frames that remain available for it to consume.
|
|
687
|
+
|
|
688
|
+
This lets overlapping removals arrive in either order without changing the result.
|
|
689
|
+
|
|
690
|
+
## Replacement
|
|
691
|
+
|
|
692
|
+
Replacement is a removal followed by a positive Insertion.
|
|
693
|
+
|
|
694
|
+
Changing:
|
|
695
|
+
|
|
696
|
+
```text
|
|
697
|
+
Draft
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
to:
|
|
701
|
+
|
|
702
|
+
```text
|
|
703
|
+
Final
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
first masks the Frames of:
|
|
707
|
+
|
|
708
|
+
```text
|
|
709
|
+
Draft
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
and then anchors:
|
|
713
|
+
|
|
714
|
+
```text
|
|
715
|
+
Final
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
into the resulting history.
|
|
719
|
+
|
|
720
|
+
Both parts use the same insertion and removal rules as every other edit.
|
|
721
|
+
|
|
722
|
+
## Actors and acknowledgements
|
|
723
|
+
|
|
724
|
+
Removal history cannot always be discarded when it disappears from the Projection.
|
|
725
|
+
|
|
726
|
+
Suppose one replica removes some Frames while another replica is offline.
|
|
727
|
+
|
|
728
|
+
The offline replica may still have unsent history anchored to those Frames.
|
|
729
|
+
|
|
730
|
+
The removed Frames must remain addressable until that old history no longer needs to be supported.
|
|
731
|
+
|
|
732
|
+
Actors report how far they have observed each reducing Session.
|
|
733
|
+
|
|
734
|
+
For example:
|
|
735
|
+
|
|
736
|
+
```text
|
|
737
|
+
Actor 3
|
|
738
|
+
|
|
739
|
+
removal Session 17
|
|
740
|
+
observed through logical time 42
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
The reported point is a **frontier**.
|
|
744
|
+
|
|
745
|
+
A single frontier summarizes a received prefix of a Session rather than acknowledging every reducing Insertion separately.
|
|
746
|
+
|
|
747
|
+
## Compaction
|
|
748
|
+
|
|
749
|
+
When all active Actors agree on the same frontier for a reducing Session, the acknowledged part can be removed from future retained Sequences.
|
|
750
|
+
|
|
751
|
+
Suppose history contains:
|
|
752
|
+
|
|
753
|
+
```text
|
|
754
|
+
positive Frames
|
|
755
|
+
removal mask
|
|
756
|
+
surviving descendants
|
|
757
|
+
```
|
|
758
|
+
|
|
759
|
+
and every active Actor has seen the removal.
|
|
760
|
+
|
|
761
|
+
A new retained Sequence no longer needs to preserve all of the machinery that represented that deletion.
|
|
762
|
+
|
|
763
|
+
Compaction can remove the acknowledged masks and remove deleted Frames from retained Footage.
|
|
764
|
+
|
|
765
|
+
If only part of a positive Insertion was deleted:
|
|
766
|
+
|
|
767
|
+
```text
|
|
768
|
+
A B C D
|
|
769
|
+
```
|
|
770
|
+
|
|
771
|
+
with:
|
|
772
|
+
|
|
773
|
+
```text
|
|
774
|
+
B C
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
gone, the retained positive history can shrink to the surviving content:
|
|
778
|
+
|
|
779
|
+
```text
|
|
780
|
+
A D
|
|
781
|
+
```
|
|
782
|
+
|
|
783
|
+
Anchors and remaining removals that referred to the old coordinates are adjusted to the smaller retained coordinate space.
|
|
784
|
+
|
|
785
|
+
The running Projection does not need to be rewritten when this happens. Compaction produces another retained description of the same history.
|
|
786
|
+
|
|
787
|
+
## Collapsed historical points
|
|
788
|
+
|
|
789
|
+
Compaction can make two old logical points collapse onto the same retained point.
|
|
790
|
+
|
|
791
|
+
Imagine:
|
|
792
|
+
|
|
793
|
+
```text
|
|
794
|
+
A | removed Frames | B
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
with surviving descendants attached on both sides of the removed region.
|
|
798
|
+
|
|
799
|
+
Before compaction those descendants were separated by different historical coordinates.
|
|
800
|
+
|
|
801
|
+
After the deleted Frames disappear from retained history, that space no longer exists.
|
|
802
|
+
|
|
803
|
+
Their order has already been resolved in Structural Order, so the compacted history keeps that order when it re-anchors the survivors around the remaining boundary.
|
|
804
|
+
|
|
805
|
+
The discarded history is no longer needed to make the same ordering decision again.
|
|
806
|
+
|
|
807
|
+
## Actor retirement
|
|
808
|
+
|
|
809
|
+
An Actor that will never return would otherwise remain part of acknowledgement consensus forever.
|
|
810
|
+
|
|
811
|
+
Retiring an Actor removes it from future compaction requirements.
|
|
812
|
+
|
|
813
|
+
It does not remove Insertions authored by that Actor.
|
|
814
|
+
|
|
815
|
+
It only changes which Actors must agree before old removal history can be discarded.
|
|
816
|
+
|
|
817
|
+
Whether an Actor is permanently gone is something the surrounding application has to decide.
|
|
818
|
+
|
|
819
|
+
## Sequence
|
|
820
|
+
|
|
821
|
+
A retained **Sequence** stores enough history to reconstruct the Projection later.
|
|
822
|
+
|
|
823
|
+
It contains canonical Insertion history, acknowledgement frontiers and the Footage belonging to surviving positive history.
|
|
824
|
+
|
|
825
|
+
Runtime fragmentation is not persisted as separate Insertions.
|
|
826
|
+
|
|
827
|
+
If one canonical Insertion currently exists as:
|
|
828
|
+
|
|
829
|
+
```text
|
|
830
|
+
[A] [B C] [D]
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
the retained history still describes the one original Insertion:
|
|
834
|
+
|
|
835
|
+
```text
|
|
836
|
+
A B C D
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
along with the other canonical history that caused its current result.
|
|
840
|
+
|
|
841
|
+
The next runtime can fragment it again as needed.
|
|
842
|
+
|
|
843
|
+
## Hydration
|
|
844
|
+
|
|
845
|
+
Loading a Sequence rebuilds Structural Order and derives the Projection from it.
|
|
846
|
+
|
|
847
|
+
A hydrated runtime does not need to reproduce the exact Strip layout of the runtime that saved the Sequence.
|
|
848
|
+
|
|
849
|
+
For example, the old runtime may have ended with:
|
|
850
|
+
|
|
851
|
+
```text
|
|
852
|
+
[A] [B C] [D]
|
|
853
|
+
```
|
|
854
|
+
|
|
855
|
+
while the new one initially materializes:
|
|
856
|
+
|
|
857
|
+
```text
|
|
858
|
+
[A B C D]
|
|
859
|
+
```
|
|
860
|
+
|
|
861
|
+
If later history needs a boundary inside it, it can split again.
|
|
862
|
+
|
|
863
|
+
Both represent the same canonical Insertion.
|
|
864
|
+
|
|
865
|
+
The visible sequence and the relationships available to future edits remain the same.
|
|
866
|
+
|
|
867
|
+
## Projection and history keep changing at different rates
|
|
868
|
+
|
|
869
|
+
A Projection can change dramatically while very little canonical history is added.
|
|
870
|
+
|
|
871
|
+
A long contiguous typing session may extend one positive Insertion.
|
|
872
|
+
|
|
873
|
+
A removal can hide many Frames while leaving the positive Insertion itself in history.
|
|
874
|
+
|
|
875
|
+
Compaction can later make retained history smaller without changing the Projection at all.
|
|
876
|
+
|
|
877
|
+
So these are separate views of the same sequence:
|
|
878
|
+
|
|
879
|
+
```text
|
|
880
|
+
Projection
|
|
881
|
+
```
|
|
882
|
+
|
|
883
|
+
is the content visible now.
|
|
884
|
+
|
|
885
|
+
```text
|
|
886
|
+
Structural Order
|
|
887
|
+
```
|
|
888
|
+
|
|
889
|
+
is the history currently needed to resolve ordering and removals.
|
|
890
|
+
|
|
891
|
+
```text
|
|
892
|
+
Sequence
|
|
893
|
+
```
|
|
894
|
+
|
|
895
|
+
is the retained form of that history, with acknowledged obsolete history compacted away when possible.
|
|
896
|
+
|
|
897
|
+
An edit starts from the Projection, becomes a relationship in Structural Order, and can eventually survive in a much smaller retained Sequence after the history around it is no longer needed.
|