@ibgib/core-gib 0.1.41 → 0.1.43
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 +314 -181
- package/dist/sync/sync-conflict-text-merge.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-dest-ahead-withid.respec.d.mts +7 -0
- package/dist/sync/sync-innerspace-dest-ahead-withid.respec.d.mts.map +1 -0
- package/dist/sync/sync-innerspace-dest-ahead-withid.respec.mjs +252 -0
- package/dist/sync/sync-innerspace-dest-ahead-withid.respec.mjs.map +1 -0
- package/dist/sync/sync-saga-coordinator.mjs +3 -3
- package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
- package/dist/test/mock-space.d.mts +1 -38
- package/dist/test/mock-space.d.mts.map +1 -1
- package/dist/test/mock-space.mjs +73 -78
- package/dist/test/mock-space.mjs.map +1 -1
- package/package.json +1 -1
- package/src/keystone/README.md +118 -0
- package/src/keystone/docs/architecture.md +30 -1
- package/src/sync/README.md +122 -5
- package/src/sync/docs/architecture.md +2 -2
- package/src/sync/{SYNC_TESTING.md → docs/testing.md} +113 -28
- package/src/sync/sync-conflict-adv-multitimelines.respec.mts +3 -3
- package/src/sync/sync-conflict-text-merge.respec.mts +326 -164
- package/src/sync/sync-innerspace-dest-ahead-withid.respec.mts +316 -0
- package/src/sync/sync-saga-coordinator.mts +4 -4
- package/src/test/mock-space.mts +72 -72
- package/src/sync/docs/verification.md +0 -43
|
@@ -2,9 +2,12 @@
|
|
|
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
|
-
import { respecfully,
|
|
10
|
+
import { respecfully, ifWe, iReckon } from '@ibgib/helper-gib/dist/respec-gib/respec-gib.mjs';
|
|
8
11
|
const maam = `[${import.meta.url}]`, sir = maam;
|
|
9
12
|
import { clone, delay, extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
10
13
|
import { GLOBAL_LOG_A_LOT } from '../core-constants.mjs';
|
|
@@ -73,19 +76,19 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
|
|
|
73
76
|
description: 'Create timeline with initial text, sync to establish common history'
|
|
74
77
|
});
|
|
75
78
|
if (logalot) {
|
|
76
|
-
console.log(`${lc} R1: Creating initial
|
|
79
|
+
console.log(`${lc} R1: Creating initial alpha with text...`);
|
|
77
80
|
}
|
|
78
|
-
// Create
|
|
81
|
+
// Create alpha with initial text on source
|
|
79
82
|
const INITIAL_TEXT = "This is the initial quiz question.\nIt has multiple lines.\nStudents will answer this.";
|
|
80
|
-
const
|
|
81
|
-
atom: '
|
|
83
|
+
const r1_alpha_v0_source = await testTransformer.create({
|
|
84
|
+
atom: 'alpha',
|
|
82
85
|
in: 'source',
|
|
83
86
|
data: { text: INITIAL_TEXT },
|
|
84
|
-
name: '
|
|
87
|
+
name: 'r1_alpha_v0_source'
|
|
85
88
|
});
|
|
86
|
-
const
|
|
89
|
+
const alpha_tjpAddr = getTjpAddr({ ibGib: r1_alpha_v0_source.ibGib, defaultIfNone: 'incomingAddr' });
|
|
87
90
|
if (logalot) {
|
|
88
|
-
console.log(`${lc} R1: Syncing initial
|
|
91
|
+
console.log(`${lc} R1: Syncing initial alpha to dest...`);
|
|
89
92
|
}
|
|
90
93
|
let r1_syncSaga;
|
|
91
94
|
try {
|
|
@@ -93,7 +96,7 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
|
|
|
93
96
|
peer: await newTestPeer(),
|
|
94
97
|
localSpace: sourceSpace,
|
|
95
98
|
metaspace,
|
|
96
|
-
domainIbGibs: [
|
|
99
|
+
domainIbGibs: [r1_alpha_v0_source.ibGib],
|
|
97
100
|
conflictStrategy: SyncConflictStrategy.optimisticWithLCS,
|
|
98
101
|
useSessionIdentity: false,
|
|
99
102
|
});
|
|
@@ -110,49 +113,65 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
|
|
|
110
113
|
// Verify both sides have same text
|
|
111
114
|
await respecfully(sir, `r1 verify post`, async () => {
|
|
112
115
|
try {
|
|
113
|
-
const
|
|
116
|
+
const r1_alpha_sourceKV = await senderCoordinator.getKnowledgeMap({
|
|
114
117
|
space: sourceSpace,
|
|
115
118
|
metaspace,
|
|
116
|
-
domainIbGibs: [
|
|
119
|
+
domainIbGibs: [r1_alpha_v0_source.ibGib]
|
|
117
120
|
});
|
|
118
|
-
const
|
|
119
|
-
|
|
121
|
+
const r1_alpha_source_tipAddr = r1_alpha_sourceKV[alpha_tjpAddr];
|
|
122
|
+
if (!r1_alpha_source_tipAddr) {
|
|
123
|
+
ifWe(sir, 'r1_alpha_source_tipAddr is falsy?', async () => {
|
|
124
|
+
iReckon(sir, true).asTo('fail').isGonnaBeFalse();
|
|
125
|
+
});
|
|
126
|
+
return; /* <<<< returns early */
|
|
127
|
+
}
|
|
128
|
+
const r1_alpha_destKV = await senderCoordinator.getKnowledgeMap({
|
|
120
129
|
space: destSpace,
|
|
121
130
|
metaspace,
|
|
122
|
-
domainIbGibs: [
|
|
131
|
+
domainIbGibs: [r1_alpha_v0_source.ibGib]
|
|
123
132
|
});
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
133
|
+
const r1_alpha_dest_tipAddr = r1_alpha_destKV[alpha_tjpAddr];
|
|
134
|
+
if (!r1_alpha_dest_tipAddr) {
|
|
135
|
+
ifWe(sir, 'r1_alpha_dest_tipAddr is falsy?', async () => {
|
|
136
|
+
iReckon(sir, true).asTo('fail').isGonnaBeFalse();
|
|
137
|
+
});
|
|
138
|
+
return; /* <<<< returns early */
|
|
139
|
+
}
|
|
140
|
+
await ifWe(sir, 'r1 tip addrs match', async () => {
|
|
141
|
+
iReckon(sir, r1_alpha_source_tipAddr).asTo('R1 source/dest have same tip').isGonnaBe(r1_alpha_dest_tipAddr);
|
|
127
142
|
});
|
|
128
|
-
await
|
|
129
|
-
if (!
|
|
143
|
+
await ifWe(sir, 'r1 text synced correctly', async () => {
|
|
144
|
+
if (!r1_alpha_dest_tipAddr) {
|
|
130
145
|
throw new Error(`r1_dest_tipAddr is null/undefined (E: 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d)`);
|
|
131
146
|
}
|
|
132
|
-
const resGet_destTip = await getFromSpace({ space: destSpace, addr:
|
|
147
|
+
const resGet_destTip = await getFromSpace({ space: destSpace, addr: r1_alpha_dest_tipAddr });
|
|
133
148
|
const destTipIbGib = resGet_destTip.ibGibs[0];
|
|
134
149
|
iReckon(sir, destTipIbGib.data.text).asTo('Dest has initial text').isGonnaBe(INITIAL_TEXT);
|
|
135
150
|
});
|
|
136
|
-
await
|
|
137
|
-
const [
|
|
138
|
-
addrs: [
|
|
151
|
+
await ifWe(sir, 'r1 dep graphs synced', async () => {
|
|
152
|
+
const [r1_alpha_source_tip] = await getIbGibsFromCache_fallbackToSpaces({
|
|
153
|
+
addrs: [r1_alpha_source_tipAddr],
|
|
154
|
+
space: sourceSpace,
|
|
155
|
+
});
|
|
156
|
+
const [r1_alpha_dest_tip] = await getIbGibsFromCache_fallbackToSpaces({
|
|
157
|
+
addrs: [r1_alpha_dest_tipAddr],
|
|
139
158
|
space: destSpace,
|
|
140
159
|
});
|
|
141
|
-
iReckon(sir,
|
|
142
|
-
if (
|
|
143
|
-
const
|
|
144
|
-
ibGib:
|
|
160
|
+
iReckon(sir, r1_alpha_dest_tip).asTo('alpha tip exists in dest').isGonnaBeTruthy();
|
|
161
|
+
if (r1_alpha_dest_tip) {
|
|
162
|
+
const r1_alpha_source_depGraph = await getDependencyGraph({
|
|
163
|
+
ibGib: r1_alpha_source_tip,
|
|
145
164
|
live: true,
|
|
146
165
|
space: sourceSpace
|
|
147
166
|
});
|
|
148
|
-
const
|
|
149
|
-
ibGib:
|
|
167
|
+
const r1_alpha_dest_depGraph = await getDependencyGraph({
|
|
168
|
+
ibGib: r1_alpha_dest_tip,
|
|
150
169
|
live: true,
|
|
151
170
|
space: destSpace
|
|
152
171
|
});
|
|
153
172
|
const graphsEqual = graphsAreEquivalent({
|
|
154
|
-
graphA:
|
|
155
|
-
graphB:
|
|
173
|
+
graphA: r1_alpha_source_depGraph,
|
|
174
|
+
graphB: r1_alpha_dest_depGraph,
|
|
156
175
|
slowButThorough: true,
|
|
157
176
|
});
|
|
158
177
|
iReckon(sir, graphsEqual).asTo('R1 dep graphs equal').isGonnaBeTrue();
|
|
@@ -174,178 +193,292 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
|
|
|
174
193
|
if (logalot) {
|
|
175
194
|
console.log(`${lc} R2: Source appending to end of text...`);
|
|
176
195
|
}
|
|
177
|
-
//
|
|
178
|
-
//
|
|
196
|
+
// const resGet_r2_source = await getFromSpace({ space: sourceSpace, addr: alpha_tjpAddr });
|
|
197
|
+
// const r2_v0_graft = resGet_r2_source.ibGibs![0] as IbGib_V1<TestData>;
|
|
198
|
+
const SOURCE_APPEND = "\nInstructor added hint.";
|
|
199
|
+
const r2_alpha_v1_source_appendedText = await testTransformer.mut8({
|
|
200
|
+
ibGib: r1_alpha_v0_source.ibGib,
|
|
201
|
+
in: 'source',
|
|
202
|
+
strField: { name: 'text', value: INITIAL_TEXT + SOURCE_APPEND },
|
|
203
|
+
name: 'r2_alpha_v1_source_appendedText',
|
|
204
|
+
});
|
|
179
205
|
// #endregion r2 source edits
|
|
180
206
|
// #region r2 dest edits
|
|
181
207
|
if (logalot) {
|
|
182
208
|
console.log(`${lc} R2: Dest prepending to beginning of text...`);
|
|
183
209
|
}
|
|
184
|
-
|
|
185
|
-
|
|
210
|
+
const resGet_r2_dest = await getFromSpace({ space: destSpace, addr: r1_alpha_v0_source.addr });
|
|
211
|
+
const r2_v0_alpha_dest = resGet_r2_dest.ibGibs[0];
|
|
212
|
+
const DEST_PREPEND = "Student note: Confusing!\n";
|
|
213
|
+
const r2_alpha_v1_dest_prependedText = await testTransformer.mut8({
|
|
214
|
+
ibGib: r2_v0_alpha_dest,
|
|
215
|
+
in: 'dest',
|
|
216
|
+
strField: { name: 'text', value: DEST_PREPEND + INITIAL_TEXT },
|
|
217
|
+
name: 'r2_alpha_v1_dest_prependedText',
|
|
218
|
+
});
|
|
186
219
|
// #endregion r2 dest edits
|
|
187
220
|
await respecfully(sir, `r2 verify pre`, async () => {
|
|
188
|
-
await
|
|
189
|
-
//
|
|
221
|
+
await ifWe(sir, 'texts as expected', async () => {
|
|
222
|
+
// before the sync, each side only has their edit. after the sync,
|
|
223
|
+
// both sides should have both prepended and appended text
|
|
224
|
+
iReckon(sir, r2_alpha_v1_source_appendedText.ibGib.data?.text.includes(INITIAL_TEXT)).asTo('alpha source has initial text').isGonnaBeTrue();
|
|
225
|
+
iReckon(sir, r2_alpha_v1_source_appendedText.ibGib.data?.text.includes(SOURCE_APPEND)).asTo('alpha source has appended text').isGonnaBeTrue();
|
|
226
|
+
iReckon(sir, r2_alpha_v1_source_appendedText.ibGib.data?.text.includes(DEST_PREPEND)).asTo('alpha source does NOT have prepended text').isGonnaBeFalse();
|
|
227
|
+
iReckon(sir, r2_alpha_v1_dest_prependedText.ibGib.data?.text.includes(INITIAL_TEXT)).asTo('alpha dest has initial text').isGonnaBeTrue();
|
|
228
|
+
iReckon(sir, r2_alpha_v1_dest_prependedText.ibGib.data?.text.includes(SOURCE_APPEND)).asTo('alpha dest does NOT have appended text').isGonnaBeFalse();
|
|
229
|
+
iReckon(sir, r2_alpha_v1_dest_prependedText.ibGib.data?.text.includes(DEST_PREPEND)).asTo('alpha dest has prepended text').isGonnaBeTrue();
|
|
190
230
|
});
|
|
191
231
|
});
|
|
192
232
|
if (logalot) {
|
|
193
|
-
console.log(`${lc} Running r2 Sync (simple
|
|
233
|
+
console.log(`${lc} Running r2 Sync (simple data.text conflict)...`);
|
|
194
234
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
// }
|
|
205
|
-
await respecfully(sir, `r2 verify post`, async () => {
|
|
206
|
-
await ifWeMight(sir, 'r2 tip addrs match', async () => {
|
|
207
|
-
// TODO: Verify source/dest have same tip addr
|
|
208
|
-
});
|
|
209
|
-
await ifWeMight(sir, 'r2 text merged correctly', async () => {
|
|
210
|
-
// TODO: Verify merged text has BOTH prepend and append
|
|
211
|
-
// Expected: "Dest prepended sentence.\n" + originalText + "\nSource appended sentence."
|
|
212
|
-
});
|
|
213
|
-
await ifWeMight(sir, 'r2 dep graphs synced', async () => {
|
|
214
|
-
// TODO: Verify dep graphs are equivalent
|
|
235
|
+
let r2_syncSaga;
|
|
236
|
+
try {
|
|
237
|
+
r2_syncSaga = await senderCoordinator.sync({
|
|
238
|
+
peer: await newTestPeer(),
|
|
239
|
+
localSpace: sourceSpace,
|
|
240
|
+
metaspace,
|
|
241
|
+
domainIbGibs: [r2_alpha_v1_source_appendedText.ibGib],
|
|
242
|
+
conflictStrategy: SyncConflictStrategy.optimisticWithLCS,
|
|
243
|
+
useSessionIdentity: false,
|
|
215
244
|
});
|
|
216
|
-
|
|
217
|
-
// #endregion Round 2: Simple append - different parts of text
|
|
218
|
-
// #region Round 3: Interleaved edits - different paragraphs
|
|
219
|
-
const _r3 = testTransformer.newRound({
|
|
220
|
-
name: 'r3_interleaved_paragraphs',
|
|
221
|
-
description: 'Source edits paragraph 1, dest edits paragraph 2 - should merge both changes'
|
|
222
|
-
});
|
|
223
|
-
// #region r3 source edits
|
|
224
|
-
if (logalot) {
|
|
225
|
-
console.log(`${lc} R3: Source editing first paragraph...`);
|
|
245
|
+
await r2_syncSaga.done;
|
|
226
246
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if (logalot) {
|
|
232
|
-
console.log(`${lc} R3: Dest editing second paragraph...`);
|
|
247
|
+
catch (e) {
|
|
248
|
+
console.error(`${lc} R2 Sync Failed:`, e);
|
|
249
|
+
iReckon(sir, false).asTo(`R2 failed: ${e}`).isGonnaBeTruthy();
|
|
250
|
+
return;
|
|
233
251
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
252
|
+
await respecfully(sir, `r2 verify post`, async () => {
|
|
253
|
+
const kv_source = await senderCoordinator.getKnowledgeMap({ space: sourceSpace, metaspace, domainIbGibs: [r1_alpha_v0_source.ibGib] });
|
|
254
|
+
const kv_dest = await senderCoordinator.getKnowledgeMap({ space: destSpace, metaspace, domainIbGibs: [r1_alpha_v0_source.ibGib] });
|
|
255
|
+
const r2_alpha_source_tipAddr = kv_source[alpha_tjpAddr];
|
|
256
|
+
if (!r2_alpha_source_tipAddr) {
|
|
257
|
+
await ifWe(sir, 'r2_alpha_source_tipAddr falsy?', async () => {
|
|
258
|
+
iReckon(sir, true).asTo('fails').isGonnaBe(false);
|
|
259
|
+
});
|
|
260
|
+
return; /* <<<< returns early */
|
|
261
|
+
}
|
|
262
|
+
const r2_alpha_dest_tipAddr = kv_dest[alpha_tjpAddr];
|
|
263
|
+
if (!r2_alpha_dest_tipAddr) {
|
|
264
|
+
await ifWe(sir, 'r2_alpha_dest_tipAddr falsy?', async () => {
|
|
265
|
+
iReckon(sir, true).asTo('fails').isGonnaBe(false);
|
|
266
|
+
});
|
|
267
|
+
return; /* <<<< returns early */
|
|
268
|
+
}
|
|
269
|
+
const [r2_alpha_source_tip] = await getIbGibsFromCache_fallbackToSpaces({
|
|
270
|
+
addrs: [r2_alpha_source_tipAddr],
|
|
271
|
+
space: sourceSpace,
|
|
240
272
|
});
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
await ifWeMight(sir, 'r3 tip addrs match', async () => {
|
|
248
|
-
// TODO: Verify tips match
|
|
273
|
+
const [r2_alpha_dest_tip] = await getIbGibsFromCache_fallbackToSpaces({
|
|
274
|
+
addrs: [r2_alpha_dest_tipAddr],
|
|
275
|
+
space: sourceSpace,
|
|
276
|
+
});
|
|
277
|
+
await ifWe(sir, 'r2 tip addrs match', async () => {
|
|
278
|
+
iReckon(sir, r2_alpha_source_tipAddr).asTo('alpha').isGonnaBe(r2_alpha_dest_tipAddr);
|
|
249
279
|
});
|
|
250
|
-
await
|
|
251
|
-
//
|
|
252
|
-
//
|
|
253
|
-
|
|
280
|
+
await ifWe(sir, 'r2 text merged correctly', async () => {
|
|
281
|
+
// before the sync, each side only has their edit. after the sync,
|
|
282
|
+
// both sides should have both prepended and appended text
|
|
283
|
+
iReckon(sir, r2_alpha_v1_source_appendedText.ibGib.data?.text.includes(INITIAL_TEXT)).asTo('alpha source has initial text').isGonnaBeTrue();
|
|
284
|
+
iReckon(sir, r2_alpha_v1_source_appendedText.ibGib.data?.text.includes(SOURCE_APPEND)).asTo('alpha source has appended text').isGonnaBeTrue();
|
|
285
|
+
iReckon(sir, r2_alpha_v1_source_appendedText.ibGib.data?.text.includes(DEST_PREPEND)).asTo('alpha source has prepended text').isGonnaBeFalse();
|
|
286
|
+
iReckon(sir, r2_alpha_v1_dest_prependedText.ibGib.data?.text.includes(INITIAL_TEXT)).asTo('alpha dest has initial text').isGonnaBeTrue();
|
|
287
|
+
iReckon(sir, r2_alpha_v1_dest_prependedText.ibGib.data?.text.includes(SOURCE_APPEND)).asTo('alpha dest has appended text').isGonnaBeFalse();
|
|
288
|
+
iReckon(sir, r2_alpha_v1_dest_prependedText.ibGib.data?.text.includes(DEST_PREPEND)).asTo('alpha dest has prepended text').isGonnaBeTrue();
|
|
289
|
+
// actually both should be the same text now of course
|
|
290
|
+
iReckon(sir, r2_alpha_source_tip.data?.text).asTo('source/dest same text').isGonnaBe(r2_alpha_dest_tip.data?.text);
|
|
291
|
+
const text = r2_alpha_source_tip.data?.text;
|
|
292
|
+
// we'll go one step further and assume the final output is exactly this
|
|
293
|
+
iReckon(sir, text).asTo('R2 has both prepend and append').isGonnaBe(DEST_PREPEND + INITIAL_TEXT + SOURCE_APPEND);
|
|
254
294
|
});
|
|
255
|
-
await
|
|
256
|
-
//
|
|
295
|
+
await ifWe(sir, 'r2 dep graphs synced', async () => {
|
|
296
|
+
// alpha's full dep graph should exist on dest
|
|
297
|
+
const depGraph_alpha_source = await getDependencyGraph({
|
|
298
|
+
ibGib: r2_alpha_source_tip,
|
|
299
|
+
live: true,
|
|
300
|
+
space: sourceSpace
|
|
301
|
+
});
|
|
302
|
+
const depGraph_alpha_dest = await getDependencyGraph({
|
|
303
|
+
ibGib: r2_alpha_dest_tip,
|
|
304
|
+
live: true,
|
|
305
|
+
space: destSpace
|
|
306
|
+
});
|
|
307
|
+
const alphaDepsAreEqual = graphsAreEquivalent({
|
|
308
|
+
graphA: depGraph_alpha_source,
|
|
309
|
+
graphB: depGraph_alpha_dest,
|
|
310
|
+
slowButThorough: true,
|
|
311
|
+
});
|
|
312
|
+
iReckon(sir, alphaDepsAreEqual).asTo('alpha got synced and graphs are equal').isGonnaBeTrue();
|
|
257
313
|
});
|
|
258
314
|
});
|
|
315
|
+
// #endregion Round 2: Simple append - different parts of text
|
|
316
|
+
// #region Round 3: Interleaved edits - different paragraphs
|
|
317
|
+
// const _r3 = testTransformer.newRound({
|
|
318
|
+
// name: 'r3_interleaved_paragraphs',
|
|
319
|
+
// description: 'Source edits paragraph 1, dest edits paragraph 2 - should merge both changes'
|
|
320
|
+
// });
|
|
321
|
+
// // #region r3 source edits
|
|
322
|
+
// if (logalot) { console.log(`${lc} R3: Source editing first paragraph...`); }
|
|
323
|
+
// const resGet_r3_source = await getFromSpace({ space: sourceSpace, addr: alpha_tjpAddr });
|
|
324
|
+
// const r3_v0_graft = resGet_r3_source.ibGibs![0] as IbGib_V1<TestData>;
|
|
325
|
+
// const r3_currentText = r3_v0_graft.data!.text!;
|
|
326
|
+
// // Split into lines, modify first paragraph (line 1)
|
|
327
|
+
// const lines = r3_currentText.split('\n');
|
|
328
|
+
// lines[0] = "This is the UPDATED quiz question."; // Source edits line 1
|
|
329
|
+
// const r3_sourceModifiedText = lines.join('\n');
|
|
330
|
+
// const r3_v1_source = await testTransformer.mut8({
|
|
331
|
+
// ibGib: r3_v0_graft,
|
|
332
|
+
// in: 'source',
|
|
333
|
+
// strField: { name: 'text', value: r3_sourceModifiedText },
|
|
334
|
+
// name: 'r3_v1_source',
|
|
335
|
+
// });
|
|
336
|
+
// // #endregion r3 source edits
|
|
337
|
+
// // #region r3 dest edits
|
|
338
|
+
// if (logalot) { console.log(`${lc} R3: Dest editing second paragraph...`); }
|
|
339
|
+
// const resGet_r3_dest = await getFromSpace({ space: destSpace, addr: alpha_tjpAddr });
|
|
340
|
+
// const r3_v0_graft_fromDest = resGet_r3_dest.ibGibs![0] as IbGib_V1<TestData>;
|
|
341
|
+
// // Split and modify third line
|
|
342
|
+
// const destLines = r3_v0_graft_fromDest.data!.text!.split('\n');
|
|
343
|
+
// destLines[2] = "Students will DEFINITELY answer this."; // Dest edits line 3
|
|
344
|
+
// const r3_destModifiedText = destLines.join('\n');
|
|
345
|
+
// const r3_v1_dest = await testTransformer.mut8({
|
|
346
|
+
// ibGib: r3_v0_graft_fromDest,
|
|
347
|
+
// in: 'dest',
|
|
348
|
+
// strField: { name: 'text', value: r3_destModifiedText },
|
|
349
|
+
// name: 'r3_v1_dest',
|
|
350
|
+
// });
|
|
351
|
+
// // #endregion r3 dest edits
|
|
352
|
+
// await respecfully(sir, `r3 verify pre`, async () => {
|
|
353
|
+
// await ifWe(sir, 'dest has alpha after R2 graft', async () => {
|
|
354
|
+
// const kv = await receiverCoordinator.getKnowledgeMap({ space: destSpace, metaspace, domainIbGibs: [r3_v0_graft_fromDest] });
|
|
355
|
+
// iReckon(sir, !!kv[alpha_tjpAddr]).asTo('dest has tip').isGonnaBeTrue();
|
|
356
|
+
// });
|
|
357
|
+
// });
|
|
358
|
+
// if (logalot) { console.log(`${lc} Running r3 Sync (interleaved paragraphs)...`); }
|
|
359
|
+
// let r3_syncSaga: SyncSagaInfo | undefined;
|
|
360
|
+
// try {
|
|
361
|
+
// r3_syncSaga = await senderCoordinator.sync({
|
|
362
|
+
// peer: await newTestPeer(),
|
|
363
|
+
// localSpace: sourceSpace,
|
|
364
|
+
// metaspace,
|
|
365
|
+
// domainIbGibs: [r3_v1_source.ibGib],
|
|
366
|
+
// conflictStrategy: SyncConflictStrategy.optimisticWithLCS,
|
|
367
|
+
// useSessionIdentity: false,
|
|
368
|
+
// });
|
|
369
|
+
// await r3_syncSaga.done;
|
|
370
|
+
// } catch (e) {
|
|
371
|
+
// console.error(`${lc} R3 Sync Failed:`, e);
|
|
372
|
+
// iReckon(sir, false).asTo(`R3 failed: ${e}`).isGonnaBeTruthy();
|
|
373
|
+
// return;
|
|
374
|
+
// }
|
|
375
|
+
// await respecfully(sir, `r3 verify post`, async () => {
|
|
376
|
+
// const kv_s = await senderCoordinator.getKnowledgeMap({ space: sourceSpace, metaspace, domainIbGibs: [r1_alpha_v0_source.ibGib] });
|
|
377
|
+
// const kv_d = await senderCoordinator.getKnowledgeMap({ space: destSpace, metaspace, domainIbGibs: [r1_alpha_v0_source.ibGib] });
|
|
378
|
+
// const r3_tip_s = kv_s[alpha_tjpAddr];
|
|
379
|
+
// const r3_tip_d = kv_d[alpha_tjpAddr];
|
|
380
|
+
// await ifWe(sir, 'r3 tip addrs match', async () => {
|
|
381
|
+
// iReckon(sir, r3_tip_s).asTo('R3 tips match').isGonnaBe(r3_tip_d);
|
|
382
|
+
// });
|
|
383
|
+
// await ifWe(sir, 'r3 both paragraph edits merged', async () => {
|
|
384
|
+
// const res = await getFromSpace({ space: sourceSpace, addr: r3_tip_s! });
|
|
385
|
+
// const tip = res.ibGibs![0] as IbGib_V1<TestData>;
|
|
386
|
+
// const mergedText = tip.data!.text!;
|
|
387
|
+
// // Should have BOTH source's line 1 change AND dest's line 3 change
|
|
388
|
+
// iReckon(sir, mergedText.includes("UPDATED quiz question"))
|
|
389
|
+
// .asTo('has source paragraph 1 edit')
|
|
390
|
+
// .isGonnaBeTrue();
|
|
391
|
+
// iReckon(sir, mergedText.includes("DEFINITELY answer this"))
|
|
392
|
+
// .asTo('has dest paragraph 2 edit')
|
|
393
|
+
// .isGonnaBeTrue();
|
|
394
|
+
// // Verify middle line unchanged
|
|
395
|
+
// iReckon(sir, mergedText.includes("It has multiple lines"))
|
|
396
|
+
// .asTo('middle line preserved')
|
|
397
|
+
// .isGonnaBeTrue();
|
|
398
|
+
// });
|
|
399
|
+
// await ifWe(sir, 'r3 dep graphs synced', async () => {
|
|
400
|
+
// const [d] = await getIbGibsFromCache_fallbackToSpaces({ addrs: [r3_tip_s!], space: destSpace });
|
|
401
|
+
// iReckon(sir, d).asTo('exists dest').isGonnaBeTruthy();
|
|
402
|
+
// });
|
|
403
|
+
// });
|
|
259
404
|
// #endregion Round 3: Interleaved edits - different paragraphs
|
|
260
405
|
// #region Round 4: Same paragraph conflict
|
|
261
|
-
const _r4 = testTransformer.newRound({
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
});
|
|
265
|
-
// #region r4 source edits
|
|
266
|
-
if (logalot) {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
//
|
|
270
|
-
//
|
|
271
|
-
//
|
|
272
|
-
//
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
//
|
|
277
|
-
// TODO:
|
|
278
|
-
//
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
// TODO:
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
// TODO: Verify LCS algorithm preserved both edits correctly
|
|
295
|
-
});
|
|
296
|
-
await ifWeMight(sir, 'r4 dep graphs synced', async () => {
|
|
297
|
-
// TODO: Verify dep graphs
|
|
298
|
-
});
|
|
299
|
-
});
|
|
406
|
+
// const _r4 = testTransformer.newRound({
|
|
407
|
+
// name: 'r4_same_paragraph_conflict',
|
|
408
|
+
// description: 'Both edit same paragraph - LCS should merge at word/character level'
|
|
409
|
+
// });
|
|
410
|
+
// // #region r4 source edits
|
|
411
|
+
// if (logalot) { console.log(`${lc} R4: Source editing same paragraph...`); }
|
|
412
|
+
// // TODO: Retrieve from source
|
|
413
|
+
// // TODO: Mutate - edit specific words in paragraph
|
|
414
|
+
// // #endregion r4 source edits
|
|
415
|
+
// // #region r4 dest edits
|
|
416
|
+
// if (logalot) { console.log(`${lc} R4: Dest editing same paragraph (different words)...`); }
|
|
417
|
+
// // TODO: Retrieve from dest
|
|
418
|
+
// // TODO: Mutate - edit different words in same paragraph
|
|
419
|
+
// // #endregion r4 dest edits
|
|
420
|
+
// await respecfully(sir, `r4 verify pre`, async () => {
|
|
421
|
+
// await ifWe(sir, 'dest has alpha after R3 graft', async () => {
|
|
422
|
+
// // TODO: Verify pre-sync state
|
|
423
|
+
// });
|
|
424
|
+
// });
|
|
425
|
+
// if (logalot) { console.log(`${lc} Running r4 Sync (same paragraph conflict)...`); }
|
|
426
|
+
// // TODO: Add sync operation
|
|
427
|
+
// await respecfully(sir, `r4 verify post`, async () => {
|
|
428
|
+
// await ifWe(sir, 'r4 tip addrs match', async () => {
|
|
429
|
+
// // TODO: Verify tips match
|
|
430
|
+
// });
|
|
431
|
+
// await ifWe(sir, 'r4 LCS merged both word changes', async () => {
|
|
432
|
+
// // TODO: Verify text has both source and dest word changes
|
|
433
|
+
// // TODO: Verify LCS algorithm preserved both edits correctly
|
|
434
|
+
// });
|
|
435
|
+
// await ifWe(sir, 'r4 dep graphs synced', async () => {
|
|
436
|
+
// // TODO: Verify dep graphs
|
|
437
|
+
// });
|
|
438
|
+
// });
|
|
300
439
|
// #endregion Round 4: Same paragraph conflict
|
|
301
440
|
// #region Round 5: Multi-field text merge
|
|
302
|
-
const _r5 = testTransformer.newRound({
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
});
|
|
306
|
-
// #region r5 source edits
|
|
307
|
-
if (logalot) {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
// TODO:
|
|
311
|
-
//
|
|
312
|
-
//
|
|
313
|
-
//
|
|
314
|
-
//
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
//
|
|
319
|
-
//
|
|
320
|
-
// TODO:
|
|
321
|
-
//
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
// TODO:
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
// TODO: Ensure one field's merge didn't affect the other
|
|
344
|
-
});
|
|
345
|
-
await ifWeMight(sir, 'r5 dep graphs synced', async () => {
|
|
346
|
-
// TODO: Verify dep graphs
|
|
347
|
-
});
|
|
348
|
-
});
|
|
441
|
+
// const _r5 = testTransformer.newRound({
|
|
442
|
+
// name: 'r5_multi_field_text',
|
|
443
|
+
// description: 'Conflicting text edits in BOTH text and description fields simultaneously'
|
|
444
|
+
// });
|
|
445
|
+
// // #region r5 source edits
|
|
446
|
+
// if (logalot) { console.log(`${lc} R5: Source editing both text and description...`); }
|
|
447
|
+
// // TODO: Retrieve from source
|
|
448
|
+
// // TODO: Mutate text field
|
|
449
|
+
// // TODO: Mutate description field (in same mut8 or separate)
|
|
450
|
+
// // #endregion r5 source edits
|
|
451
|
+
// // #region r5 dest edits
|
|
452
|
+
// if (logalot) { console.log(`${lc} R5: Dest editing both text and description differently...`); }
|
|
453
|
+
// // TODO: Retrieve from dest
|
|
454
|
+
// // TODO: Mutate text field (different changes)
|
|
455
|
+
// // TODO: Mutate description field (different changes)
|
|
456
|
+
// // #endregion r5 dest edits
|
|
457
|
+
// await respecfully(sir, `r5 verify pre`, async () => {
|
|
458
|
+
// await ifWe(sir, 'dest has alpha after R4 graft', async () => {
|
|
459
|
+
// // TODO: Verify pre-sync state
|
|
460
|
+
// });
|
|
461
|
+
// });
|
|
462
|
+
// if (logalot) { console.log(`${lc} Running r5 Sync (multi-field text merge)...`); }
|
|
463
|
+
// // TODO: Add sync operation
|
|
464
|
+
// await respecfully(sir, `r5 verify post`, async () => {
|
|
465
|
+
// await ifWe(sir, 'r5 tip addrs match', async () => {
|
|
466
|
+
// // TODO: Verify tips match
|
|
467
|
+
// });
|
|
468
|
+
// await ifWe(sir, 'r5 text field merged', async () => {
|
|
469
|
+
// // TODO: Verify text field has both source and dest changes
|
|
470
|
+
// });
|
|
471
|
+
// await ifWe(sir, 'r5 description field merged', async () => {
|
|
472
|
+
// // TODO: Verify description field has both source and dest changes
|
|
473
|
+
// });
|
|
474
|
+
// await ifWe(sir, 'r5 both fields independently LCS-merged', async () => {
|
|
475
|
+
// // TODO: Verify each field was merged independently
|
|
476
|
+
// // TODO: Ensure one field's merge didn't affect the other
|
|
477
|
+
// });
|
|
478
|
+
// await ifWe(sir, 'r5 dep graphs synced', async () => {
|
|
479
|
+
// // TODO: Verify dep graphs
|
|
480
|
+
// });
|
|
481
|
+
// });
|
|
349
482
|
// #endregion Round 5: Multi-field text merge
|
|
350
483
|
});
|
|
351
484
|
//# sourceMappingURL=sync-conflict-text-merge.respec.mjs.map
|