@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.
Files changed (28) hide show
  1. package/dist/sync/sync-conflict-adv-multitimelines.respec.mjs +2 -2
  2. package/dist/sync/sync-conflict-adv-multitimelines.respec.mjs.map +1 -1
  3. package/dist/sync/sync-conflict-text-merge.respec.d.mts +4 -1
  4. package/dist/sync/sync-conflict-text-merge.respec.d.mts.map +1 -1
  5. package/dist/sync/sync-conflict-text-merge.respec.mjs +314 -181
  6. package/dist/sync/sync-conflict-text-merge.respec.mjs.map +1 -1
  7. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.d.mts +7 -0
  8. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.d.mts.map +1 -0
  9. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.mjs +252 -0
  10. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.mjs.map +1 -0
  11. package/dist/sync/sync-saga-coordinator.mjs +3 -3
  12. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  13. package/dist/test/mock-space.d.mts +1 -38
  14. package/dist/test/mock-space.d.mts.map +1 -1
  15. package/dist/test/mock-space.mjs +73 -78
  16. package/dist/test/mock-space.mjs.map +1 -1
  17. package/package.json +1 -1
  18. package/src/keystone/README.md +118 -0
  19. package/src/keystone/docs/architecture.md +30 -1
  20. package/src/sync/README.md +122 -5
  21. package/src/sync/docs/architecture.md +2 -2
  22. package/src/sync/{SYNC_TESTING.md → docs/testing.md} +113 -28
  23. package/src/sync/sync-conflict-adv-multitimelines.respec.mts +3 -3
  24. package/src/sync/sync-conflict-text-merge.respec.mts +326 -164
  25. package/src/sync/sync-innerspace-dest-ahead-withid.respec.mts +316 -0
  26. package/src/sync/sync-saga-coordinator.mts +4 -4
  27. package/src/test/mock-space.mts +72 -72
  28. 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
- * Tests same-field content conflicts with various text patterns.
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, iReckon, ifWeMight } from '@ibgib/helper-gib/dist/respec-gib/respec-gib.mjs';
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 content with text...`);
79
+ console.log(`${lc} R1: Creating initial alpha with text...`);
77
80
  }
78
- // Create content with initial text on source
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 r1_content_v0_source = await testTransformer.create({
81
- atom: 'content',
83
+ const r1_alpha_v0_source = await testTransformer.create({
84
+ atom: 'alpha',
82
85
  in: 'source',
83
86
  data: { text: INITIAL_TEXT },
84
- name: 'r1_content_v0_source'
87
+ name: 'r1_alpha_v0_source'
85
88
  });
86
- const content_tjpAddr = getTjpAddr({ ibGib: r1_content_v0_source.ibGib, defaultIfNone: 'incomingAddr' });
89
+ const alpha_tjpAddr = getTjpAddr({ ibGib: r1_alpha_v0_source.ibGib, defaultIfNone: 'incomingAddr' });
87
90
  if (logalot) {
88
- console.log(`${lc} R1: Syncing initial content to dest...`);
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: [r1_content_v0_source.ibGib],
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 r1_sourceKV = await senderCoordinator.getKnowledgeMap({
116
+ const r1_alpha_sourceKV = await senderCoordinator.getKnowledgeMap({
114
117
  space: sourceSpace,
115
118
  metaspace,
116
- domainIbGibs: [r1_content_v0_source.ibGib]
119
+ domainIbGibs: [r1_alpha_v0_source.ibGib]
117
120
  });
118
- const r1_source_tipAddr = r1_sourceKV[content_tjpAddr];
119
- const r1_destKV = await senderCoordinator.getKnowledgeMap({
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: [r1_content_v0_source.ibGib]
131
+ domainIbGibs: [r1_alpha_v0_source.ibGib]
123
132
  });
124
- const r1_dest_tipAddr = r1_destKV[content_tjpAddr];
125
- await ifWeMight(sir, 'r1 tip addrs match', async () => {
126
- iReckon(sir, r1_source_tipAddr).asTo('R1 source/dest have same tip').isGonnaBe(r1_dest_tipAddr);
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 ifWeMight(sir, 'r1 text synced correctly', async () => {
129
- if (!r1_dest_tipAddr) {
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: r1_dest_tipAddr });
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 ifWeMight(sir, 'r1 dep graphs synced', async () => {
137
- const [content_dest] = await getIbGibsFromCache_fallbackToSpaces({
138
- addrs: [r1_content_v0_source.addr],
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, content_dest).asTo('content exists in dest').isGonnaBeTruthy();
142
- if (content_dest) {
143
- const depGraph_source = await getDependencyGraph({
144
- ibGib: r1_content_v0_source.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 depGraph_dest = await getDependencyGraph({
149
- ibGib: content_dest,
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: depGraph_source,
155
- graphB: depGraph_dest,
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
- // TODO: Retrieve content from source
178
- // TODO: Mutate with text = originalText + "\nSource appended sentence."
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
- // TODO: Retrieve content from dest
185
- // TODO: Mutate with text = "Dest prepended sentence.\n" + originalText
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 ifWeMight(sir, 'dest has content at common version', async () => {
189
- // TODO: Verify dest KV has timeline tip
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 append conflict)...`);
233
+ console.log(`${lc} Running r2 Sync (simple data.text conflict)...`);
194
234
  }
