@sovereignbase/sequencer 1.0.0 → 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 +324 -957
- package/README.md +19 -5
- package/dist/index.cjs +44 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +29 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +44 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/INTERNALS.md
CHANGED
|
@@ -1,50 +1,34 @@
|
|
|
1
|
-
# How
|
|
1
|
+
# How sequencer works
|
|
2
2
|
|
|
3
|
-
Sequencer
|
|
3
|
+
Sequencer keeps an ordered sequence synchronized between replicas.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Applications see a normal indexed sequence:
|
|
6
6
|
|
|
7
7
|
```text
|
|
8
8
|
A B C D
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
with positions:
|
|
12
12
|
|
|
13
13
|
```text
|
|
14
|
-
|
|
15
|
-
remove 1..3
|
|
16
|
-
replace 4..6
|
|
14
|
+
0 1 2 3
|
|
17
15
|
```
|
|
18
16
|
|
|
19
|
-
|
|
17
|
+
Internally Sequencer cannot use those positions to describe replicated edits.
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
Sequencer solves this by translating every local edit from a temporary visible position into a stable relationship with existing history.
|
|
24
|
-
|
|
25
|
-
The basic model is:
|
|
19
|
+
If another Frame is inserted before `B`:
|
|
26
20
|
|
|
27
21
|
```text
|
|
28
|
-
|
|
29
|
-
↓
|
|
30
|
-
historical logical point
|
|
31
|
-
↓
|
|
32
|
-
canonical Insertion
|
|
33
|
-
↓
|
|
34
|
-
deterministic Structural Order
|
|
35
|
-
↓
|
|
36
|
-
visible Projection
|
|
22
|
+
A X B C D
|
|
37
23
|
```
|
|
38
24
|
|
|
39
|
-
|
|
25
|
+
`B` moves from position `1` to position `2`.
|
|
40
26
|
|
|
41
|
-
|
|
27
|
+
Instead, when an edit is made, Sequencer finds the existing history around that position and records the edit relative to it.
|
|
42
28
|
|
|
43
|
-
|
|
29
|
+
## Projection and Structural Order
|
|
44
30
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
The **Projection** is what the application sees.
|
|
31
|
+
The **Projection** is the sequence the application currently sees.
|
|
48
32
|
|
|
49
33
|
For example:
|
|
50
34
|
|
|
@@ -52,15 +36,13 @@ For example:
|
|
|
52
36
|
A B C D
|
|
53
37
|
```
|
|
54
38
|
|
|
55
|
-
|
|
39
|
+
has four visible Frames:
|
|
56
40
|
|
|
57
41
|
```text
|
|
58
42
|
A B C D
|
|
59
43
|
0 1 2 3
|
|
60
44
|
```
|
|
61
45
|
|
|
62
|
-
Applications read and edit these visible positions.
|
|
63
|
-
|
|
64
46
|
Insertion positions are boundaries between Frames:
|
|
65
47
|
|
|
66
48
|
```text
|
|
@@ -68,80 +50,37 @@ Insertion positions are boundaries between Frames:
|
|
|
68
50
|
0 1 2 3 4
|
|
69
51
|
```
|
|
70
52
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
A Frame position identifies visible content.
|
|
74
|
-
|
|
75
|
-
A boundary identifies a place where new history can be attached.
|
|
76
|
-
|
|
77
|
-
Projection positions are deliberately temporary. They describe the current visible result, not the permanent identity of anything inside it.
|
|
78
|
-
|
|
79
|
-
---
|
|
80
|
-
|
|
81
|
-
## History must use stable coordinates
|
|
82
|
-
|
|
83
|
-
Suppose two replicas begin with:
|
|
84
|
-
|
|
85
|
-
```text
|
|
86
|
-
A B
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
Replica 1 inserts:
|
|
53
|
+
Behind the Projection is **Structural Order**.
|
|
90
54
|
|
|
91
|
-
|
|
92
|
-
X
|
|
93
|
-
```
|
|
55
|
+
Structural Order contains the Insertions that produced the sequence, including history that may no longer be visible.
|
|
94
56
|
|
|
95
|
-
|
|
57
|
+
A simple sequence might start as:
|
|
96
58
|
|
|
97
59
|
```text
|
|
98
|
-
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
At the same time, Replica 2 inserts:
|
|
60
|
+
Structural Order
|
|
102
61
|
|
|
103
|
-
|
|
104
|
-
Y
|
|
105
|
-
```
|
|
62
|
+
[A B C D]
|
|
106
63
|
|
|
107
|
-
|
|
64
|
+
Projection
|
|
108
65
|
|
|
109
|
-
|
|
110
|
-
A Y B
|
|
66
|
+
A B C D
|
|
111
67
|
```
|
|
112
68
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
If Sequencer replicated only:
|
|
69
|
+
After `B C` are removed, the Projection becomes:
|
|
116
70
|
|
|
117
71
|
```text
|
|
118
|
-
|
|
119
|
-
insert Y at 1
|
|
72
|
+
A D
|
|
120
73
|
```
|
|
121
74
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
Instead, both edits are translated into a relationship with the same historical boundary between `A` and `B`.
|
|
125
|
-
|
|
126
|
-
That boundary remains meaningful even after the visible sequence changes.
|
|
75
|
+
but Structural Order still contains the original positive Insertion and the history describing the removal.
|
|
127
76
|
|
|
128
|
-
|
|
77
|
+
More history can later attach to those original coordinates, so hidden history may remain useful long after its Frames disappear from the Projection.
|
|
129
78
|
|
|
130
|
-
|
|
79
|
+
## Insertions
|
|
131
80
|
|
|
132
|
-
|
|
81
|
+
History is made of **Insertions**.
|
|
133
82
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
Conceptually, every Insertion contains:
|
|
137
|
-
|
|
138
|
-
```text
|
|
139
|
-
where it belongs
|
|
140
|
-
+
|
|
141
|
-
what history it introduces
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
Its canonical coordinates are:
|
|
83
|
+
An Insertion has six coordinates:
|
|
145
84
|
|
|
146
85
|
```text
|
|
147
86
|
anchorSession
|
|
@@ -153,399 +92,325 @@ insertionStart
|
|
|
153
92
|
insertionDiff
|
|
154
93
|
```
|
|
155
94
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
The anchor:
|
|
95
|
+
The first three describe where the Insertion belongs:
|
|
159
96
|
|
|
160
97
|
```text
|
|
161
98
|
(anchorSession, anchorStart, anchorDiff)
|
|
162
99
|
```
|
|
163
100
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
The identity:
|
|
101
|
+
The next two identify the Insertion:
|
|
167
102
|
|
|
168
103
|
```text
|
|
169
104
|
(insertionSession, insertionStart)
|
|
170
105
|
```
|
|
171
106
|
|
|
172
|
-
describes
|
|
107
|
+
and `insertionDiff` describes its original Frame length and whether it adds or removes Frames.
|
|
173
108
|
|
|
174
|
-
|
|
109
|
+
A positive Insertion adds Frames:
|
|
175
110
|
|
|
176
111
|
```text
|
|
177
|
-
insertionDiff
|
|
112
|
+
insertionDiff = 4
|
|
178
113
|
```
|
|
179
114
|
|
|
180
|
-
|
|
115
|
+
A reducing Insertion masks Frames:
|
|
181
116
|
|
|
182
|
-
|
|
117
|
+
```text
|
|
118
|
+
insertionDiff = -4
|
|
119
|
+
```
|
|
183
120
|
|
|
184
|
-
|
|
121
|
+
Positive Insertions can also carry **Footage**, which contains the actual values.
|
|
185
122
|
|
|
186
|
-
|
|
123
|
+
Sequencer orders the Insertion. Footage is what eventually appears in the Projection.
|
|
187
124
|
|
|
188
|
-
##
|
|
125
|
+
## Frames and logical points
|
|
189
126
|
|
|
190
|
-
|
|
127
|
+
Suppose one Insertion contains:
|
|
191
128
|
|
|
192
129
|
```text
|
|
193
|
-
|
|
130
|
+
A B C
|
|
194
131
|
```
|
|
195
132
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
This means:
|
|
133
|
+
It has three Frames:
|
|
199
134
|
|
|
200
135
|
```text
|
|
201
|
-
|
|
136
|
+
A B C
|
|
137
|
+
0 1 2
|
|
202
138
|
```
|
|
203
139
|
|
|
204
|
-
and:
|
|
140
|
+
and four logical points:
|
|
205
141
|
|
|
206
142
|
```text
|
|
207
|
-
|
|
143
|
+
| A | B | C |
|
|
144
|
+
0 1 2 3
|
|
208
145
|
```
|
|
209
146
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
That separation is useful for several reasons.
|
|
213
|
-
|
|
214
|
-
The same operation can be recognized after retransmission.
|
|
215
|
-
|
|
216
|
-
Fragments of one Insertion still belong to the same canonical identity.
|
|
217
|
-
|
|
218
|
-
An Insertion can be found independently from whichever Strip currently represents its anchor.
|
|
219
|
-
|
|
220
|
-
And duplicate delivery does not create duplicate visible content.
|
|
221
|
-
|
|
222
|
-
---
|
|
223
|
-
|
|
224
|
-
# Logical time
|
|
225
|
-
|
|
226
|
-
Every sequencing Session owns its own logical coordinate space.
|
|
227
|
-
|
|
228
|
-
A newly authored Insertion receives a start position inside that Session.
|
|
147
|
+
An anchor points to one of these boundaries.
|
|
229
148
|
|
|
230
149
|
For example:
|
|
231
150
|
|
|
232
151
|
```text
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
Insertion A starts at 0
|
|
236
|
-
Insertion B starts at 6
|
|
237
|
-
Insertion C starts at 11
|
|
152
|
+
anchorDiff = 2
|
|
238
153
|
```
|
|
239
154
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
They are logical coordinates used only to identify history.
|
|
243
|
-
|
|
244
|
-
A canonical Insertion normally reserves both:
|
|
155
|
+
refers to:
|
|
245
156
|
|
|
246
157
|
```text
|
|
247
|
-
|
|
248
|
-
+
|
|
249
|
-
a following logical boundary
|
|
158
|
+
A B | C
|
|
250
159
|
```
|
|
251
160
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
That following boundary gives later history a stable point to reference.
|
|
255
|
-
|
|
256
|
-
---
|
|
257
|
-
|
|
258
|
-
## Frames and logical points are different
|
|
161
|
+
inside that original Insertion.
|
|
259
162
|
|
|
260
|
-
|
|
163
|
+
If later edits move `C` somewhere else in the Projection, this point is still point `2` of the same original Insertion.
|
|
261
164
|
|
|
262
|
-
|
|
263
|
-
A B C
|
|
264
|
-
```
|
|
165
|
+
## Anchoring an edit
|
|
265
166
|
|
|
266
|
-
|
|
167
|
+
Suppose the Projection contains:
|
|
267
168
|
|
|
268
169
|
```text
|
|
269
|
-
|
|
170
|
+
Hello world
|
|
270
171
|
```
|
|
271
172
|
|
|
272
|
-
|
|
173
|
+
and `big ` is inserted here:
|
|
273
174
|
|
|
274
175
|
```text
|
|
275
|
-
|
|
276
|
-
0 1 2 3
|
|
176
|
+
Hello | world
|
|
277
177
|
```
|
|
278
178
|
|
|
279
|
-
|
|
179
|
+
Sequencer first finds which original Insertion owns that boundary.
|
|
280
180
|
|
|
281
|
-
|
|
181
|
+
If the boundary is point `6` of an Insertion identified by:
|
|
282
182
|
|
|
283
183
|
```text
|
|
284
|
-
|
|
184
|
+
(session 4, start 20)
|
|
285
185
|
```
|
|
286
186
|
|
|
287
|
-
|
|
187
|
+
the new Insertion can anchor to:
|
|
288
188
|
|
|
289
189
|
```text
|
|
290
|
-
|
|
190
|
+
anchorSession = 4
|
|
191
|
+
anchorStart = 20
|
|
192
|
+
anchorDiff = 6
|
|
291
193
|
```
|
|
292
194
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
It does **not** mean:
|
|
195
|
+
Another replica might currently see:
|
|
296
196
|
|
|
297
197
|
```text
|
|
298
|
-
|
|
198
|
+
Well, Hello world
|
|
299
199
|
```
|
|
300
200
|
|
|
301
|
-
|
|
201
|
+
The same anchor still refers to the point after `Hello ` in the original Insertion.
|
|
302
202
|
|
|
303
|
-
|
|
203
|
+
The Projection position is different, but the relationship is the same.
|
|
304
204
|
|
|
305
|
-
|
|
205
|
+
## Insertion identity
|
|
306
206
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
# From a local edit to canonical history
|
|
310
|
-
|
|
311
|
-
Suppose the current Projection is:
|
|
207
|
+
An Insertion is identified by:
|
|
312
208
|
|
|
313
209
|
```text
|
|
314
|
-
|
|
210
|
+
(insertionSession, insertionStart)
|
|
315
211
|
```
|
|
316
212
|
|
|
317
|
-
|
|
213
|
+
The anchor is not part of its identity.
|
|
318
214
|
|
|
319
|
-
|
|
320
|
-
big
|
|
321
|
-
```
|
|
215
|
+
If the same Insertion arrives twice, both copies have the same identity.
|
|
322
216
|
|
|
323
|
-
|
|
217
|
+
Sequencer can keep the first and ignore the duplicate instead of inserting the same content twice.
|
|
324
218
|
|
|
325
|
-
|
|
326
|
-
Hello | world
|
|
327
|
-
```
|
|
219
|
+
Fragments of an Insertion also keep this identity. Splitting an Insertion at runtime does not create new replicated history.
|
|
328
220
|
|
|
329
|
-
|
|
221
|
+
## Sessions
|
|
330
222
|
|
|
331
|
-
|
|
223
|
+
Insertions are authored inside **Sessions**.
|
|
332
224
|
|
|
333
|
-
|
|
225
|
+
A Session has its own logical time.
|
|
334
226
|
|
|
335
|
-
|
|
336
|
-
specific historical Insertion
|
|
337
|
-
+
|
|
338
|
-
specific logical point inside it
|
|
339
|
-
```
|
|
227
|
+
Suppose a Session creates a three-Frame Insertion starting at `0`.
|
|
340
228
|
|
|
341
|
-
|
|
229
|
+
Its Frame coordinates occupy:
|
|
342
230
|
|
|
343
231
|
```text
|
|
344
|
-
|
|
232
|
+
0 1 2
|
|
345
233
|
```
|
|
346
234
|
|
|
347
|
-
|
|
235
|
+
and its endpoint is:
|
|
348
236
|
|
|
349
237
|
```text
|
|
350
|
-
|
|
238
|
+
3
|
|
351
239
|
```
|
|
352
240
|
|
|
353
|
-
|
|
241
|
+
A new independent Insertion normally starts after another reserved logical point:
|
|
354
242
|
|
|
355
|
-
|
|
243
|
+
```text
|
|
244
|
+
0 1 2 | 3
|
|
245
|
+
↑
|
|
246
|
+
boundary
|
|
356
247
|
|
|
357
|
-
|
|
248
|
+
next start = 4
|
|
249
|
+
```
|
|
358
250
|
|
|
359
|
-
|
|
251
|
+
The gap gives the previous Insertion its own endpoint without making that endpoint the identity of the next independent Insertion.
|
|
360
252
|
|
|
361
|
-
|
|
253
|
+
Positive and reducing history use separate Sessions.
|
|
362
254
|
|
|
363
|
-
|
|
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.
|
|
364
256
|
|
|
365
|
-
|
|
257
|
+
## Structural Order
|
|
366
258
|
|
|
367
|
-
|
|
259
|
+
Every materialized Insertion is placed into one Structural Order.
|
|
368
260
|
|
|
369
|
-
|
|
261
|
+
Suppose the original history is:
|
|
370
262
|
|
|
371
263
|
```text
|
|
372
|
-
|
|
373
|
-
removal history
|
|
374
|
-
fragments
|
|
375
|
-
concurrent siblings
|
|
376
|
-
causal descendants
|
|
377
|
-
hidden historical boundaries
|
|
264
|
+
A B
|
|
378
265
|
```
|
|
379
266
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
Conceptually:
|
|
267
|
+
and a new Insertion anchors between them:
|
|
383
268
|
|
|
384
269
|
```text
|
|
385
|
-
|
|
386
|
-
↓
|
|
387
|
-
surviving positive Frames
|
|
388
|
-
↓
|
|
389
|
-
Projection
|
|
270
|
+
A | B
|
|
390
271
|
```
|
|
391
272
|
|
|
392
|
-
Structural Order
|
|
393
|
-
|
|
394
|
-
The Projection answers:
|
|
273
|
+
Structural Order can now represent:
|
|
395
274
|
|
|
396
275
|
```text
|
|
397
|
-
|
|
276
|
+
A X B
|
|
398
277
|
```
|
|
399
278
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
```text
|
|
403
|
-
what historical relationships produced that result?
|
|
404
|
-
```
|
|
405
|
-
|
|
406
|
-
---
|
|
407
|
-
|
|
408
|
-
# Concurrent Insertions
|
|
409
|
-
|
|
410
|
-
Two Insertions directly compete when they use exactly the same canonical anchor.
|
|
411
|
-
|
|
412
|
-
For example, both of these may attach to:
|
|
279
|
+
If another replica concurrently inserts `Y` at the same anchor, both new Insertions describe the same historical point:
|
|
413
280
|
|
|
414
281
|
```text
|
|
415
282
|
A | B
|
|
283
|
+
X
|
|
284
|
+
Y
|
|
416
285
|
```
|
|
417
286
|
|
|
418
|
-
|
|
287
|
+
They must get the same order on every replica even when they arrive in different orders.
|
|
419
288
|
|
|
420
|
-
|
|
421
|
-
X
|
|
422
|
-
Y
|
|
423
|
-
```
|
|
289
|
+
Sequencer orders competing Insertions from the anchor outward by:
|
|
424
290
|
|
|
425
|
-
|
|
291
|
+
1. positive Insertions before reducing Insertions;
|
|
292
|
+
2. greater Session first;
|
|
293
|
+
3. within the same Session, greater start first.
|
|
426
294
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
Closer to the shared anchor:
|
|
430
|
-
|
|
431
|
-
1. positive Insertions come before reducing Insertions;
|
|
432
|
-
2. within the same sign, larger Session identifiers come first;
|
|
433
|
-
3. within the same Session, larger start coordinates come first.
|
|
434
|
-
|
|
435
|
-
Every replica can calculate this from the canonical history alone.
|
|
436
|
-
|
|
437
|
-
So one replica may receive:
|
|
295
|
+
So receiving:
|
|
438
296
|
|
|
439
297
|
```text
|
|
440
298
|
X
|
|
441
299
|
Y
|
|
442
300
|
```
|
|
443
301
|
|
|
444
|
-
|
|
302
|
+
or:
|
|
445
303
|
|
|
446
304
|
```text
|
|
447
305
|
Y
|
|
448
306
|
X
|
|
449
307
|
```
|
|
450
308
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
---
|
|
309
|
+
produces the same Structural Order once both are known.
|
|
454
310
|
|
|
455
|
-
|
|
311
|
+
## Causal subtrees
|
|
456
312
|
|
|
457
|
-
|
|
313
|
+
An Insertion can have more history attached to it.
|
|
458
314
|
|
|
459
|
-
|
|
315
|
+
Suppose two replicas start from an empty sequence.
|
|
460
316
|
|
|
461
|
-
|
|
317
|
+
One creates:
|
|
462
318
|
|
|
463
319
|
```text
|
|
464
|
-
|
|
320
|
+
Project notes
|
|
465
321
|
```
|
|
466
322
|
|
|
467
|
-
and
|
|
323
|
+
and continues editing it.
|
|
324
|
+
|
|
325
|
+
The other independently creates:
|
|
468
326
|
|
|
469
327
|
```text
|
|
470
|
-
|
|
328
|
+
Shopping list
|
|
471
329
|
```
|
|
472
330
|
|
|
473
|
-
|
|
331
|
+
and continues editing that.
|
|
474
332
|
|
|
475
|
-
The two
|
|
333
|
+
The two initial Insertions compete at the root.
|
|
476
334
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
But the descendants of each root must remain with that root.
|
|
480
|
-
|
|
481
|
-
The final Structural Order may be:
|
|
335
|
+
Their later edits are descendants of those roots:
|
|
482
336
|
|
|
483
337
|
```text
|
|
484
|
-
|
|
338
|
+
Project notes
|
|
339
|
+
├─ child
|
|
340
|
+
└─ child
|
|
485
341
|
|
|
486
|
-
|
|
342
|
+
Shopping list
|
|
343
|
+
├─ child
|
|
344
|
+
└─ child
|
|
487
345
|
```
|
|
488
346
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
It must not become:
|
|
347
|
+
When the roots are ordered, their descendants stay with them:
|
|
492
348
|
|
|
493
349
|
```text
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
rest of A
|
|
497
|
-
rest of B
|
|
350
|
+
[Project notes subtree]
|
|
351
|
+
[Shopping list subtree]
|
|
498
352
|
```
|
|
499
353
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
This is what lets independently developed branches of history remain coherent when they meet.
|
|
354
|
+
rather than becoming interleaved:
|
|
503
355
|
|
|
504
|
-
|
|
356
|
+
```text
|
|
357
|
+
part of Project notes
|
|
358
|
+
part of Shopping list
|
|
359
|
+
rest of Project notes
|
|
360
|
+
rest of Shopping list
|
|
361
|
+
```
|
|
505
362
|
|
|
506
|
-
|
|
363
|
+
When a competitor is inserted into Structural Order, its place is determined relative to the complete subtree of the competitors already there.
|
|
507
364
|
|
|
508
|
-
|
|
365
|
+
## History can arrive before its parent
|
|
509
366
|
|
|
510
|
-
Suppose one replica
|
|
367
|
+
Suppose one replica creates:
|
|
511
368
|
|
|
512
369
|
```text
|
|
513
370
|
Hello
|
|
514
371
|
```
|
|
515
372
|
|
|
516
|
-
and
|
|
373
|
+
and then inserts:
|
|
517
374
|
|
|
518
375
|
```text
|
|
519
|
-
|
|
376
|
+
world
|
|
520
377
|
```
|
|
521
378
|
|
|
522
|
-
|
|
379
|
+
after it.
|
|
380
|
+
|
|
381
|
+
The second Insertion anchors to the first.
|
|
382
|
+
|
|
383
|
+
Another replica may receive:
|
|
523
384
|
|
|
524
385
|
```text
|
|
525
386
|
world
|
|
526
387
|
```
|
|
527
388
|
|
|
528
|
-
before
|
|
389
|
+
before:
|
|
529
390
|
|
|
530
391
|
```text
|
|
531
392
|
Hello
|
|
532
393
|
```
|
|
533
394
|
|
|
534
|
-
|
|
395
|
+
There is not yet anything local that can resolve the anchor.
|
|
535
396
|
|
|
536
|
-
|
|
397
|
+
The Insertion waits.
|
|
537
398
|
|
|
538
|
-
When
|
|
399
|
+
When `Hello` arrives, its identity becomes available and the waiting Insertion can be placed:
|
|
539
400
|
|
|
540
|
-
|
|
401
|
+
```text
|
|
402
|
+
Hello world
|
|
403
|
+
```
|
|
541
404
|
|
|
542
|
-
The same
|
|
405
|
+
The same thing can happen when the parent exists but has not yet grown far enough to contain the referenced logical point.
|
|
543
406
|
|
|
544
|
-
|
|
407
|
+
The relationship itself does not change while it waits.
|
|
545
408
|
|
|
546
|
-
|
|
409
|
+
## Author-time relationships
|
|
547
410
|
|
|
548
|
-
|
|
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:
|
|
549
414
|
|
|
550
415
|
```text
|
|
551
416
|
world
|
|
@@ -556,7 +421,7 @@ Now, Well, actually Hello world
|
|
|
556
421
|
Okay, Now, Well, actually Hello world
|
|
557
422
|
```
|
|
558
423
|
|
|
559
|
-
Another replica might receive the
|
|
424
|
+
Another replica might receive the Insertions in this order:
|
|
560
425
|
|
|
561
426
|
```text
|
|
562
427
|
world
|
|
@@ -567,128 +432,66 @@ Well
|
|
|
567
432
|
Okay
|
|
568
433
|
```
|
|
569
434
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
Each operation describes where it belonged relative to existing canonical history at author time.
|
|
435
|
+
`actually` is still attached to the historical Insertion it followed when it was authored.
|
|
573
436
|
|
|
574
|
-
Once
|
|
437
|
+
Once the required history has arrived, the relationships can be resolved into:
|
|
575
438
|
|
|
576
439
|
```text
|
|
577
440
|
Okay, Now, Well, actually Hello world
|
|
578
441
|
```
|
|
579
442
|
|
|
580
|
-
|
|
443
|
+
## Strips
|
|
581
444
|
|
|
582
|
-
|
|
583
|
-
author-time relationships
|
|
584
|
-
```
|
|
445
|
+
An Insertion does not always stay in one piece inside a running Projection.
|
|
585
446
|
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
```text
|
|
589
|
-
author-time numeric indexes
|
|
590
|
-
```
|
|
591
|
-
|
|
592
|
-
---
|
|
593
|
-
|
|
594
|
-
# Canonical history and runtime fragmentation
|
|
595
|
-
|
|
596
|
-
A canonical Insertion is a logical piece of history.
|
|
597
|
-
|
|
598
|
-
It does not need to remain one physical runtime object forever.
|
|
599
|
-
|
|
600
|
-
Suppose one Insertion originally contains:
|
|
447
|
+
Suppose an original Insertion contains:
|
|
601
448
|
|
|
602
449
|
```text
|
|
603
450
|
A B C D
|
|
604
451
|
```
|
|
605
452
|
|
|
606
|
-
|
|
453
|
+
An edit at the middle may split its runtime representation into:
|
|
607
454
|
|
|
608
455
|
```text
|
|
609
456
|
[A B] [C D]
|
|
610
457
|
```
|
|
611
458
|
|
|
612
|
-
These pieces are
|
|
459
|
+
These pieces are **Strips**.
|
|
613
460
|
|
|
614
|
-
|
|
461
|
+
Both Strips still belong to the same original Insertion.
|
|
615
462
|
|
|
616
|
-
|
|
463
|
+
The original coordinate space is still:
|
|
617
464
|
|
|
618
465
|
```text
|
|
619
|
-
same anchor
|
|
620
|
-
same insertion identity
|
|
621
|
-
same original coordinate space
|
|
622
|
-
```
|
|
623
|
-
|
|
624
|
-
They merely represent different portions of it at runtime.
|
|
625
|
-
|
|
626
|
-
Conceptually:
|
|
627
|
-
|
|
628
|
-
```text
|
|
629
|
-
canonical Insertion
|
|
630
|
-
|
|
631
466
|
| A | B | C | D |
|
|
632
467
|
0 1 2 3 4
|
|
633
|
-
|
|
634
|
-
↓
|
|
635
|
-
|
|
636
|
-
runtime materialization
|
|
637
|
-
|
|
638
|
-
[A B] [C D]
|
|
639
|
-
```
|
|
640
|
-
|
|
641
|
-
The logical points remain:
|
|
642
|
-
|
|
643
|
-
```text
|
|
644
|
-
0 1 2 3 4
|
|
645
468
|
```
|
|
646
469
|
|
|
647
|
-
|
|
470
|
+
The left Strip represents one part of that space and the right Strip represents another.
|
|
648
471
|
|
|
649
|
-
|
|
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.
|
|
650
473
|
|
|
651
|
-
|
|
474
|
+
Different replicas can also have different fragmentation.
|
|
652
475
|
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
This separation between canonical identity and runtime representation is essential.
|
|
656
|
-
|
|
657
|
-
A replica may represent one Insertion as:
|
|
476
|
+
One might currently have:
|
|
658
477
|
|
|
659
478
|
```text
|
|
660
479
|
[A B C D]
|
|
661
480
|
```
|
|
662
481
|
|
|
663
|
-
while another
|
|
482
|
+
while another has:
|
|
664
483
|
|
|
665
484
|
```text
|
|
666
485
|
[A] [B C] [D]
|
|
667
486
|
```
|
|
668
487
|
|
|
669
|
-
|
|
488
|
+
They still agree on the original Insertion and its coordinates.
|
|
670
489
|
|
|
671
|
-
|
|
672
|
-
which Insertion it is
|
|
673
|
-
```
|
|
490
|
+
## Extending an Insertion
|
|
674
491
|
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
```text
|
|
678
|
-
which original logical point an anchor refers to
|
|
679
|
-
```
|
|
492
|
+
Consecutive editing often continues the Insertion that was just created.
|
|
680
493
|
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
The receiver resolves canonical coordinates through whatever fragmentation exists locally.
|
|
684
|
-
|
|
685
|
-
Runtime fragmentation is therefore invisible to replication.
|
|
686
|
-
|
|
687
|
-
---
|
|
688
|
-
|
|
689
|
-
# Consecutive editing can extend history
|
|
690
|
-
|
|
691
|
-
Without any coalescing, typing:
|
|
494
|
+
Typing:
|
|
692
495
|
|
|
693
496
|
```text
|
|
694
497
|
H
|
|
@@ -698,13 +501,9 @@ Hell
|
|
|
698
501
|
Hello
|
|
699
502
|
```
|
|
700
503
|
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
That would preserve correctness, but history would grow unnecessarily quickly.
|
|
504
|
+
does not need five unrelated canonical Insertions.
|
|
704
505
|
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
Conceptually:
|
|
506
|
+
When the new content is a clean continuation of the latest local positive Insertion, its original extent can grow:
|
|
708
507
|
|
|
709
508
|
```text
|
|
710
509
|
H
|
|
@@ -718,35 +517,19 @@ Hell
|
|
|
718
517
|
Hello
|
|
719
518
|
```
|
|
720
519
|
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
The key requirement is that extending it must not change previously established structural relationships.
|
|
724
|
-
|
|
725
|
-
If history has already attached to the old endpoint in a way that requires that boundary to remain distinct, a new independent Insertion is created instead.
|
|
726
|
-
|
|
727
|
-
If the canonical Insertion has fragmented at runtime, a valid extension can still become another fragment of the same grown canonical identity.
|
|
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.
|
|
728
521
|
|
|
729
|
-
|
|
522
|
+
This is only done while the old endpoint can safely grow.
|
|
730
523
|
|
|
731
|
-
|
|
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.
|
|
732
525
|
|
|
733
|
-
|
|
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.
|
|
734
527
|
|
|
735
|
-
|
|
528
|
+
## Removal
|
|
736
529
|
|
|
737
|
-
|
|
530
|
+
Removal is represented by reducing Insertions.
|
|
738
531
|
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
```text
|
|
742
|
-
insertionDiff < 0
|
|
743
|
-
```
|
|
744
|
-
|
|
745
|
-
which targets original Frames belonging to a positive Insertion.
|
|
746
|
-
|
|
747
|
-
This is best understood as **masking**.
|
|
748
|
-
|
|
749
|
-
Suppose the original content is:
|
|
532
|
+
Suppose one positive Insertion contains:
|
|
750
533
|
|
|
751
534
|
```text
|
|
752
535
|
A B C D
|
|
@@ -754,27 +537,27 @@ A B C D
|
|
|
754
537
|
|
|
755
538
|
and `B C` are removed.
|
|
756
539
|
|
|
757
|
-
The
|
|
758
|
-
|
|
759
|
-
A reducing Insertion records:
|
|
540
|
+
The removal anchors to the original positive Insertion and covers those original Frames:
|
|
760
541
|
|
|
761
542
|
```text
|
|
762
|
-
|
|
543
|
+
original
|
|
544
|
+
|
|
545
|
+
A B C D
|
|
546
|
+
└─┬─┘
|
|
547
|
+
removed
|
|
763
548
|
```
|
|
764
549
|
|
|
765
|
-
The Projection
|
|
550
|
+
The Projection becomes:
|
|
766
551
|
|
|
767
552
|
```text
|
|
768
553
|
A D
|
|
769
554
|
```
|
|
770
555
|
|
|
771
|
-
|
|
556
|
+
The original coordinates still exist in Structural Order.
|
|
772
557
|
|
|
773
|
-
|
|
558
|
+
This becomes especially useful when insertion and removal happen concurrently.
|
|
774
559
|
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
Consider two replicas starting with:
|
|
560
|
+
Suppose both replicas start with:
|
|
778
561
|
|
|
779
562
|
```text
|
|
780
563
|
The old house
|
|
@@ -786,135 +569,103 @@ Replica A removes:
|
|
|
786
569
|
old
|
|
787
570
|
```
|
|
788
571
|
|
|
789
|
-
|
|
572
|
+
and sees:
|
|
790
573
|
|
|
791
574
|
```text
|
|
792
|
-
|
|
575
|
+
The house
|
|
793
576
|
```
|
|
794
577
|
|
|
795
|
-
|
|
578
|
+
At the same time Replica B inserts:
|
|
796
579
|
|
|
797
580
|
```text
|
|
798
|
-
|
|
581
|
+
small
|
|
799
582
|
```
|
|
800
583
|
|
|
801
|
-
|
|
584
|
+
after `old `:
|
|
802
585
|
|
|
803
586
|
```text
|
|
804
|
-
small
|
|
587
|
+
The old small house
|
|
805
588
|
```
|
|
806
589
|
|
|
807
|
-
|
|
590
|
+
The removal authored by A refers to the original Frames of `old `.
|
|
808
591
|
|
|
809
|
-
|
|
592
|
+
It never referred to `small ` because those Frames did not exist in A's history.
|
|
810
593
|
|
|
811
|
-
|
|
812
|
-
old
|
|
813
|
-
```
|
|
814
|
-
|
|
815
|
-
After synchronization the result becomes:
|
|
594
|
+
After synchronization:
|
|
816
595
|
|
|
817
596
|
```text
|
|
818
597
|
The small house
|
|
819
598
|
```
|
|
820
599
|
|
|
821
|
-
|
|
600
|
+
The concurrent insertion survives.
|
|
822
601
|
|
|
823
|
-
|
|
602
|
+
## A removal can cross several Insertions
|
|
824
603
|
|
|
825
|
-
|
|
604
|
+
A visible range can contain Frames from several original Insertions.
|
|
826
605
|
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
What looks like one contiguous visible range may internally contain Frames from several canonical Insertions.
|
|
830
|
-
|
|
831
|
-
For example:
|
|
606
|
+
For example, the Projection:
|
|
832
607
|
|
|
833
608
|
```text
|
|
834
609
|
Hello world
|
|
835
610
|
```
|
|
836
611
|
|
|
837
|
-
might
|
|
612
|
+
might have been built from:
|
|
838
613
|
|
|
839
614
|
```text
|
|
840
|
-
[Hello]
|
|
841
|
-
[ ]
|
|
842
|
-
[world]
|
|
615
|
+
[Hello] [ ] [world]
|
|
843
616
|
```
|
|
844
617
|
|
|
845
|
-
from three different historical Insertions.
|
|
846
|
-
|
|
847
618
|
Removing:
|
|
848
619
|
|
|
849
620
|
```text
|
|
850
621
|
lo wo
|
|
851
622
|
```
|
|
852
623
|
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
Sequencer expresses the removal against the actual original Insertions whose Frames are being consumed.
|
|
856
|
-
|
|
857
|
-
Each reducing Insertion targets only Frames belonging to its own historical parent.
|
|
624
|
+
crosses all three.
|
|
858
625
|
|
|
859
|
-
|
|
626
|
+
Sequencer describes the removal against the original Frames of each Insertion it crosses.
|
|
860
627
|
|
|
861
|
-
|
|
628
|
+
The visible edit is one range, but its historical description can contain several reducing Insertions.
|
|
862
629
|
|
|
863
|
-
|
|
630
|
+
## Removal fragments
|
|
864
631
|
|
|
865
|
-
A
|
|
632
|
+
A reducing Insertion can also become fragmented.
|
|
866
633
|
|
|
867
|
-
Suppose original
|
|
634
|
+
Suppose an original positive Insertion contains:
|
|
868
635
|
|
|
869
636
|
```text
|
|
870
637
|
A B C D E F
|
|
871
638
|
```
|
|
872
639
|
|
|
873
|
-
|
|
640
|
+
and its current structural representation has already become:
|
|
874
641
|
|
|
875
642
|
```text
|
|
876
643
|
[A B] [C D] [E F]
|
|
877
644
|
```
|
|
878
645
|
|
|
879
|
-
A removal
|
|
646
|
+
A removal covering:
|
|
880
647
|
|
|
881
648
|
```text
|
|
882
649
|
B C D E
|
|
883
650
|
```
|
|
884
651
|
|
|
885
|
-
may need
|
|
652
|
+
may need mask fragments at several places in Structural Order.
|
|
886
653
|
|
|
887
|
-
Those
|
|
654
|
+
Those mask Strips still belong to one canonical reducing Insertion.
|
|
888
655
|
|
|
889
|
-
|
|
656
|
+
Its identity and original target coordinates do not change.
|
|
890
657
|
|
|
891
|
-
|
|
658
|
+
## Overlapping removals
|
|
892
659
|
|
|
893
|
-
|
|
894
|
-
canonical history
|
|
895
|
-
```
|
|
660
|
+
Two replicas can remove some of the same original Frames.
|
|
896
661
|
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
```text
|
|
900
|
-
runtime representation
|
|
901
|
-
```
|
|
902
|
-
|
|
903
|
-
remain separate.
|
|
904
|
-
|
|
905
|
-
---
|
|
906
|
-
|
|
907
|
-
# Overlapping removals
|
|
908
|
-
|
|
909
|
-
Concurrent replicas may independently remove overlapping Frames.
|
|
910
|
-
|
|
911
|
-
For example, from:
|
|
662
|
+
Starting from:
|
|
912
663
|
|
|
913
664
|
```text
|
|
914
665
|
the brown fox jumps
|
|
915
666
|
```
|
|
916
667
|
|
|
917
|
-
one replica
|
|
668
|
+
one replica might remove:
|
|
918
669
|
|
|
919
670
|
```text
|
|
920
671
|
brown fox
|
|
@@ -926,605 +677,221 @@ while another removes:
|
|
|
926
677
|
fox jumps
|
|
927
678
|
```
|
|
928
679
|
|
|
929
|
-
Both
|
|
930
|
-
|
|
931
|
-
The Frames belonging to:
|
|
680
|
+
Both target the original Frames of `fox`.
|
|
932
681
|
|
|
933
|
-
|
|
934
|
-
fox
|
|
935
|
-
```
|
|
682
|
+
When the second removal is integrated, those Frames may already be masked.
|
|
936
683
|
|
|
937
|
-
|
|
684
|
+
They cannot reduce the Projection again.
|
|
938
685
|
|
|
939
|
-
|
|
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.
|
|
940
687
|
|
|
941
|
-
|
|
688
|
+
This lets overlapping removals arrive in either order without changing the result.
|
|
942
689
|
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
```text
|
|
946
|
-
one original Frame cannot reduce the Projection twice
|
|
947
|
-
```
|
|
690
|
+
## Replacement
|
|
948
691
|
|
|
949
|
-
|
|
692
|
+
Replacement is a removal followed by a positive Insertion.
|
|
950
693
|
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
# Replacement is composition
|
|
954
|
-
|
|
955
|
-
Replacement does not require its own structural concept.
|
|
956
|
-
|
|
957
|
-
Replacing:
|
|
694
|
+
Changing:
|
|
958
695
|
|
|
959
696
|
```text
|
|
960
697
|
Draft
|
|
961
698
|
```
|
|
962
699
|
|
|
963
|
-
|
|
700
|
+
to:
|
|
964
701
|
|
|
965
702
|
```text
|
|
966
703
|
Final
|
|
967
704
|
```
|
|
968
705
|
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
```text
|
|
972
|
-
remove Draft
|
|
973
|
-
insert Final
|
|
974
|
-
```
|
|
975
|
-
|
|
976
|
-
The important part is the relationship between those two operations.
|
|
977
|
-
|
|
978
|
-
The new content is anchored against the history that exists after the removal relationship has been established.
|
|
979
|
-
|
|
980
|
-
This keeps replacement semantics consistent with ordinary insertion and removal instead of introducing another independent ordering model.
|
|
981
|
-
|
|
982
|
-
---
|
|
983
|
-
|
|
984
|
-
# Visible content and historical content are deliberately different
|
|
985
|
-
|
|
986
|
-
After enough editing, Structural Order may contain much more history than the Projection shows.
|
|
987
|
-
|
|
988
|
-
For example:
|
|
989
|
-
|
|
990
|
-
```text
|
|
991
|
-
Structural Order
|
|
992
|
-
|
|
993
|
-
[A B C]
|
|
994
|
-
[mask B]
|
|
995
|
-
[X]
|
|
996
|
-
[mask C]
|
|
997
|
-
[Y]
|
|
998
|
-
```
|
|
999
|
-
|
|
1000
|
-
could produce a Projection such as:
|
|
1001
|
-
|
|
1002
|
-
```text
|
|
1003
|
-
A X Y
|
|
1004
|
-
```
|
|
1005
|
-
|
|
1006
|
-
The hidden history is not accidental garbage.
|
|
1007
|
-
|
|
1008
|
-
It may still be required to understand:
|
|
1009
|
-
|
|
1010
|
-
```text
|
|
1011
|
-
future delayed operations
|
|
1012
|
-
historical anchor points
|
|
1013
|
-
concurrent relationships
|
|
1014
|
-
removal ownership
|
|
1015
|
-
ordering of descendants
|
|
1016
|
-
```
|
|
1017
|
-
|
|
1018
|
-
Sequencer therefore cannot simply delete every hidden node as soon as it stops being visible.
|
|
1019
|
-
|
|
1020
|
-
---
|
|
1021
|
-
|
|
1022
|
-
# Replication transports canonical history
|
|
1023
|
-
|
|
1024
|
-
Replicas exchange canonical Insertions and acknowledgement information.
|
|
1025
|
-
|
|
1026
|
-
The transport itself is not part of the sequencing model.
|
|
1027
|
-
|
|
1028
|
-
History may be delivered:
|
|
1029
|
-
|
|
1030
|
-
```text
|
|
1031
|
-
immediately
|
|
1032
|
-
later
|
|
1033
|
-
out of order
|
|
1034
|
-
more than once
|
|
1035
|
-
through a central server
|
|
1036
|
-
peer to peer
|
|
1037
|
-
after being persisted
|
|
1038
|
-
```
|
|
1039
|
-
|
|
1040
|
-
None of these should affect the eventual ordering.
|
|
1041
|
-
|
|
1042
|
-
The important property is that the same canonical history eventually reaches the replicas that need it.
|
|
1043
|
-
|
|
1044
|
-
---
|
|
1045
|
-
|
|
1046
|
-
# Duplicate delivery is harmless
|
|
1047
|
-
|
|
1048
|
-
Because canonical Insertions have stable identities, receiving the same history multiple times does not duplicate its visible effect.
|
|
1049
|
-
|
|
1050
|
-
This allows replication systems to favor reliability over exactly-once transport.
|
|
1051
|
-
|
|
1052
|
-
A sender can retransmit uncertain history.
|
|
1053
|
-
|
|
1054
|
-
A relay can replay stored history.
|
|
1055
|
-
|
|
1056
|
-
A reconnecting replica can receive data it already has.
|
|
1057
|
-
|
|
1058
|
-
Sequencer recognizes the canonical identity and keeps the resulting history idempotent.
|
|
1059
|
-
|
|
1060
|
-
---
|
|
1061
|
-
|
|
1062
|
-
# Actors and Sessions have different roles
|
|
1063
|
-
|
|
1064
|
-
A **Session** identifies authored sequencing history.
|
|
1065
|
-
|
|
1066
|
-
An **Actor** participates in acknowledgement of removal history.
|
|
1067
|
-
|
|
1068
|
-
These concepts are intentionally separate.
|
|
1069
|
-
|
|
1070
|
-
One Actor may have several independent Sessions.
|
|
1071
|
-
|
|
1072
|
-
Different replicas belonging to the same logical Actor can therefore create history without sharing one mutable sequencing clock.
|
|
1073
|
-
|
|
1074
|
-
Session identities answer:
|
|
1075
|
-
|
|
1076
|
-
```text
|
|
1077
|
-
who authored this canonical history stream?
|
|
1078
|
-
```
|
|
1079
|
-
|
|
1080
|
-
Actor identities answer:
|
|
1081
|
-
|
|
1082
|
-
```text
|
|
1083
|
-
whose acknowledgement is required before old removal history can be forgotten?
|
|
1084
|
-
```
|
|
1085
|
-
|
|
1086
|
-
---
|
|
1087
|
-
|
|
1088
|
-
# Why acknowledgements are needed
|
|
1089
|
-
|
|
1090
|
-
Suppose Replica A removes some content.
|
|
1091
|
-
|
|
1092
|
-
Replica B is currently offline.
|
|
1093
|
-
|
|
1094
|
-
Replica B may still contain unsent history anchored to the content that A removed.
|
|
1095
|
-
|
|
1096
|
-
If A permanently discarded every trace of that historical content immediately, B's delayed operation could later refer to a point that no longer exists anywhere in A's retained state.
|
|
1097
|
-
|
|
1098
|
-
Sequencer therefore separates:
|
|
1099
|
-
|
|
1100
|
-
```text
|
|
1101
|
-
content is no longer visible
|
|
1102
|
-
```
|
|
1103
|
-
|
|
1104
|
-
from:
|
|
1105
|
-
|
|
1106
|
-
```text
|
|
1107
|
-
history is safe to forget
|
|
1108
|
-
```
|
|
1109
|
-
|
|
1110
|
-
Those are not the same event.
|
|
1111
|
-
|
|
1112
|
-
---
|
|
1113
|
-
|
|
1114
|
-
# Removal frontiers
|
|
1115
|
-
|
|
1116
|
-
Actors acknowledge received prefixes of removal Sessions.
|
|
1117
|
-
|
|
1118
|
-
Conceptually an acknowledgement says:
|
|
1119
|
-
|
|
1120
|
-
```text
|
|
1121
|
-
Actor A has observed this removal Session
|
|
1122
|
-
through logical point N
|
|
1123
|
-
```
|
|
1124
|
-
|
|
1125
|
-
A frontier summarizes a whole contiguous prefix rather than listing every individual removal.
|
|
1126
|
-
|
|
1127
|
-
This keeps acknowledgement state small while still allowing Sequencer to determine which removal history is globally known among the active Actors.
|
|
1128
|
-
|
|
1129
|
-
---
|
|
1130
|
-
|
|
1131
|
-
# Compaction
|
|
1132
|
-
|
|
1133
|
-
Once all active Actors agree on a removal frontier, the acknowledged removal history becomes eligible for compaction.
|
|
1134
|
-
|
|
1135
|
-
Compaction does not simply delete mask nodes.
|
|
1136
|
-
|
|
1137
|
-
It constructs an equivalent retained history in which obsolete removed Frames and the historical machinery surrounding them can be omitted.
|
|
1138
|
-
|
|
1139
|
-
This may involve:
|
|
1140
|
-
|
|
1141
|
-
```text
|
|
1142
|
-
removing acknowledged masks
|
|
1143
|
-
removing Footage that can no longer reappear
|
|
1144
|
-
shortening positive Insertions
|
|
1145
|
-
adjusting surviving mask coordinates
|
|
1146
|
-
collapsing obsolete logical regions
|
|
1147
|
-
re-anchoring surviving history
|
|
1148
|
-
```
|
|
1149
|
-
|
|
1150
|
-
The required invariant is simple:
|
|
1151
|
-
|
|
1152
|
-
```text
|
|
1153
|
-
Projection before compaction
|
|
1154
|
-
==
|
|
1155
|
-
Projection reconstructed from compacted history
|
|
1156
|
-
```
|
|
1157
|
-
|
|
1158
|
-
But preserving that invariant under future editing is the harder part.
|
|
1159
|
-
|
|
1160
|
-
The compacted history must not only look the same now.
|
|
1161
|
-
|
|
1162
|
-
It must also preserve the ordering relationships that remain relevant later.
|
|
1163
|
-
|
|
1164
|
-
---
|
|
1165
|
-
|
|
1166
|
-
# Compaction can collapse historical space
|
|
1167
|
-
|
|
1168
|
-
Consider surviving children originally attached to two different logical points:
|
|
1169
|
-
|
|
1170
|
-
```text
|
|
1171
|
-
point 1
|
|
1172
|
-
↓
|
|
1173
|
-
removed historical region
|
|
1174
|
-
↓
|
|
1175
|
-
point 2
|
|
1176
|
-
```
|
|
1177
|
-
|
|
1178
|
-
After the region between them becomes safe to forget, both historical points may collapse onto the same retained boundary.
|
|
1179
|
-
|
|
1180
|
-
At that point the original geometric distinction no longer exists.
|
|
1181
|
-
|
|
1182
|
-
But the children may already have a resolved order.
|
|
1183
|
-
|
|
1184
|
-
Compaction must preserve that order.
|
|
1185
|
-
|
|
1186
|
-
Sequencer can therefore re-anchor surviving positive history according to its already resolved retained Structural Order.
|
|
1187
|
-
|
|
1188
|
-
In other words, once obsolete history is discarded:
|
|
706
|
+
first masks the Frames of:
|
|
1189
707
|
|
|
1190
708
|
```text
|
|
1191
|
-
|
|
1192
|
-
```
|
|
1193
|
-
|
|
1194
|
-
can become more important than:
|
|
1195
|
-
|
|
1196
|
-
```text
|
|
1197
|
-
the exact historical path that originally produced it
|
|
1198
|
-
```
|
|
1199
|
-
|
|
1200
|
-
This is what lets retained state become smaller without reopening old ordering decisions.
|
|
1201
|
-
|
|
1202
|
-
---
|
|
1203
|
-
|
|
1204
|
-
# Compaction does not rewrite live history
|
|
1205
|
-
|
|
1206
|
-
Compaction operates on retained state.
|
|
1207
|
-
|
|
1208
|
-
A live Projection does not need to restructure itself every time a snapshot is produced.
|
|
1209
|
-
|
|
1210
|
-
Instead:
|
|
1211
|
-
|
|
1212
|
-
```text
|
|
1213
|
-
live Structural Order
|
|
1214
|
-
↓
|
|
1215
|
-
derive equivalent compacted history
|
|
1216
|
-
↓
|
|
1217
|
-
persist / transfer snapshot
|
|
1218
|
-
```
|
|
1219
|
-
|
|
1220
|
-
A later Projection can hydrate from that compacted history and produce the same visible state and compatible future ordering.
|
|
1221
|
-
|
|
1222
|
-
This keeps persistence optimization separate from the current editing runtime.
|
|
1223
|
-
|
|
1224
|
-
---
|
|
1225
|
-
|
|
1226
|
-
# Actor retirement
|
|
1227
|
-
|
|
1228
|
-
A permanently gone Actor would otherwise block removal compaction forever.
|
|
1229
|
-
|
|
1230
|
-
Sequencer therefore allows an Actor to be retired from future acknowledgement consensus.
|
|
1231
|
-
|
|
1232
|
-
Retirement means:
|
|
1233
|
-
|
|
1234
|
-
```text
|
|
1235
|
-
this Actor is no longer expected to acknowledge future compaction
|
|
709
|
+
Draft
|
|
1236
710
|
```
|
|
1237
711
|
|
|
1238
|
-
|
|
712
|
+
and then anchors:
|
|
1239
713
|
|
|
1240
714
|
```text
|
|
1241
|
-
|
|
715
|
+
Final
|
|
1242
716
|
```
|
|
1243
717
|
|
|
1244
|
-
|
|
718
|
+
into the resulting history.
|
|
1245
719
|
|
|
1246
|
-
|
|
720
|
+
Both parts use the same insertion and removal rules as every other edit.
|
|
1247
721
|
|
|
1248
|
-
|
|
722
|
+
## Actors and acknowledgements
|
|
1249
723
|
|
|
1250
|
-
|
|
724
|
+
Removal history cannot always be discarded when it disappears from the Projection.
|
|
1251
725
|
|
|
1252
|
-
|
|
726
|
+
Suppose one replica removes some Frames while another replica is offline.
|
|
1253
727
|
|
|
1254
|
-
|
|
728
|
+
The offline replica may still have unsent history anchored to those Frames.
|
|
1255
729
|
|
|
1256
|
-
|
|
730
|
+
The removed Frames must remain addressable until that old history no longer needs to be supported.
|
|
1257
731
|
|
|
1258
|
-
|
|
1259
|
-
canonical Insertions
|
|
1260
|
-
retained acknowledgement state
|
|
1261
|
-
positive Footage
|
|
1262
|
-
```
|
|
732
|
+
Actors report how far they have observed each reducing Session.
|
|
1263
733
|
|
|
1264
|
-
|
|
734
|
+
For example:
|
|
1265
735
|
|
|
1266
736
|
```text
|
|
1267
|
-
|
|
1268
|
-
temporary traversal indexes
|
|
1269
|
-
recent lookup positions
|
|
1270
|
-
allocation addresses
|
|
1271
|
-
```
|
|
1272
|
-
|
|
1273
|
-
Those can be reconstructed.
|
|
1274
|
-
|
|
1275
|
-
The persistence boundary therefore follows the same conceptual separation as replication:
|
|
737
|
+
Actor 3
|
|
1276
738
|
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
runtime materialization is disposable
|
|
739
|
+
removal Session 17
|
|
740
|
+
observed through logical time 42
|
|
1280
741
|
```
|
|
1281
742
|
|
|
1282
|
-
|
|
743
|
+
The reported point is a **frontier**.
|
|
1283
744
|
|
|
1284
|
-
|
|
745
|
+
A single frontier summarizes a received prefix of a Session rather than acknowledging every reducing Insertion separately.
|
|
1285
746
|
|
|
1286
|
-
|
|
747
|
+
## Compaction
|
|
1287
748
|
|
|
1288
|
-
|
|
749
|
+
When all active Actors agree on the same frontier for a reducing Session, the acknowledged part can be removed from future retained Sequences.
|
|
1289
750
|
|
|
1290
|
-
|
|
751
|
+
Suppose history contains:
|
|
1291
752
|
|
|
1292
753
|
```text
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
754
|
+
positive Frames
|
|
755
|
+
removal mask
|
|
756
|
+
surviving descendants
|
|
1296
757
|
```
|
|
1297
758
|
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
They are not part of the distributed identity of the sequence.
|
|
1301
|
-
|
|
1302
|
-
---
|
|
1303
|
-
|
|
1304
|
-
# The same history can have different runtime shapes
|
|
759
|
+
and every active Actor has seen the removal.
|
|
1305
760
|
|
|
1306
|
-
|
|
761
|
+
A new retained Sequence no longer needs to preserve all of the machinery that represented that deletion.
|
|
1307
762
|
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
```text
|
|
1311
|
-
[A B C] [D E]
|
|
1312
|
-
```
|
|
763
|
+
Compaction can remove the acknowledged masks and remove deleted Frames from retained Footage.
|
|
1313
764
|
|
|
1314
|
-
|
|
765
|
+
If only part of a positive Insertion was deleted:
|
|
1315
766
|
|
|
1316
767
|
```text
|
|
1317
|
-
|
|
768
|
+
A B C D
|
|
1318
769
|
```
|
|
1319
770
|
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
As long as all of them agree on:
|
|
771
|
+
with:
|
|
1323
772
|
|
|
1324
773
|
```text
|
|
1325
|
-
|
|
1326
|
-
canonical anchors
|
|
1327
|
-
original Frame coordinates
|
|
1328
|
-
deterministic Structural Order
|
|
774
|
+
B C
|
|
1329
775
|
```
|
|
1330
776
|
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
Convergence is therefore defined over logical history and Projection, not over internal memory layout.
|
|
1334
|
-
|
|
1335
|
-
---
|
|
1336
|
-
|
|
1337
|
-
# Three coordinate spaces
|
|
1338
|
-
|
|
1339
|
-
Many apparent complexities in Sequencer become much simpler when three different coordinate spaces are kept separate.
|
|
1340
|
-
|
|
1341
|
-
## Projection positions
|
|
1342
|
-
|
|
1343
|
-
These are the indexes applications use:
|
|
777
|
+
gone, the retained positive history can shrink to the surviving content:
|
|
1344
778
|
|
|
1345
779
|
```text
|
|
1346
|
-
|
|
780
|
+
A D
|
|
1347
781
|
```
|
|
1348
782
|
|
|
1349
|
-
|
|
783
|
+
Anchors and remaining removals that referred to the old coordinates are adjusted to the smaller retained coordinate space.
|
|
1350
784
|
|
|
1351
|
-
|
|
785
|
+
The running Projection does not need to be rewritten when this happens. Compaction produces another retained description of the same history.
|
|
1352
786
|
|
|
1353
|
-
|
|
787
|
+
## Collapsed historical points
|
|
1354
788
|
|
|
1355
|
-
|
|
789
|
+
Compaction can make two old logical points collapse onto the same retained point.
|
|
1356
790
|
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
They survive:
|
|
791
|
+
Imagine:
|
|
1360
792
|
|
|
1361
793
|
```text
|
|
1362
|
-
|
|
1363
|
-
fragmentation
|
|
1364
|
-
removal
|
|
1365
|
-
reordered delivery
|
|
1366
|
-
restart
|
|
794
|
+
A | removed Frames | B
|
|
1367
795
|
```
|
|
1368
796
|
|
|
1369
|
-
|
|
797
|
+
with surviving descendants attached on both sides of the removed region.
|
|
1370
798
|
|
|
1371
|
-
|
|
799
|
+
Before compaction those descendants were separated by different historical coordinates.
|
|
1372
800
|
|
|
1373
|
-
|
|
801
|
+
After the deleted Frames disappear from retained history, that space no longer exists.
|
|
1374
802
|
|
|
1375
|
-
|
|
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.
|
|
1376
804
|
|
|
1377
|
-
|
|
805
|
+
The discarded history is no longer needed to make the same ordering decision again.
|
|
1378
806
|
|
|
1379
|
-
|
|
807
|
+
## Actor retirement
|
|
1380
808
|
|
|
1381
|
-
|
|
809
|
+
An Actor that will never return would otherwise remain part of acknowledgement consensus forever.
|
|
1382
810
|
|
|
1383
|
-
|
|
811
|
+
Retiring an Actor removes it from future compaction requirements.
|
|
1384
812
|
|
|
1385
|
-
|
|
1386
|
-
Projection position
|
|
1387
|
-
!=
|
|
1388
|
-
canonical logical coordinate
|
|
1389
|
-
!=
|
|
1390
|
-
runtime structural position
|
|
1391
|
-
```
|
|
813
|
+
It does not remove Insertions authored by that Actor.
|
|
1392
814
|
|
|
1393
|
-
|
|
815
|
+
It only changes which Actors must agree before old removal history can be discarded.
|
|
1394
816
|
|
|
1395
|
-
|
|
817
|
+
Whether an Actor is permanently gone is something the surrounding application has to decide.
|
|
1396
818
|
|
|
1397
|
-
|
|
819
|
+
## Sequence
|
|
1398
820
|
|
|
1399
|
-
|
|
821
|
+
A retained **Sequence** stores enough history to reconstruct the Projection later.
|
|
1400
822
|
|
|
1401
|
-
|
|
823
|
+
It contains canonical Insertion history, acknowledgement frontiers and the Footage belonging to surviving positive history.
|
|
1402
824
|
|
|
1403
|
-
|
|
1404
|
-
Hello
|
|
1405
|
-
```
|
|
825
|
+
Runtime fragmentation is not persisted as separate Insertions.
|
|
1406
826
|
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
Replica B later receives that history.
|
|
1410
|
-
|
|
1411
|
-
Both now derive:
|
|
827
|
+
If one canonical Insertion currently exists as:
|
|
1412
828
|
|
|
1413
829
|
```text
|
|
1414
|
-
|
|
830
|
+
[A] [B C] [D]
|
|
1415
831
|
```
|
|
1416
832
|
|
|
1417
|
-
|
|
833
|
+
the retained history still describes the one original Insertion:
|
|
1418
834
|
|
|
1419
835
|
```text
|
|
1420
|
-
|
|
1421
|
-
```
|
|
1422
|
-
|
|
1423
|
-
at the end.
|
|
1424
|
-
|
|
1425
|
-
If eligible, the existing positive history may simply extend.
|
|
1426
|
-
|
|
1427
|
-
Meanwhile Replica B inserts:
|
|
1428
|
-
|
|
1429
|
-
```text
|
|
1430
|
-
beautiful
|
|
836
|
+
A B C D
|
|
1431
837
|
```
|
|
1432
838
|
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
Now the replicas contain concurrent history.
|
|
839
|
+
along with the other canonical history that caused its current result.
|
|
1436
840
|
|
|
1437
|
-
|
|
841
|
+
The next runtime can fragment it again as needed.
|
|
1438
842
|
|
|
1439
|
-
|
|
843
|
+
## Hydration
|
|
1440
844
|
|
|
1441
|
-
|
|
845
|
+
Loading a Sequence rebuilds Structural Order and derives the Projection from it.
|
|
1442
846
|
|
|
1443
|
-
|
|
1444
|
-
Hello beautiful world
|
|
1445
|
-
```
|
|
847
|
+
A hydrated runtime does not need to reproduce the exact Strip layout of the runtime that saved the Sequence.
|
|
1446
848
|
|
|
1447
|
-
|
|
849
|
+
For example, the old runtime may have ended with:
|
|
1448
850
|
|
|
1449
851
|
```text
|
|
1450
|
-
|
|
852
|
+
[A] [B C] [D]
|
|
1451
853
|
```
|
|
1452
854
|
|
|
1453
|
-
while
|
|
855
|
+
while the new one initially materializes:
|
|
1454
856
|
|
|
1455
857
|
```text
|
|
1456
|
-
|
|
858
|
+
[A B C D]
|
|
1457
859
|
```
|
|
1458
860
|
|
|
1459
|
-
inside
|
|
1460
|
-
|
|
1461
|
-
The removal masks only Frames actually observed by its author.
|
|
861
|
+
If later history needs a boundary inside it, it can split again.
|
|
1462
862
|
|
|
1463
|
-
|
|
863
|
+
Both represent the same canonical Insertion.
|
|
1464
864
|
|
|
1465
|
-
|
|
865
|
+
The visible sequence and the relationships available to future edits remain the same.
|
|
1466
866
|
|
|
1467
|
-
|
|
867
|
+
## Projection and history keep changing at different rates
|
|
1468
868
|
|
|
1469
|
-
A
|
|
869
|
+
A Projection can change dramatically while very little canonical history is added.
|
|
1470
870
|
|
|
1471
|
-
A
|
|
871
|
+
A long contiguous typing session may extend one positive Insertion.
|
|
1472
872
|
|
|
1473
|
-
|
|
1474
|
-
Hello wide world
|
|
1475
|
-
```
|
|
873
|
+
A removal can hide many Frames while leaving the positive Insertion itself in history.
|
|
1476
874
|
|
|
1477
|
-
|
|
875
|
+
Compaction can later make retained history smaller without changing the Projection at all.
|
|
1478
876
|
|
|
1479
|
-
|
|
877
|
+
So these are separate views of the same sequence:
|
|
1480
878
|
|
|
1481
879
|
```text
|
|
1482
|
-
|
|
1483
|
-
→ canonical anchors
|
|
1484
|
-
→ deterministic history
|
|
1485
|
-
→ concurrency
|
|
1486
|
-
→ fragmentation
|
|
1487
|
-
→ masking
|
|
1488
|
-
→ acknowledgement
|
|
1489
|
-
→ compaction
|
|
1490
|
-
→ equivalent reconstruction
|
|
880
|
+
Projection
|
|
1491
881
|
```
|
|
1492
882
|
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
# The central idea
|
|
1496
|
-
|
|
1497
|
-
Sequencer works because temporary visible positions are never treated as permanent distributed identities.
|
|
1498
|
-
|
|
1499
|
-
Every edit is translated into stable historical relationships.
|
|
1500
|
-
|
|
1501
|
-
Those relationships can survive:
|
|
883
|
+
is the content visible now.
|
|
1502
884
|
|
|
1503
885
|
```text
|
|
1504
|
-
|
|
1505
|
-
different packet orders
|
|
1506
|
-
duplicate delivery
|
|
1507
|
-
offline replicas
|
|
1508
|
-
fragmentation
|
|
1509
|
-
removal
|
|
1510
|
-
restart
|
|
1511
|
-
compaction
|
|
886
|
+
Structural Order
|
|
1512
887
|
```
|
|
1513
888
|
|
|
1514
|
-
|
|
889
|
+
is the history currently needed to resolve ordering and removals.
|
|
1515
890
|
|
|
1516
891
|
```text
|
|
1517
|
-
|
|
1518
|
-
↓
|
|
1519
|
-
canonical historical relationship
|
|
1520
|
-
↓
|
|
1521
|
-
deterministic Structural Order
|
|
1522
|
-
↓
|
|
1523
|
-
local Projection
|
|
892
|
+
Sequence
|
|
1524
893
|
```
|
|
1525
894
|
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
Once they know the same canonical history, they can independently derive the same result.
|
|
895
|
+
is the retained form of that history, with acknowledged obsolete history compacted away when possible.
|
|
1529
896
|
|
|
1530
|
-
|
|
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.
|