@ibgib/core-gib 0.1.41 → 0.1.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/sync/sync-conflict-adv-multitimelines.respec.mjs +2 -2
- package/dist/sync/sync-conflict-adv-multitimelines.respec.mjs.map +1 -1
- package/dist/sync/sync-conflict-text-merge.respec.d.mts +4 -1
- package/dist/sync/sync-conflict-text-merge.respec.d.mts.map +1 -1
- package/dist/sync/sync-conflict-text-merge.respec.mjs +308 -175
- package/dist/sync/sync-conflict-text-merge.respec.mjs.map +1 -1
- package/package.json +1 -1
- package/src/sync/sync-conflict-adv-multitimelines.respec.mts +3 -3
- package/src/sync/sync-conflict-text-merge.respec.mts +320 -158
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
* @module sync-conflict-text-merge.respec
|
|
3
3
|
*
|
|
4
4
|
* Verifies text merge (LCS algorithm) in SyncSagaCoordinator.
|
|
5
|
-
*
|
|
5
|
+
*
|
|
6
|
+
* Tests ibgib.data.text conflicts with various text patterns, which with
|
|
7
|
+
* optimistic merging. This should trigger the automatic text merging which is
|
|
8
|
+
* different than the replay of dna for other types of conflict grafts.
|
|
6
9
|
*/
|
|
7
10
|
|
|
8
11
|
import {
|
|
@@ -102,21 +105,20 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
|
|
|
102
105
|
description: 'Create timeline with initial text, sync to establish common history'
|
|
103
106
|
});
|
|
104
107
|
|
|
105
|
-
if (logalot) { console.log(`${lc} R1: Creating initial
|
|
108
|
+
if (logalot) { console.log(`${lc} R1: Creating initial alpha with text...`); }
|
|
106
109
|
|
|
107
|
-
// Create
|
|
110
|
+
// Create alpha with initial text on source
|
|
108
111
|
const INITIAL_TEXT = "This is the initial quiz question.\nIt has multiple lines.\nStudents will answer this.";
|
|
109
112
|
|
|
110
|
-
const
|
|
111
|
-
atom: '
|
|
113
|
+
const r1_alpha_v0_source = await testTransformer.create({
|
|
114
|
+
atom: 'alpha',
|
|
112
115
|
in: 'source',
|
|
113
116
|
data: { text: INITIAL_TEXT },
|
|
114
|
-
name: '
|
|
117
|
+
name: 'r1_alpha_v0_source'
|
|
115
118
|
});
|
|
119
|
+
const alpha_tjpAddr = getTjpAddr({ ibGib: r1_alpha_v0_source.ibGib, defaultIfNone: 'incomingAddr' })!;
|
|
116
120
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (logalot) { console.log(`${lc} R1: Syncing initial content to dest...`); }
|
|
121
|
+
if (logalot) { console.log(`${lc} R1: Syncing initial alpha to dest...`); }
|
|
120
122
|
|
|
121
123
|
let r1_syncSaga: SyncSagaInfo | undefined;
|
|
122
124
|
try {
|
|
@@ -124,7 +126,7 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
|
|
|
124
126
|
peer: await newTestPeer(),
|
|
125
127
|
localSpace: sourceSpace,
|
|
126
128
|
metaspace,
|
|
127
|
-
domainIbGibs: [
|
|
129
|
+
domainIbGibs: [r1_alpha_v0_source.ibGib],
|
|
128
130
|
conflictStrategy: SyncConflictStrategy.optimisticWithLCS,
|
|
129
131
|
useSessionIdentity: false,
|
|
130
132
|
});
|
|
@@ -139,54 +141,70 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
|
|
|
139
141
|
// Verify both sides have same text
|
|
140
142
|
await respecfully(sir, `r1 verify post`, async () => {
|
|
141
143
|
try {
|
|
142
|
-
const
|
|
144
|
+
const r1_alpha_sourceKV = await senderCoordinator.getKnowledgeMap({
|
|
143
145
|
space: sourceSpace,
|
|
144
146
|
metaspace,
|
|
145
|
-
domainIbGibs: [
|
|
147
|
+
domainIbGibs: [r1_alpha_v0_source.ibGib]
|
|
146
148
|
});
|
|
147
|
-
const
|
|
149
|
+
const r1_alpha_source_tipAddr = r1_alpha_sourceKV[alpha_tjpAddr];
|
|
150
|
+
if (!r1_alpha_source_tipAddr) {
|
|
151
|
+
ifWeMight(sir, 'r1_alpha_source_tipAddr is falsy?', async () => {
|
|
152
|
+
iReckon(sir, true).asTo('fail').isGonnaBeFalse();
|
|
153
|
+
});
|
|
154
|
+
return; /* <<<< returns early */
|
|
155
|
+
}
|
|
148
156
|
|
|
149
|
-
const
|
|
157
|
+
const r1_alpha_destKV = await senderCoordinator.getKnowledgeMap({
|
|
150
158
|
space: destSpace,
|
|
151
159
|
metaspace,
|
|
152
|
-
domainIbGibs: [
|
|
160
|
+
domainIbGibs: [r1_alpha_v0_source.ibGib]
|
|
153
161
|
});
|
|
154
|
-
const
|
|
162
|
+
const r1_alpha_dest_tipAddr = r1_alpha_destKV[alpha_tjpAddr];
|
|
163
|
+
if (!r1_alpha_dest_tipAddr) {
|
|
164
|
+
ifWeMight(sir, 'r1_alpha_dest_tipAddr is falsy?', async () => {
|
|
165
|
+
iReckon(sir, true).asTo('fail').isGonnaBeFalse();
|
|
166
|
+
});
|
|
167
|
+
return; /* <<<< returns early */
|
|
168
|
+
}
|
|
155
169
|
|
|
156
170
|
await ifWeMight(sir, 'r1 tip addrs match', async () => {
|
|
157
|
-
iReckon(sir,
|
|
171
|
+
iReckon(sir, r1_alpha_source_tipAddr).asTo('R1 source/dest have same tip').isGonnaBe(r1_alpha_dest_tipAddr);
|
|
158
172
|
});
|
|
159
173
|
|
|
160
174
|
await ifWeMight(sir, 'r1 text synced correctly', async () => {
|
|
161
|
-
if (!
|
|
175
|
+
if (!r1_alpha_dest_tipAddr) {
|
|
162
176
|
throw new Error(`r1_dest_tipAddr is null/undefined (E: 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d)`);
|
|
163
177
|
}
|
|
164
|
-
const resGet_destTip = await getFromSpace({ space: destSpace, addr:
|
|
178
|
+
const resGet_destTip = await getFromSpace({ space: destSpace, addr: r1_alpha_dest_tipAddr });
|
|
165
179
|
const destTipIbGib = resGet_destTip.ibGibs![0] as IbGib_V1<TestData>;
|
|
166
180
|
|
|
167
181
|
iReckon(sir, destTipIbGib.data!.text).asTo('Dest has initial text').isGonnaBe(INITIAL_TEXT);
|
|
168
182
|
});
|
|
169
183
|
|
|
170
184
|
await ifWeMight(sir, 'r1 dep graphs synced', async () => {
|
|
171
|
-
const [
|
|
172
|
-
addrs: [
|
|
185
|
+
const [r1_alpha_source_tip] = await getIbGibsFromCache_fallbackToSpaces({
|
|
186
|
+
addrs: [r1_alpha_source_tipAddr],
|
|
187
|
+
space: sourceSpace,
|
|
188
|
+
});
|
|
189
|
+
const [r1_alpha_dest_tip] = await getIbGibsFromCache_fallbackToSpaces({
|
|
190
|
+
addrs: [r1_alpha_dest_tipAddr],
|
|
173
191
|
space: destSpace,
|
|
174
192
|
});
|
|
175
|
-
iReckon(sir,
|
|
176
|
-
if (
|
|
177
|
-
const
|
|
178
|
-
ibGib:
|
|
193
|
+
iReckon(sir, r1_alpha_dest_tip).asTo('alpha tip exists in dest').isGonnaBeTruthy();
|
|
194
|
+
if (r1_alpha_dest_tip) {
|
|
195
|
+
const r1_alpha_source_depGraph = await getDependencyGraph({
|
|
196
|
+
ibGib: r1_alpha_source_tip,
|
|
179
197
|
live: true,
|
|
180
198
|
space: sourceSpace
|
|
181
199
|
});
|
|
182
|
-
const
|
|
183
|
-
ibGib:
|
|
200
|
+
const r1_alpha_dest_depGraph = await getDependencyGraph({
|
|
201
|
+
ibGib: r1_alpha_dest_tip,
|
|
184
202
|
live: true,
|
|
185
203
|
space: destSpace
|
|
186
204
|
});
|
|
187
205
|
const graphsEqual = graphsAreEquivalent({
|
|
188
|
-
graphA:
|
|
189
|
-
graphB:
|
|
206
|
+
graphA: r1_alpha_source_depGraph,
|
|
207
|
+
graphB: r1_alpha_dest_depGraph,
|
|
190
208
|
slowButThorough: true,
|
|
191
209
|
});
|
|
192
210
|
iReckon(sir, graphsEqual).asTo('R1 dep graphs equal').isGonnaBeTrue();
|
|
@@ -211,8 +229,16 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
|
|
|
211
229
|
|
|
212
230
|
if (logalot) { console.log(`${lc} R2: Source appending to end of text...`); }
|
|
213
231
|
|
|
214
|
-
//
|
|
215
|
-
//
|
|
232
|
+
// const resGet_r2_source = await getFromSpace({ space: sourceSpace, addr: alpha_tjpAddr });
|
|
233
|
+
// const r2_v0_graft = resGet_r2_source.ibGibs![0] as IbGib_V1<TestData>;
|
|
234
|
+
|
|
235
|
+
const SOURCE_APPEND = "\nInstructor added hint.";
|
|
236
|
+
const r2_alpha_v1_source_appendedText = await testTransformer.mut8({
|
|
237
|
+
ibGib: r1_alpha_v0_source.ibGib,
|
|
238
|
+
in: 'source',
|
|
239
|
+
strField: { name: 'text', value: INITIAL_TEXT + SOURCE_APPEND },
|
|
240
|
+
name: 'r2_alpha_v1_source_appendedText',
|
|
241
|
+
});
|
|
216
242
|
|
|
217
243
|
// #endregion r2 source edits
|
|
218
244
|
|
|
@@ -220,42 +246,118 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
|
|
|
220
246
|
|
|
221
247
|
if (logalot) { console.log(`${lc} R2: Dest prepending to beginning of text...`); }
|
|
222
248
|
|
|
223
|
-
|
|
224
|
-
|
|
249
|
+
const resGet_r2_dest = await getFromSpace({ space: destSpace, addr: r1_alpha_v0_source.addr });
|
|
250
|
+
const r2_v0_alpha_dest = resGet_r2_dest.ibGibs![0] as IbGib_V1<TestData>;
|
|
251
|
+
|
|
252
|
+
const DEST_PREPEND = "Student note: Confusing!\n";
|
|
253
|
+
const r2_alpha_v1_dest_prependedText = await testTransformer.mut8({
|
|
254
|
+
ibGib: r2_v0_alpha_dest,
|
|
255
|
+
in: 'dest',
|
|
256
|
+
strField: { name: 'text', value: DEST_PREPEND + INITIAL_TEXT },
|
|
257
|
+
name: 'r2_alpha_v1_dest_prependedText',
|
|
258
|
+
});
|
|
225
259
|
|
|
226
260
|
// #endregion r2 dest edits
|
|
227
261
|
|
|
228
262
|
await respecfully(sir, `r2 verify pre`, async () => {
|
|
229
|
-
await ifWeMight(sir, '
|
|
230
|
-
//
|
|
263
|
+
await ifWeMight(sir, 'texts as expected', async () => {
|
|
264
|
+
// before the sync, each side only has their edit. after the sync,
|
|
265
|
+
// both sides should have both prepended and appended text
|
|
266
|
+
iReckon(sir, r2_alpha_v1_source_appendedText.ibGib.data?.text.includes(INITIAL_TEXT)).asTo('alpha source has initial text').isGonnaBeTrue();
|
|
267
|
+
iReckon(sir, r2_alpha_v1_source_appendedText.ibGib.data?.text.includes(SOURCE_APPEND)).asTo('alpha source has appended text').isGonnaBeTrue();
|
|
268
|
+
iReckon(sir, r2_alpha_v1_source_appendedText.ibGib.data?.text.includes(DEST_PREPEND)).asTo('alpha source does NOT have prepended text').isGonnaBeFalse();
|
|
269
|
+
iReckon(sir, r2_alpha_v1_dest_prependedText.ibGib.data?.text.includes(INITIAL_TEXT)).asTo('alpha dest has initial text').isGonnaBeTrue();
|
|
270
|
+
iReckon(sir, r2_alpha_v1_dest_prependedText.ibGib.data?.text.includes(SOURCE_APPEND)).asTo('alpha dest does NOT have appended text').isGonnaBeFalse();
|
|
271
|
+
iReckon(sir, r2_alpha_v1_dest_prependedText.ibGib.data?.text.includes(DEST_PREPEND)).asTo('alpha dest has prepended text').isGonnaBeTrue();
|
|
231
272
|
});
|
|
232
273
|
});
|
|
233
274
|
|
|
234
|
-
if (logalot) { console.log(`${lc} Running r2 Sync (simple
|
|
275
|
+
if (logalot) { console.log(`${lc} Running r2 Sync (simple data.text conflict)...`); }
|
|
235
276
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
277
|
+
let r2_syncSaga: SyncSagaInfo | undefined;
|
|
278
|
+
try {
|
|
279
|
+
r2_syncSaga = await senderCoordinator.sync({
|
|
280
|
+
peer: await newTestPeer(),
|
|
281
|
+
localSpace: sourceSpace,
|
|
282
|
+
metaspace,
|
|
283
|
+
domainIbGibs: [r2_alpha_v1_source_appendedText.ibGib],
|
|
284
|
+
conflictStrategy: SyncConflictStrategy.optimisticWithLCS,
|
|
285
|
+
useSessionIdentity: false,
|
|
286
|
+
});
|
|
287
|
+
await r2_syncSaga.done;
|
|
288
|
+
} catch (e) {
|
|
289
|
+
console.error(`${lc} R2 Sync Failed:`, e);
|
|
290
|
+
iReckon(sir, false).asTo(`R2 failed: ${e}`).isGonnaBeTruthy();
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
246
293
|
|
|
247
294
|
await respecfully(sir, `r2 verify post`, async () => {
|
|
295
|
+
const kv_source = await senderCoordinator.getKnowledgeMap({ space: sourceSpace, metaspace, domainIbGibs: [r1_alpha_v0_source.ibGib] });
|
|
296
|
+
const kv_dest = await senderCoordinator.getKnowledgeMap({ space: destSpace, metaspace, domainIbGibs: [r1_alpha_v0_source.ibGib] });
|
|
297
|
+
const r2_alpha_source_tipAddr = kv_source[alpha_tjpAddr];
|
|
298
|
+
if (!r2_alpha_source_tipAddr) {
|
|
299
|
+
await ifWeMight(sir, 'r2_alpha_source_tipAddr falsy?', async () => {
|
|
300
|
+
iReckon(sir, true).asTo('fails').isGonnaBe(false);
|
|
301
|
+
});
|
|
302
|
+
return; /* <<<< returns early */
|
|
303
|
+
}
|
|
304
|
+
const r2_alpha_dest_tipAddr = kv_dest[alpha_tjpAddr];
|
|
305
|
+
if (!r2_alpha_dest_tipAddr) {
|
|
306
|
+
await ifWeMight(sir, 'r2_alpha_dest_tipAddr falsy?', async () => {
|
|
307
|
+
iReckon(sir, true).asTo('fails').isGonnaBe(false);
|
|
308
|
+
});
|
|
309
|
+
return; /* <<<< returns early */
|
|
310
|
+
}
|
|
311
|
+
const [r2_alpha_source_tip] = await getIbGibsFromCache_fallbackToSpaces({
|
|
312
|
+
addrs: [r2_alpha_source_tipAddr],
|
|
313
|
+
space: sourceSpace,
|
|
314
|
+
});
|
|
315
|
+
const [r2_alpha_dest_tip] = await getIbGibsFromCache_fallbackToSpaces({
|
|
316
|
+
addrs: [r2_alpha_dest_tipAddr],
|
|
317
|
+
space: sourceSpace,
|
|
318
|
+
});
|
|
319
|
+
|
|
248
320
|
await ifWeMight(sir, 'r2 tip addrs match', async () => {
|
|
249
|
-
|
|
321
|
+
iReckon(sir, r2_alpha_source_tipAddr).asTo('alpha').isGonnaBe(r2_alpha_dest_tipAddr);
|
|
250
322
|
});
|
|
251
323
|
|
|
252
324
|
await ifWeMight(sir, 'r2 text merged correctly', async () => {
|
|
253
|
-
//
|
|
254
|
-
//
|
|
325
|
+
// before the sync, each side only has their edit. after the sync,
|
|
326
|
+
// both sides should have both prepended and appended text
|
|
327
|
+
iReckon(sir, r2_alpha_v1_source_appendedText.ibGib.data?.text.includes(INITIAL_TEXT)).asTo('alpha source has initial text').isGonnaBeTrue();
|
|
328
|
+
iReckon(sir, r2_alpha_v1_source_appendedText.ibGib.data?.text.includes(SOURCE_APPEND)).asTo('alpha source has appended text').isGonnaBeTrue();
|
|
329
|
+
iReckon(sir, r2_alpha_v1_source_appendedText.ibGib.data?.text.includes(DEST_PREPEND)).asTo('alpha source has prepended text').isGonnaBeFalse();
|
|
330
|
+
iReckon(sir, r2_alpha_v1_dest_prependedText.ibGib.data?.text.includes(INITIAL_TEXT)).asTo('alpha dest has initial text').isGonnaBeTrue();
|
|
331
|
+
iReckon(sir, r2_alpha_v1_dest_prependedText.ibGib.data?.text.includes(SOURCE_APPEND)).asTo('alpha dest has appended text').isGonnaBeFalse();
|
|
332
|
+
iReckon(sir, r2_alpha_v1_dest_prependedText.ibGib.data?.text.includes(DEST_PREPEND)).asTo('alpha dest has prepended text').isGonnaBeTrue();
|
|
333
|
+
|
|
334
|
+
// actually both should be the same text now of course
|
|
335
|
+
iReckon(sir, r2_alpha_source_tip.data?.text).asTo('source/dest same text').isGonnaBe(r2_alpha_dest_tip.data?.text);
|
|
336
|
+
|
|
337
|
+
const text = r2_alpha_source_tip.data?.text;
|
|
338
|
+
|
|
339
|
+
// we'll go one step further and assume the final output is exactly this
|
|
340
|
+
iReckon(sir, text).asTo('R2 has both prepend and append').isGonnaBe(DEST_PREPEND + INITIAL_TEXT + SOURCE_APPEND);
|
|
255
341
|
});
|
|
256
342
|
|
|
257
343
|
await ifWeMight(sir, 'r2 dep graphs synced', async () => {
|
|
258
|
-
//
|
|
344
|
+
// alpha's full dep graph should exist on dest
|
|
345
|
+
const depGraph_alpha_source = await getDependencyGraph({
|
|
346
|
+
ibGib: r2_alpha_source_tip,
|
|
347
|
+
live: true,
|
|
348
|
+
space: sourceSpace
|
|
349
|
+
});
|
|
350
|
+
const depGraph_alpha_dest = await getDependencyGraph({
|
|
351
|
+
ibGib: r2_alpha_dest_tip,
|
|
352
|
+
live: true,
|
|
353
|
+
space: destSpace
|
|
354
|
+
});
|
|
355
|
+
const alphaDepsAreEqual = graphsAreEquivalent({
|
|
356
|
+
graphA: depGraph_alpha_source,
|
|
357
|
+
graphB: depGraph_alpha_dest,
|
|
358
|
+
slowButThorough: true,
|
|
359
|
+
});
|
|
360
|
+
iReckon(sir, alphaDepsAreEqual).asTo('alpha got synced and graphs are equal').isGonnaBeTrue();
|
|
259
361
|
});
|
|
260
362
|
});
|
|
261
363
|
|
|
@@ -263,168 +365,228 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
|
|
|
263
365
|
|
|
264
366
|
// #region Round 3: Interleaved edits - different paragraphs
|
|
265
367
|
|
|
266
|
-
const _r3 = testTransformer.newRound({
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
});
|
|
368
|
+
// const _r3 = testTransformer.newRound({
|
|
369
|
+
// name: 'r3_interleaved_paragraphs',
|
|
370
|
+
// description: 'Source edits paragraph 1, dest edits paragraph 2 - should merge both changes'
|
|
371
|
+
// });
|
|
270
372
|
|
|
271
|
-
// #region r3 source edits
|
|
373
|
+
// // #region r3 source edits
|
|
272
374
|
|
|
273
|
-
if (logalot) { console.log(`${lc} R3: Source editing first paragraph...`); }
|
|
375
|
+
// if (logalot) { console.log(`${lc} R3: Source editing first paragraph...`); }
|
|
274
376
|
|
|
275
|
-
//
|
|
276
|
-
//
|
|
377
|
+
// const resGet_r3_source = await getFromSpace({ space: sourceSpace, addr: alpha_tjpAddr });
|
|
378
|
+
// const r3_v0_graft = resGet_r3_source.ibGibs![0] as IbGib_V1<TestData>;
|
|
379
|
+
// const r3_currentText = r3_v0_graft.data!.text!;
|
|
277
380
|
|
|
278
|
-
//
|
|
381
|
+
// // Split into lines, modify first paragraph (line 1)
|
|
382
|
+
// const lines = r3_currentText.split('\n');
|
|
383
|
+
// lines[0] = "This is the UPDATED quiz question."; // Source edits line 1
|
|
384
|
+
// const r3_sourceModifiedText = lines.join('\n');
|
|
279
385
|
|
|
280
|
-
//
|
|
386
|
+
// const r3_v1_source = await testTransformer.mut8({
|
|
387
|
+
// ibGib: r3_v0_graft,
|
|
388
|
+
// in: 'source',
|
|
389
|
+
// strField: { name: 'text', value: r3_sourceModifiedText },
|
|
390
|
+
// name: 'r3_v1_source',
|
|
391
|
+
// });
|
|
281
392
|
|
|
282
|
-
|
|
393
|
+
// // #endregion r3 source edits
|
|
283
394
|
|
|
284
|
-
//
|
|
285
|
-
// TODO: Mutate - modify second paragraph only
|
|
395
|
+
// // #region r3 dest edits
|
|
286
396
|
|
|
287
|
-
//
|
|
397
|
+
// if (logalot) { console.log(`${lc} R3: Dest editing second paragraph...`); }
|
|
288
398
|
|
|
289
|
-
await
|
|
290
|
-
|
|
291
|
-
// TODO: Verify pre-sync state
|
|
292
|
-
});
|
|
293
|
-
});
|
|
399
|
+
// const resGet_r3_dest = await getFromSpace({ space: destSpace, addr: alpha_tjpAddr });
|
|
400
|
+
// const r3_v0_graft_fromDest = resGet_r3_dest.ibGibs![0] as IbGib_V1<TestData>;
|
|
294
401
|
|
|
295
|
-
|
|
402
|
+
// // Split and modify third line
|
|
403
|
+
// const destLines = r3_v0_graft_fromDest.data!.text!.split('\n');
|
|
404
|
+
// destLines[2] = "Students will DEFINITELY answer this."; // Dest edits line 3
|
|
405
|
+
// const r3_destModifiedText = destLines.join('\n');
|
|
296
406
|
|
|
297
|
-
//
|
|
407
|
+
// const r3_v1_dest = await testTransformer.mut8({
|
|
408
|
+
// ibGib: r3_v0_graft_fromDest,
|
|
409
|
+
// in: 'dest',
|
|
410
|
+
// strField: { name: 'text', value: r3_destModifiedText },
|
|
411
|
+
// name: 'r3_v1_dest',
|
|
412
|
+
// });
|
|
298
413
|
|
|
299
|
-
|
|
300
|
-
await ifWeMight(sir, 'r3 tip addrs match', async () => {
|
|
301
|
-
// TODO: Verify tips match
|
|
302
|
-
});
|
|
414
|
+
// // #endregion r3 dest edits
|
|
303
415
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
416
|
+
// await respecfully(sir, `r3 verify pre`, async () => {
|
|
417
|
+
// await ifWeMight(sir, 'dest has alpha after R2 graft', async () => {
|
|
418
|
+
// const kv = await receiverCoordinator.getKnowledgeMap({ space: destSpace, metaspace, domainIbGibs: [r3_v0_graft_fromDest] });
|
|
419
|
+
// iReckon(sir, !!kv[alpha_tjpAddr]).asTo('dest has tip').isGonnaBeTrue();
|
|
420
|
+
// });
|
|
421
|
+
// });
|
|
309
422
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
423
|
+
// if (logalot) { console.log(`${lc} Running r3 Sync (interleaved paragraphs)...`); }
|
|
424
|
+
|
|
425
|
+
// let r3_syncSaga: SyncSagaInfo | undefined;
|
|
426
|
+
// try {
|
|
427
|
+
// r3_syncSaga = await senderCoordinator.sync({
|
|
428
|
+
// peer: await newTestPeer(),
|
|
429
|
+
// localSpace: sourceSpace,
|
|
430
|
+
// metaspace,
|
|
431
|
+
// domainIbGibs: [r3_v1_source.ibGib],
|
|
432
|
+
// conflictStrategy: SyncConflictStrategy.optimisticWithLCS,
|
|
433
|
+
// useSessionIdentity: false,
|
|
434
|
+
// });
|
|
435
|
+
// await r3_syncSaga.done;
|
|
436
|
+
// } catch (e) {
|
|
437
|
+
// console.error(`${lc} R3 Sync Failed:`, e);
|
|
438
|
+
// iReckon(sir, false).asTo(`R3 failed: ${e}`).isGonnaBeTruthy();
|
|
439
|
+
// return;
|
|
440
|
+
// }
|
|
441
|
+
|
|
442
|
+
// await respecfully(sir, `r3 verify post`, async () => {
|
|
443
|
+
// const kv_s = await senderCoordinator.getKnowledgeMap({ space: sourceSpace, metaspace, domainIbGibs: [r1_alpha_v0_source.ibGib] });
|
|
444
|
+
// const kv_d = await senderCoordinator.getKnowledgeMap({ space: destSpace, metaspace, domainIbGibs: [r1_alpha_v0_source.ibGib] });
|
|
445
|
+
// const r3_tip_s = kv_s[alpha_tjpAddr];
|
|
446
|
+
// const r3_tip_d = kv_d[alpha_tjpAddr];
|
|
447
|
+
|
|
448
|
+
// await ifWeMight(sir, 'r3 tip addrs match', async () => {
|
|
449
|
+
// iReckon(sir, r3_tip_s).asTo('R3 tips match').isGonnaBe(r3_tip_d);
|
|
450
|
+
// });
|
|
451
|
+
|
|
452
|
+
// await ifWeMight(sir, 'r3 both paragraph edits merged', async () => {
|
|
453
|
+
// const res = await getFromSpace({ space: sourceSpace, addr: r3_tip_s! });
|
|
454
|
+
// const tip = res.ibGibs![0] as IbGib_V1<TestData>;
|
|
455
|
+
// const mergedText = tip.data!.text!;
|
|
456
|
+
|
|
457
|
+
// // Should have BOTH source's line 1 change AND dest's line 3 change
|
|
458
|
+
// iReckon(sir, mergedText.includes("UPDATED quiz question"))
|
|
459
|
+
// .asTo('has source paragraph 1 edit')
|
|
460
|
+
// .isGonnaBeTrue();
|
|
461
|
+
// iReckon(sir, mergedText.includes("DEFINITELY answer this"))
|
|
462
|
+
// .asTo('has dest paragraph 2 edit')
|
|
463
|
+
// .isGonnaBeTrue();
|
|
464
|
+
|
|
465
|
+
// // Verify middle line unchanged
|
|
466
|
+
// iReckon(sir, mergedText.includes("It has multiple lines"))
|
|
467
|
+
// .asTo('middle line preserved')
|
|
468
|
+
// .isGonnaBeTrue();
|
|
469
|
+
// });
|
|
470
|
+
|
|
471
|
+
// await ifWeMight(sir, 'r3 dep graphs synced', async () => {
|
|
472
|
+
// const [d] = await getIbGibsFromCache_fallbackToSpaces({ addrs: [r3_tip_s!], space: destSpace });
|
|
473
|
+
// iReckon(sir, d).asTo('exists dest').isGonnaBeTruthy();
|
|
474
|
+
// });
|
|
475
|
+
// });
|
|
314
476
|
|
|
315
477
|
// #endregion Round 3: Interleaved edits - different paragraphs
|
|
316
478
|
|
|
317
479
|
// #region Round 4: Same paragraph conflict
|
|
318
480
|
|
|
319
|
-
const _r4 = testTransformer.newRound({
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
});
|
|
481
|
+
// const _r4 = testTransformer.newRound({
|
|
482
|
+
// name: 'r4_same_paragraph_conflict',
|
|
483
|
+
// description: 'Both edit same paragraph - LCS should merge at word/character level'
|
|
484
|
+
// });
|
|
323
485
|
|
|
324
|
-
// #region r4 source edits
|
|
486
|
+
// // #region r4 source edits
|
|
325
487
|
|
|
326
|
-
if (logalot) { console.log(`${lc} R4: Source editing same paragraph...`); }
|
|
488
|
+
// if (logalot) { console.log(`${lc} R4: Source editing same paragraph...`); }
|
|
327
489
|
|
|
328
|
-
// TODO: Retrieve from source
|
|
329
|
-
// TODO: Mutate - edit specific words in paragraph
|
|
490
|
+
// // TODO: Retrieve from source
|
|
491
|
+
// // TODO: Mutate - edit specific words in paragraph
|
|
330
492
|
|
|
331
|
-
// #endregion r4 source edits
|
|
493
|
+
// // #endregion r4 source edits
|
|
332
494
|
|
|
333
|
-
// #region r4 dest edits
|
|
495
|
+
// // #region r4 dest edits
|
|
334
496
|
|
|
335
|
-
if (logalot) { console.log(`${lc} R4: Dest editing same paragraph (different words)...`); }
|
|
497
|
+
// if (logalot) { console.log(`${lc} R4: Dest editing same paragraph (different words)...`); }
|
|
336
498
|
|
|
337
|
-
// TODO: Retrieve from dest
|
|
338
|
-
// TODO: Mutate - edit different words in same paragraph
|
|
499
|
+
// // TODO: Retrieve from dest
|
|
500
|
+
// // TODO: Mutate - edit different words in same paragraph
|
|
339
501
|
|
|
340
|
-
// #endregion r4 dest edits
|
|
502
|
+
// // #endregion r4 dest edits
|
|
341
503
|
|
|
342
|
-
await respecfully(sir, `r4 verify pre`, async () => {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
});
|
|
504
|
+
// await respecfully(sir, `r4 verify pre`, async () => {
|
|
505
|
+
// await ifWeMight(sir, 'dest has alpha after R3 graft', async () => {
|
|
506
|
+
// // TODO: Verify pre-sync state
|
|
507
|
+
// });
|
|
508
|
+
// });
|
|
347
509
|
|
|
348
|
-
if (logalot) { console.log(`${lc} Running r4 Sync (same paragraph conflict)...`); }
|
|
510
|
+
// if (logalot) { console.log(`${lc} Running r4 Sync (same paragraph conflict)...`); }
|
|
349
511
|
|
|
350
|
-
// TODO: Add sync operation
|
|
512
|
+
// // TODO: Add sync operation
|
|
351
513
|
|
|
352
|
-
await respecfully(sir, `r4 verify post`, async () => {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
514
|
+
// await respecfully(sir, `r4 verify post`, async () => {
|
|
515
|
+
// await ifWeMight(sir, 'r4 tip addrs match', async () => {
|
|
516
|
+
// // TODO: Verify tips match
|
|
517
|
+
// });
|
|
356
518
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
519
|
+
// await ifWeMight(sir, 'r4 LCS merged both word changes', async () => {
|
|
520
|
+
// // TODO: Verify text has both source and dest word changes
|
|
521
|
+
// // TODO: Verify LCS algorithm preserved both edits correctly
|
|
522
|
+
// });
|
|
361
523
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
});
|
|
524
|
+
// await ifWeMight(sir, 'r4 dep graphs synced', async () => {
|
|
525
|
+
// // TODO: Verify dep graphs
|
|
526
|
+
// });
|
|
527
|
+
// });
|
|
366
528
|
|
|
367
529
|
// #endregion Round 4: Same paragraph conflict
|
|
368
530
|
|
|
369
531
|
// #region Round 5: Multi-field text merge
|
|
370
532
|
|
|
371
|
-
const _r5 = testTransformer.newRound({
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
});
|
|
533
|
+
// const _r5 = testTransformer.newRound({
|
|
534
|
+
// name: 'r5_multi_field_text',
|
|
535
|
+
// description: 'Conflicting text edits in BOTH text and description fields simultaneously'
|
|
536
|
+
// });
|
|
375
537
|
|
|
376
|
-
// #region r5 source edits
|
|
538
|
+
// // #region r5 source edits
|
|
377
539
|
|
|
378
|
-
if (logalot) { console.log(`${lc} R5: Source editing both text and description...`); }
|
|
540
|
+
// if (logalot) { console.log(`${lc} R5: Source editing both text and description...`); }
|
|
379
541
|
|
|
380
|
-
// TODO: Retrieve from source
|
|
381
|
-
// TODO: Mutate text field
|
|
382
|
-
// TODO: Mutate description field (in same mut8 or separate)
|
|
542
|
+
// // TODO: Retrieve from source
|
|
543
|
+
// // TODO: Mutate text field
|
|
544
|
+
// // TODO: Mutate description field (in same mut8 or separate)
|
|
383
545
|
|
|
384
|
-
// #endregion r5 source edits
|
|
546
|
+
// // #endregion r5 source edits
|
|
385
547
|
|
|
386
|
-
// #region r5 dest edits
|
|
548
|
+
// // #region r5 dest edits
|
|
387
549
|
|
|
388
|
-
if (logalot) { console.log(`${lc} R5: Dest editing both text and description differently...`); }
|
|
550
|
+
// if (logalot) { console.log(`${lc} R5: Dest editing both text and description differently...`); }
|
|
389
551
|
|
|
390
|
-
// TODO: Retrieve from dest
|
|
391
|
-
// TODO: Mutate text field (different changes)
|
|
392
|
-
// TODO: Mutate description field (different changes)
|
|
552
|
+
// // TODO: Retrieve from dest
|
|
553
|
+
// // TODO: Mutate text field (different changes)
|
|
554
|
+
// // TODO: Mutate description field (different changes)
|
|
393
555
|
|
|
394
|
-
// #endregion r5 dest edits
|
|
556
|
+
// // #endregion r5 dest edits
|
|
395
557
|
|
|
396
|
-
await respecfully(sir, `r5 verify pre`, async () => {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
});
|
|
558
|
+
// await respecfully(sir, `r5 verify pre`, async () => {
|
|
559
|
+
// await ifWeMight(sir, 'dest has alpha after R4 graft', async () => {
|
|
560
|
+
// // TODO: Verify pre-sync state
|
|
561
|
+
// });
|
|
562
|
+
// });
|
|
401
563
|
|
|
402
|
-
if (logalot) { console.log(`${lc} Running r5 Sync (multi-field text merge)...`); }
|
|
564
|
+
// if (logalot) { console.log(`${lc} Running r5 Sync (multi-field text merge)...`); }
|
|
403
565
|
|
|
404
|
-
// TODO: Add sync operation
|
|
566
|
+
// // TODO: Add sync operation
|
|
405
567
|
|
|
406
|
-
await respecfully(sir, `r5 verify post`, async () => {
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
568
|
+
// await respecfully(sir, `r5 verify post`, async () => {
|
|
569
|
+
// await ifWeMight(sir, 'r5 tip addrs match', async () => {
|
|
570
|
+
// // TODO: Verify tips match
|
|
571
|
+
// });
|
|
410
572
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
573
|
+
// await ifWeMight(sir, 'r5 text field merged', async () => {
|
|
574
|
+
// // TODO: Verify text field has both source and dest changes
|
|
575
|
+
// });
|
|
414
576
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
577
|
+
// await ifWeMight(sir, 'r5 description field merged', async () => {
|
|
578
|
+
// // TODO: Verify description field has both source and dest changes
|
|
579
|
+
// });
|
|
418
580
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
581
|
+
// await ifWeMight(sir, 'r5 both fields independently LCS-merged', async () => {
|
|
582
|
+
// // TODO: Verify each field was merged independently
|
|
583
|
+
// // TODO: Ensure one field's merge didn't affect the other
|
|
584
|
+
// });
|
|
423
585
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
});
|
|
586
|
+
// await ifWeMight(sir, 'r5 dep graphs synced', async () => {
|
|
587
|
+
// // TODO: Verify dep graphs
|
|
588
|
+
// });
|
|
589
|
+
// });
|
|
428
590
|
|
|
429
591
|
// #endregion Round 5: Multi-field text merge
|
|
430
592
|
});
|