195
- // TODO: Add sync operation here
196
- // let r2_syncSaga: SyncSagaInfo | undefined;
197
- // try {
198
- // r2_syncSaga = await senderCoordinator.sync({...});
199
- // await r2_syncSaga.done;
200
- // } catch (e) {
201
- // console.error(`${lc} R2 Sync Failed:`, e);
202
- // iReckon(sir, false).asTo(`R2 Sync failed: ${e}`).isGonnaBeTruthy();
203
- // return;
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
- // TODO: Retrieve from source
228
- // TODO: Mutate - modify first paragraph only
229
- // #endregion r3 source edits
230
- // #region r3 dest edits
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
- // TODO: Retrieve from dest
235
- // TODO: Mutate - modify second paragraph only
236
- // #endregion r3 dest edits
237
- await respecfully(sir, `r3 verify pre`, async () => {
238
- await ifWeMight(sir, 'dest has content after R2 graft', async () => {
239
- // TODO: Verify pre-sync state
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
- if (logalot) {
243
- console.log(`${lc} Running r3 Sync (interleaved paragraphs)...`);
244
- }
245
- // TODO: Add sync operation
246
- await respecfully(sir, `r3 verify post`, async () => {
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 ifWeMight(sir, 'r3 both paragraph edits merged', async () => {
251
- // TODO: Verify text has both paragraph changes
252
- // TODO: Check paragraph 1 has source changes
253
- // TODO: Check paragraph 2 has dest changes
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 ifWeMight(sir, 'r3 dep graphs synced', async () => {
256
- // TODO: Verify dep graphs
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
- name: 'r4_same_paragraph_conflict',
263
- description: 'Both edit same paragraph - LCS should merge at word/character level'
264
- });
265
- // #region r4 source edits
266
- if (logalot) {
267
- console.log(`${lc} R4: Source editing same paragraph...`);
268
- }
269
- // TODO: Retrieve from source
270
- // TODO: Mutate - edit specific words in paragraph
271
- // #endregion r4 source edits
272
- // #region r4 dest edits
273
- if (logalot) {
274
- console.log(`${lc} R4: Dest editing same paragraph (different words)...`);
275
- }
276
- // TODO: Retrieve from dest
277
- // TODO: Mutate - edit different words in same paragraph
278
- // #endregion r4 dest edits
279
- await respecfully(sir, `r4 verify pre`, async () => {
280
- await ifWeMight(sir, 'dest has content after R3 graft', async () => {
281
- // TODO: Verify pre-sync state
282
- });
283
- });
284
- if (logalot) {
285
- console.log(`${lc} Running r4 Sync (same paragraph conflict)...`);
286
- }
287
- // TODO: Add sync operation
288
- await respecfully(sir, `r4 verify post`, async () => {
289
- await ifWeMight(sir, 'r4 tip addrs match', async () => {
290
- // TODO: Verify tips match
291
- });
292
- await ifWeMight(sir, 'r4 LCS merged both word changes', async () => {
293
- // TODO: Verify text has both source and dest word changes
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
- name: 'r5_multi_field_text',
304
- description: 'Conflicting text edits in BOTH text and description fields simultaneously'
305
- });
306
- // #region r5 source edits
307
- if (logalot) {
308
- console.log(`${lc} R5: Source editing both text and description...`);
309
- }
310
- // TODO: Retrieve from source
311
- // TODO: Mutate text field
312
- // TODO: Mutate description field (in same mut8 or separate)
313
- // #endregion r5 source edits
314
- // #region r5 dest edits
315
- if (logalot) {
316
- console.log(`${lc} R5: Dest editing both text and description differently...`);
317
- }
318
- // TODO: Retrieve from dest
319
- // TODO: Mutate text field (different changes)
320
- // TODO: Mutate description field (different changes)
321
- // #endregion r5 dest edits
322
- await respecfully(sir, `r5 verify pre`, async () => {
323
- await ifWeMight(sir, 'dest has content after R4 graft', async () => {
324
- // TODO: Verify pre-sync state
325
- });
326
- });
327
- if (logalot) {
328
- console.log(`${lc} Running r5 Sync (multi-field text merge)...`);
329
- }
330
- // TODO: Add sync operation
331
- await respecfully(sir, `r5 verify post`, async () => {
332
- await ifWeMight(sir, 'r5 tip addrs match', async () => {
333
- // TODO: Verify tips match
334
- });
335
- await ifWeMight(sir, 'r5 text field merged', async () => {
336
- // TODO: Verify text field has both source and dest changes
337
- });
338
- await ifWeMight(sir, 'r5 description field merged', async () => {
339
- // TODO: Verify description field has both source and dest changes
340
- });
341
- await ifWeMight(sir, 'r5 both fields independently LCS-merged', async () => {
342
- // TODO: Verify each field was merged independently
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