@ibgib/core-gib 0.1.40 → 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.
@@ -114,6 +114,8 @@ await respecfully(sir, `Multi-round/timeline permutations`, async () => {
114
114
  in: 'source',
115
115
  name: 'r1_alpha_v0_source', // should be auto-calculated?
116
116
  });
117
+ const alpha_tjpAddr =
118
+ getTjpAddr({ ibGib: r1_alpha_v0_source.ibGib, defaultIfNone: 'incomingAddr' })!;
117
119
 
118
120
  // Create v1 (common) - will be synced to dest
119
121
  const r1_alpha_v1_source_common = await testTransformer.mut8({
@@ -121,13 +123,11 @@ await respecfully(sir, `Multi-round/timeline permutations`, async () => {
121
123
  strField: 'commonField',
122
124
  name: 'r1_alpha_v1_source_common'
123
125
  });
124
- const alpha_tjpAddr =
125
- getTjpAddr({ ibGib: r1_alpha_v0_source.ibGib, defaultIfNone: 'incomingAddr' })!;
126
126
 
127
127
  // #endregion r1 setup
128
128
 
129
129
  await respecfully(sir, `r1 verify pre`, async () => {
130
- await ifWeMight(sir, 'dest should NOT have alpha', async () => {
130
+ await ifWe(sir, 'dest should NOT have alpha', async () => {
131
131
  const resGet = await getFromSpace({
132
132
  space: destSpace,
133
133
  addr: alpha_tjpAddr,
@@ -151,7 +151,7 @@ await respecfully(sir, `Multi-round/timeline permutations`, async () => {
151
151
  if (logalot) { console.log(`${lc} r1_syncSaga Complete.`); }
152
152
 
153
153
  await respecfully(sir, `r1 verify post`, async () => {
154
- await ifWeMight(sir, 'dest should have alpha', async () => {
154
+ await ifWe(sir, 'dest should have alpha', async () => {
155
155
  // alpha's full dep graph should exist on dest
156
156
  const [alpha_dest] = await getIbGibsFromCache_fallbackToSpaces({
157
157
  addrs: [r1_alpha_v0_source.addr],
@@ -170,7 +170,7 @@ await respecfully(sir, `Multi-round/timeline permutations`, async () => {
170
170
  });
171
171
 
172
172
  // Get alpha_v1_common from destSpace for Round 2
173
- const resGetDest = await getFromSpace({ space: destSpace, addr: alpha_tjpAddr });
173
+ const resGetDest = await getFromSpace({ space: destSpace, addr: r1_alpha_v1_source_common.addr });
174
174
  if (!resGetDest.success || !resGetDest.ibGibs || resGetDest.ibGibs.length === 0) {
175
175
  throw new Error(`Failed to retrieve alpha from destSpace after sync. (E: 40c67811eba14f729880a46dcbb65126)`);
176
176
  }
@@ -231,7 +231,7 @@ await respecfully(sir, `Multi-round/timeline permutations`, async () => {
231
231
  // Verify Receiver has correct KV (Pre-Sync Check)
232
232
  // This ensures the conflict precondition exists.
233
233
  await respecfully(sir, `r2 verify pre`, async () => {
234
- await ifWeMight(sir, 'dest has alpha v1 common', async () => {
234
+ await ifWe(sir, 'dest has alpha v1 common', async () => {
235
235
  try {
236
236
  const destKV = await receiverCoordinator.getKnowledgeMap({
237
237
  space: destSpace,
@@ -310,7 +310,7 @@ await respecfully(sir, `Multi-round/timeline permutations`, async () => {
310
310
  if (!alpha_dest_tipAddr) {
311
311
  throw new Error(`dest Space missing timeline tip for ${alpha_tjpAddr} (E: 30b018c6349917aa28c9f538fa567826)`);
312
312
  }
313
- await ifWeMight(sir, 'tip addrs', async () => {
313
+ await ifWe(sir, 'tip addrs', async () => {
314
314
  iReckon(sir, alpha_source_tipAddr).asTo('source/dest have same tip addrs').isGonnaBe(alpha_dest_tipAddr);
315
315
  })
316
316
 
@@ -336,7 +336,7 @@ await respecfully(sir, `Multi-round/timeline permutations`, async () => {
336
336
  // #endregion DEBUG SANITY CHECK
337
337
 
338
338
 
339
- await ifWeMight(sir, 'r2 basics of alpha merge', async () => {
339
+ await ifWe(sir, 'r2 basics of alpha merge', async () => {
340
340
  iReckon(sir, alpha_source_tipAddr)
341
341
  .asTo(`Source Tip (${alpha_source_tipAddr}) should NOT be r2_alpha_v3_source_rel8dBeta`)
342
342
  .not.isGonnaBe(r2_alpha_v3_source_rel8dBeta.addr);
@@ -359,7 +359,7 @@ await respecfully(sir, `Multi-round/timeline permutations`, async () => {
359
359
  iReckon(sir, gotten_alpha_source_tipIbGib.data![r2_dest_mut8Info.key!]).asTo(`New Tip has dest field ${r2_dest_mut8Info.key!}`).isGonnaBe(r2_dest_mut8Info.value!);
360
360
  });
361
361
 
362
- await ifWeMight(sir, 'r2 alpha and deps synced', async () => {
362
+ await ifWe(sir, 'r2 alpha and deps synced', async () => {
363
363
  // alpha's full dep graph should exist on dest, even though its
364
364
  // timeline was grafted
365
365
  const [alpha_dest] = await getIbGibsFromCache_fallbackToSpaces({
@@ -392,7 +392,7 @@ await respecfully(sir, `Multi-round/timeline permutations`, async () => {
392
392
  }
393
393
  });
394
394
 
395
- await ifWeMight(sir, 'r2 beta and deps synced', async () => {
395
+ await ifWe(sir, 'r2 beta and deps synced', async () => {
396
396
  // beta's full dep graph should exist on dest
397
397
  const [beta_dest] = await getIbGibsFromCache_fallbackToSpaces({
398
398
  addrs: [r2_beta_v0_source.addr],
@@ -439,8 +439,37 @@ await respecfully(sir, `Multi-round/timeline permutations`, async () => {
439
439
 
440
440
  if (logalot) { console.log(`${lc} Creating r3 divergent edits on source...`); }
441
441
 
442
- // Source: Mutate alpha fieldC, mutate beta betaFieldA
443
- // TODO: Add source edits here
442
+ // Source: Get latest alpha and beta from source, then mutate both
443
+ // After R2, alpha has graft point on source. We'll mutate from that.
444
+ const resGet_r3_alpha_source = await getFromSpace({ space: sourceSpace, addr: alpha_tjpAddr });
445
+ if (!resGet_r3_alpha_source.success || !resGet_r3_alpha_source.ibGibs || resGet_r3_alpha_source.ibGibs.length === 0) {
446
+ throw new Error(`Failed to retrieve alpha from sourceSpace for R3. (E: 8e3a4f7c9b2d1a5e6f8c3d9e2b4a7c1f)`);
447
+ }
448
+ const r3_alpha_v3_graftPoint = resGet_r3_alpha_source.ibGibs[0];
449
+
450
+ const beta_tjpAddr = getTjpAddr({ ibGib: r2_beta_v0_source.ibGib, defaultIfNone: 'incomingAddr' })!;
451
+ const resGet_r3_beta_source = await getFromSpace({ space: sourceSpace, addr: beta_tjpAddr });
452
+ if (!resGet_r3_beta_source.success || !resGet_r3_beta_source.ibGibs || resGet_r3_beta_source.ibGibs.length === 0) {
453
+ throw new Error(`Failed to retrieve beta from sourceSpace for R3. (E: 3f9e2c8a7d5b1c4e9f6a2d8c5b7e1a3f)`);
454
+ }
455
+ const r3_beta_v0_graftPoint = resGet_r3_beta_source.ibGibs[0];
456
+
457
+ // Mutate alpha fieldC on source
458
+ const r3_alpha_v4_source_mut8fieldC = await testTransformer.mut8({
459
+ ibGib: r3_alpha_v3_graftPoint,
460
+ in: 'source',
461
+ strField: 'fieldC',
462
+ name: 'r3_alpha_v4_source_mut8fieldC',
463
+ comments_snake_plus_CamelCase: 'postGraft',
464
+ });
465
+
466
+ // Mutate beta betaFieldA on source
467
+ const r3_beta_v1_source = await testTransformer.mut8({
468
+ ibGib: r3_beta_v0_graftPoint,
469
+ in: 'source',
470
+ strField: 'betaFieldA',
471
+ name: 'r3_beta_v1_source',
472
+ });
444
473
 
445
474
  // #endregion r3 source edits
446
475
 
@@ -448,46 +477,646 @@ await respecfully(sir, `Multi-round/timeline permutations`, async () => {
448
477
 
449
478
  if (logalot) { console.log(`${lc} Creating r3 divergent edits on dest...`); }
450
479
 
451
- // Dest: Mutate alpha fieldD, mutate beta betaFieldB
452
- // TODO: Add dest edits here
480
+ // Dest: Get latest alpha and beta from dest, then mutate both
481
+ const resGet_r3_alpha_dest = await getFromSpace({ space: destSpace, addr: alpha_tjpAddr });
482
+ if (!resGet_r3_alpha_dest.success || !resGet_r3_alpha_dest.ibGibs || resGet_r3_alpha_dest.ibGibs.length === 0) {
483
+ throw new Error(`Failed to retrieve alpha from destSpace for R3. (E: 2c7e9f1a4b8d3e5c7a9f2d4e6b8c1a5e)`);
484
+ }
485
+ const r3_alpha_v3_graftPoint_fromDest = resGet_r3_alpha_dest.ibGibs[0];
486
+
487
+ const resGet_r3_beta_dest = await getFromSpace({ space: destSpace, addr: beta_tjpAddr });
488
+ if (!resGet_r3_beta_dest.success || !resGet_r3_beta_dest.ibGibs || resGet_r3_beta_dest.ibGibs.length === 0) {
489
+ throw new Error(`Failed to retrieve beta from destSpace for R3. (E: 5d8c2e9a1f4b7e3c6d9a2f5e8b1c4a7e)`);
490
+ }
491
+ const r3_beta_v0_graftPoint_fromDest = resGet_r3_beta_dest.ibGibs[0];
492
+
493
+ // Mutate alpha fieldD on dest
494
+ const r3_alpha_v4_dest_mut8fieldD = await testTransformer.mut8({
495
+ ibGib: r3_alpha_v3_graftPoint_fromDest,
496
+ in: 'dest',
497
+ strField: 'fieldD',
498
+ name: 'r3_alpha_v4_dest_mut8fieldD',
499
+ comments_snake_plus_CamelCase: 'postGraft',
500
+ });
501
+
502
+ // Mutate beta betaFieldB on dest
503
+ const r3_beta_v1_dest = await testTransformer.mut8({
504
+ ibGib: r3_beta_v0_graftPoint_fromDest,
505
+ in: 'dest',
506
+ strField: 'betaFieldB',
507
+ name: 'r3_beta_v1_dest',
508
+ });
509
+
510
+ if (logalot) { console.log(`${lc} R3 Divergence created (both alpha and beta conflicted).`); }
453
511
 
454
512
  // #endregion r3 dest edits
455
513
 
456
514
  await respecfully(sir, `r3 verify pre`, async () => {
457
- // TODO: Verify pre-sync state
458
- await ifWeMight(sir, 'source has divergent alpha and beta', async () => {
459
- // Verify source has its versions
460
- });
515
+ await ifWe(sir, 'dest has both alpha and beta tips (pre-conflict)', async () => {
516
+ try {
517
+ const destKV = await receiverCoordinator.getKnowledgeMap({
518
+ space: destSpace,
519
+ metaspace,
520
+ domainIbGibs: [r3_alpha_v3_graftPoint_fromDest, r3_beta_v0_graftPoint_fromDest]
521
+ });
461
522
 
462
- await ifWeMight(sir, 'dest has divergent alpha and beta', async () => {
463
- // Verify dest has its versions
523
+ // Verify alpha tip exists on dest
524
+ const destAlphaTip = destKV[alpha_tjpAddr];
525
+ iReckon(sir, !!destAlphaTip).asTo(`Dest KV has alpha timeline tip`).isGonnaBeTruthy();
526
+
527
+ // Verify beta tip exists on dest
528
+ const destBetaTip = destKV[beta_tjpAddr];
529
+ iReckon(sir, !!destBetaTip).asTo(`Dest KV has beta timeline tip`).isGonnaBeTruthy();
530
+ } catch (error) {
531
+ console.error(`${lc} ${extractErrorMsg(error)}`);
532
+ iReckon(sir, true).asTo('getKnowledgeMap errored out').isGonnaBeFalse();
533
+ }
464
534
  });
465
535
  });
466
536
 
467
- if (logalot) { console.log(`${lc} Running r3 Sync...`); }
537
+ if (logalot) { console.log(`${lc} Running r3 Sync (both alpha and beta conflict)...`); }
468
538
 
469
- // TODO: Add sync operation here
470
- // const r3_syncSaga = await senderCoordinator.sync({...});
539
+ let r3_syncSaga: SyncSagaInfo | undefined;
540
+ try {
541
+ r3_syncSaga = await senderCoordinator.sync({
542
+ peer: await newTestPeer(),
543
+ localSpace: sourceSpace,
544
+ metaspace,
545
+ domainIbGibs: [r3_alpha_v4_source_mut8fieldC.ibGib, r3_beta_v1_source.ibGib],
546
+ conflictStrategy: SyncConflictStrategy.optimisticWithLCS,
547
+ useSessionIdentity: false,
548
+ });
549
+
550
+ if (logalot) { console.log(`${lc} awaiting r3_syncSaga.done`) }
551
+ await r3_syncSaga.done;
552
+
553
+ if (logalot) { console.log(`${lc} r3_syncSaga Complete.`); }
554
+ } catch (e) {
555
+ console.error(`${lc} R3 Sync Failed with Error:`, e);
556
+ iReckon(sir, false).asTo(`R3 Sync failed with error: ${e}`).isGonnaBeTruthy();
557
+ return; // Exit test early
558
+ }
471
559
 
472
560
  await respecfully(sir, `r3 verify post`, async () => {
473
- // TODO: Verify post-sync state
561
+ try {
562
+ // Get KVs for both timelines after sync
563
+ const alpha_sourceKV_afterR3 = await senderCoordinator.getKnowledgeMap({
564
+ space: sourceSpace,
565
+ metaspace,
566
+ domainIbGibs: [r1_alpha_v0_source.ibGib]
567
+ });
568
+ const r3_alpha_source_tipAddr = alpha_sourceKV_afterR3[alpha_tjpAddr];
474
569
 
475
- await ifWeMight(sir, 'r3 alpha merge has both edits', async () => {
476
- // Verify alpha has fieldC (source) AND fieldD (dest)
477
- });
570
+ const alpha_destKV_afterR3 = await senderCoordinator.getKnowledgeMap({
571
+ space: destSpace,
572
+ metaspace,
573
+ domainIbGibs: [r1_alpha_v0_source.ibGib]
574
+ });
575
+ const r3_alpha_dest_tipAddr = alpha_destKV_afterR3[alpha_tjpAddr];
478
576
 
479
- await ifWeMight(sir, 'r3 beta merge has both edits', async () => {
480
- // Verify beta has betaFieldA (source) AND betaFieldB (dest)
481
- });
577
+ const beta_sourceKV_afterR3 = await senderCoordinator.getKnowledgeMap({
578
+ space: sourceSpace,
579
+ metaspace,
580
+ domainIbGibs: [r2_beta_v0_source.ibGib]
581
+ });
582
+ const r3_beta_source_tipAddr = beta_sourceKV_afterR3[beta_tjpAddr];
583
+
584
+ const beta_destKV_afterR3 = await senderCoordinator.getKnowledgeMap({
585
+ space: destSpace,
586
+ metaspace,
587
+ domainIbGibs: [r2_beta_v0_source.ibGib]
588
+ });
589
+ const r3_beta_dest_tipAddr = beta_destKV_afterR3[beta_tjpAddr];
590
+ if (!r3_beta_dest_tipAddr) {
591
+ ifWe(sir, 'r3_beta_dest_tipAddr is falsy?', async () => {
592
+ iReckon(sir, true).asTo('fail').isGonnaBeFalse();
593
+ });
594
+ return; /* <<<< returns early */
595
+ }
596
+
597
+ await ifWe(sir, 'r3 tip addrs match (both timelines)', async () => {
598
+ iReckon(sir, r3_alpha_source_tipAddr).asTo('alpha source/dest have same tip addrs').isGonnaBe(r3_alpha_dest_tipAddr);
599
+ iReckon(sir, r3_beta_source_tipAddr).asTo('beta source/dest have same tip addrs').isGonnaBe(r3_beta_dest_tipAddr);
600
+ });
601
+
602
+ // Fetch alpha tip ibgib
603
+ if (!r3_alpha_source_tipAddr) {
604
+ throw new Error(`r3_alpha_source_tipAddr is null/undefined (E: 746f32e97387ce2e1401ea6e1c1b4826)`);
605
+ }
606
+ const resGet_r3_alpha_tip = await getFromSpace({ space: sourceSpace, addr: r3_alpha_source_tipAddr });
607
+ const r3_alpha_tipIbGib = resGet_r3_alpha_tip.ibGibs![0] as IbGib_V1<TestData>;
608
+
609
+ // Fetch beta tip ibgib
610
+ if (!r3_beta_source_tipAddr) {
611
+ throw new Error(`r3_beta_source_tipAddr is null/undefined (E: 9212c9e87248017d08a243682462ba26)`);
612
+ }
613
+ const resGet_r3_beta_tip = await getFromSpace({ space: sourceSpace, addr: r3_beta_source_tipAddr });
614
+ const r3_beta_tipIbGib = resGet_r3_beta_tip.ibGibs![0] as IbGib_V1<TestData>;
615
+
616
+ await ifWe(sir, 'r3 alpha merge has all four fields (commonField, fieldA, fieldB, fieldC, fieldD)', async () => {
617
+ // Should have new graft point with different addr than before
618
+ iReckon(sir, r3_alpha_source_tipAddr)
619
+ .asTo(`Alpha R3 tip should NOT be r3_alpha_v4_source_mut8fieldC`)
620
+ .not.isGonnaBe(r3_alpha_v4_source_mut8fieldC.addr);
621
+ iReckon(sir, r3_alpha_source_tipAddr)
622
+ .asTo(`Alpha R3 tip should NOT be r3_alpha_v4_dest_mut8fieldD`)
623
+ .not.isGonnaBe(r3_alpha_v4_dest_mut8fieldD.addr);
624
+
625
+ // Check alpha has ALL fields: commonField (R1), fieldA (R2 source), fieldB (R2 dest), fieldC (R3 source), fieldD (R3 dest)
626
+ const r3_alpha_v4_source_mut8Info = r3_alpha_v4_source_mut8fieldC.infos[0] as TestMut8Info;
627
+ const r3_alpha_v4_dest_mut8Info = r3_alpha_v4_dest_mut8fieldD.infos[0] as TestMut8Info;
628
+
629
+ iReckon(sir, r3_alpha_tipIbGib.data![r3_alpha_v4_source_mut8Info.key!])
630
+ .asTo(`Alpha R3 tip has source field ${r3_alpha_v4_source_mut8Info.key!}`)
631
+ .isGonnaBe(r3_alpha_v4_source_mut8Info.value!);
632
+ iReckon(sir, r3_alpha_tipIbGib.data![r3_alpha_v4_dest_mut8Info.key!])
633
+ .asTo(`Alpha R3 tip has dest field ${r3_alpha_v4_dest_mut8Info.key!}`)
634
+ .isGonnaBe(r3_alpha_v4_dest_mut8Info.value!);
635
+ });
636
+
637
+ await ifWe(sir, 'r3 beta merge has both fields (betaFieldA, betaFieldB)', async () => {
638
+ // Should have new graft point with different addr than before
639
+ iReckon(sir, r3_beta_source_tipAddr)
640
+ .asTo(`Beta R3 tip should NOT be r3_beta_v1_source`)
641
+ .not.isGonnaBe(r3_beta_v1_source.addr);
642
+ iReckon(sir, r3_beta_source_tipAddr)
643
+ .asTo(`Beta R3 tip should NOT be r3_beta_v1_dest`)
644
+ .not.isGonnaBe(r3_beta_v1_dest.addr);
645
+
646
+ // Check beta has BOTH fields: betaFieldA (R3 source), betaFieldB (R3 dest)
647
+ const r3_source_beta_mut8Info = r3_beta_v1_source.infos[0] as TestMut8Info;
648
+ const r3_dest_beta_mut8Info = r3_beta_v1_dest.infos[0] as TestMut8Info;
649
+
650
+ iReckon(sir, r3_beta_tipIbGib.data![r3_source_beta_mut8Info.key!])
651
+ .asTo(`Beta R3 tip has source field ${r3_source_beta_mut8Info.key!}`)
652
+ .isGonnaBe(r3_source_beta_mut8Info.value!);
653
+ iReckon(sir, r3_beta_tipIbGib.data![r3_dest_beta_mut8Info.key!])
654
+ .asTo(`Beta R3 tip has dest field ${r3_dest_beta_mut8Info.key!}`)
655
+ .isGonnaBe(r3_dest_beta_mut8Info.value!);
656
+ });
657
+
658
+ await ifWe(sir, 'r3 alpha and deps synced', async () => {
659
+ const [alpha_dest] = await getIbGibsFromCache_fallbackToSpaces({
660
+ // addrs: [r1_alpha_v0_source.addr],
661
+ addrs: [r3_alpha_source_tipAddr],
662
+ space: destSpace,
663
+ });
664
+ iReckon(sir, alpha_dest).asTo('alpha exists in dest').isGonnaBeTruthy();
665
+ if (alpha_dest) {
666
+ try {
667
+ const depGraph_alpha_source = await getDependencyGraph({
668
+ ibGib: r1_alpha_v0_source.ibGib,
669
+ live: true,
670
+ space: sourceSpace
671
+ });
672
+ const depGraph_alpha_dest = await getDependencyGraph({
673
+ ibGib: alpha_dest,
674
+ live: true,
675
+ space: destSpace
676
+ });
677
+ const alphaDepsAreEqual = graphsAreEquivalent({
678
+ graphA: depGraph_alpha_source,
679
+ graphB: depGraph_alpha_dest,
680
+ slowButThorough: true,
681
+ });
682
+ iReckon(sir, alphaDepsAreEqual).asTo('alpha dep graph equal after R3 graft').isGonnaBeTrue();
683
+ } catch (error) {
684
+ console.error(`${lc} ${extractErrorMsg(error)}`);
685
+ iReckon(sir, true).asTo('ERROR: alpha dep graph check failed').isGonnaBeFalse();
686
+ }
687
+ }
688
+ });
689
+
690
+ await ifWe(sir, 'r3 beta and deps synced', async () => {
691
+ const [beta_dest] = await getIbGibsFromCache_fallbackToSpaces({
692
+ // addrs: [r2_beta_v0_source.addr],
693
+ addrs: [r3_beta_dest_tipAddr],
694
+ space: destSpace,
695
+ });
696
+ iReckon(sir, beta_dest).asTo('beta exists in dest').isGonnaBeTruthy();
697
+ if (beta_dest) {
698
+ try {
699
+ const depGraph_beta_source = await getDependencyGraph({
700
+ ibGib: r2_beta_v0_source.ibGib,
701
+ live: true,
702
+ space: sourceSpace
703
+ });
704
+ const depGraph_beta_dest = await getDependencyGraph({
705
+ ibGib: beta_dest,
706
+ live: true,
707
+ space: destSpace
708
+ });
709
+ const betaDepsAreEqual = graphsAreEquivalent({
710
+ graphA: depGraph_beta_source,
711
+ graphB: depGraph_beta_dest,
712
+ slowButThorough: true,
713
+ });
714
+ iReckon(sir, betaDepsAreEqual).asTo('beta dep graph equal after R3 graft').isGonnaBeTrue();
715
+ } catch (error) {
716
+ console.error(`${lc} ${extractErrorMsg(error)}`);
717
+ iReckon(sir, true).asTo('ERROR: beta dep graph check failed').isGonnaBeFalse();
718
+ }
719
+ }
720
+ });
721
+
722
+ } catch (error) {
723
+ console.error(`${lc} ${extractErrorMsg(error)}`);
724
+ iReckon(sir, true).asTo('R3 verify post errored out').isGonnaBeFalse();
725
+ }
726
+ });
727
+
728
+ // #endregion Round 3: Multiple Timeline Conflicts
729
+
730
+ // #region Round 4: Chain Edits After Graft
731
+
732
+ const _r4 = testTransformer.newRound({
733
+ name: 'r4_chain_edits_after_graft',
734
+ description: 'Post-graft chain edits: mut8 → create gamma → rel8 gamma → mut8 again, tests continued editing on grafted timelines'
735
+ });
736
+
737
+ // #region r4 source edits
738
+
739
+ if (logalot) { console.log(`${lc} Creating r4 chain edits on source (post-graft)...`); }
740
+
741
+ // Source: Build chain on alpha post-graft
742
+ // 1. Retrieve alpha R3 graft point from source
743
+ const resGet_r4_alpha_source = await getFromSpace({ space: sourceSpace, addr: alpha_tjpAddr });
744
+ if (!resGet_r4_alpha_source.success || !resGet_r4_alpha_source.ibGibs || resGet_r4_alpha_source.ibGibs.length === 0) {
745
+ throw new Error(`Failed to retrieve alpha from sourceSpace for R4. (E: 1f2e3d4c5b6a7e8f9d0c1b2a3e4f5d6c)`);
746
+ }
747
+ const r4_alpha_v4_graftPoint = resGet_r4_alpha_source.ibGibs[0];
748
+
749
+ // 2. Mutate alpha v5 (fieldE) from R3 graft point
750
+ const r4_alpha_v5_source = await testTransformer.mut8({
751
+ ibGib: r4_alpha_v4_graftPoint,
752
+ in: 'source',
753
+ strField: 'fieldE',
754
+ name: 'r4_alpha_v5_source',
755
+ comments_snake_plus_CamelCase: 'postGraft2',
756
+ });
757
+
758
+ // 3. Create new gamma timeline
759
+ const r4_gamma_v0_source = await testTransformer.create({
760
+ atom: 'gamma',
761
+ in: 'source',
762
+ data: { gammaField: 'gamma created on source' },
763
+ name: 'r4_gamma_v0_source'
764
+ });
765
+
766
+ // 4. Relate alpha to gamma (creates v6)
767
+ const r4_alpha_v6_source_rel8dGamma = await testTransformer.rel8({
768
+ stepInfo: r4_alpha_v5_source,
769
+ in: 'source',
770
+ targetIbGibs: [r4_gamma_v0_source.ibGib],
771
+ rel8nName: TEST_REL8N_NAME,
772
+ name: 'r4_alpha_v6_source_rel8dGamma'
773
+ });
774
+
775
+ // 5. Mutate alpha again v7 (fieldF)
776
+ const r4_alpha_v7_source = await testTransformer.mut8({
777
+ ibGib: r4_alpha_v6_source_rel8dGamma.ibGib,
778
+ in: 'source',
779
+ strField: 'fieldF',
780
+ name: 'r4_alpha_v7_source',
781
+ comments_snake_plus_CamelCase: 'chainEnd',
782
+ });
783
+
784
+ // 6. Retrieve beta R3 graft point from source
785
+ const resGet_r4_beta_source = await getFromSpace({ space: sourceSpace, addr: beta_tjpAddr });
786
+ if (!resGet_r4_beta_source.success || !resGet_r4_beta_source.ibGibs || resGet_r4_beta_source.ibGibs.length === 0) {
787
+ throw new Error(`Failed to retrieve beta from sourceSpace for R4. (E: 4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b)`);
788
+ }
789
+ const r4_beta_v1_graftPoint = resGet_r4_beta_source.ibGibs[0];
482
790
 
483
- await ifWeMight(sir, 'r3 alpha and deps synced', async () => {
484
- // Verify alpha's full dep graph on both spaces
791
+ // 7. Mutate beta v2 (betaFieldD) on source - creates divergence with dest
792
+ const r4_beta_v2_source = await testTransformer.mut8({
793
+ ibGib: r4_beta_v1_graftPoint,
794
+ in: 'source',
795
+ strField: 'betaFieldD',
796
+ name: 'r4_beta_v2_source',
797
+ });
798
+
799
+ // #endregion r4 source edits
800
+
801
+ // #region r4 dest edits
802
+
803
+ if (logalot) { console.log(`${lc} Creating r4 edits on dest (post-graft)...`); }
804
+
805
+ // Dest: Mutate both alpha and beta from their R3 graft points
806
+ // 1. Retrieve alpha R3 graft point from dest
807
+ const resGet_r4_alpha_dest = await getFromSpace({ space: destSpace, addr: alpha_tjpAddr });
808
+ if (!resGet_r4_alpha_dest.success || !resGet_r4_alpha_dest.ibGibs || resGet_r4_alpha_dest.ibGibs.length === 0) {
809
+ throw new Error(`Failed to retrieve alpha from destSpace for R4. (E: 9e8d7c6b5a4f3e2d1c0b9a8e7f6d5c4b)`);
810
+ }
811
+ const r4_alpha_v4_graftPoint_fromDest = resGet_r4_alpha_dest.ibGibs[0];
812
+
813
+ // 2. Mutate alpha v5 (fieldG) from R3 graft point
814
+ const r4_alpha_v5_dest = await testTransformer.mut8({
815
+ ibGib: r4_alpha_v4_graftPoint_fromDest,
816
+ in: 'dest',
817
+ strField: 'fieldG',
818
+ name: 'r4_alpha_v5_dest',
819
+ comments_snake_plus_CamelCase: 'postGraft2',
820
+ });
821
+
822
+ // 3. Retrieve beta R3 graft point from dest (reuse beta_tjpAddr from R3)
823
+ const resGet_r4_beta_dest = await getFromSpace({ space: destSpace, addr: beta_tjpAddr });
824
+ if (!resGet_r4_beta_dest.success || !resGet_r4_beta_dest.ibGibs || resGet_r4_beta_dest.ibGibs.length === 0) {
825
+ throw new Error(`Failed to retrieve beta from destSpace for R4. (E: 3b2a1f0e9d8c7b6a5e4f3d2c1b0a9e8f)`);
826
+ }
827
+ const r4_beta_v1_graftPoint_fromDest = resGet_r4_beta_dest.ibGibs[0];
828
+
829
+ // 4. Mutate beta v2 (betaFieldC)
830
+ const r4_beta_v2_dest = await testTransformer.mut8({
831
+ ibGib: r4_beta_v1_graftPoint_fromDest,
832
+ in: 'dest',
833
+ strField: 'betaFieldC',
834
+ name: 'r4_beta_v2_dest',
835
+ });
836
+
837
+ if (logalot) { console.log(`${lc} R4 Divergence created (post-graft chain edits).`); }
838
+
839
+ // #endregion r4 dest edits
840
+
841
+ await respecfully(sir, `r4 verify pre`, async () => {
842
+ await ifWe(sir, 'dest has alpha and beta post-R3 tips', async () => {
843
+ try {
844
+ const destKV = await receiverCoordinator.getKnowledgeMap({
845
+ space: destSpace,
846
+ metaspace,
847
+ domainIbGibs: [r4_alpha_v4_graftPoint_fromDest, r4_beta_v1_graftPoint_fromDest]
848
+ });
849
+
850
+ // Verify alpha tip exists on dest (should be R3 graft point)
851
+ const destAlphaTip = destKV[alpha_tjpAddr];
852
+ iReckon(sir, !!destAlphaTip).asTo(`Dest KV has alpha timeline tip`).isGonnaBeTruthy();
853
+
854
+ // Verify beta tip exists on dest (should be R3 graft point)
855
+ const destBetaTip = destKV[beta_tjpAddr];
856
+ iReckon(sir, !!destBetaTip).asTo(`Dest KV has beta timeline tip`).isGonnaBeTruthy();
857
+ } catch (error) {
858
+ console.error(`${lc} ${extractErrorMsg(error)}`);
859
+ iReckon(sir, true).asTo('getKnowledgeMap errored out').isGonnaBeFalse();
860
+ }
485
861
  });
862
+ });
863
+
864
+ if (logalot) { console.log(`${lc} Running r4 Sync (chain edits after graft)...`); }
486
865
 
487
- await ifWeMight(sir, 'r3 beta and deps synced', async () => {
488
- // Verify beta's full dep graph on both spaces
866
+ let r4_syncSaga: SyncSagaInfo | undefined;
867
+ try {
868
+ r4_syncSaga = await senderCoordinator.sync({
869
+ peer: await newTestPeer(),
870
+ localSpace: sourceSpace,
871
+ metaspace,
872
+ domainIbGibs: [r4_alpha_v7_source.ibGib, r4_gamma_v0_source.ibGib, r4_beta_v2_source.ibGib],
873
+ conflictStrategy: SyncConflictStrategy.optimisticWithLCS,
874
+ useSessionIdentity: false,
489
875
  });
876
+
877
+ if (logalot) { console.log(`${lc} awaiting r4_syncSaga.done`) }
878
+ await r4_syncSaga.done;
879
+
880
+ if (logalot) { console.log(`${lc} r4_syncSaga Complete.`); }
881
+ } catch (e) {
882
+ console.error(`${lc} R4 Sync Failed with Error:`, e);
883
+ iReckon(sir, false).asTo(`R4 Sync failed with error: ${e}`).isGonnaBeTruthy();
884
+ return; // Exit test early
885
+ }
886
+
887
+ await respecfully(sir, `r4 verify post`, async () => {
888
+ try {
889
+ // Get KVs for all three timelines after sync
890
+ const gamma_tjpAddr = getTjpAddr({ ibGib: r4_gamma_v0_source.ibGib, defaultIfNone: 'incomingAddr' })!;
891
+
892
+ const r4_alpha_sourceKV = await senderCoordinator.getKnowledgeMap({
893
+ space: sourceSpace,
894
+ metaspace,
895
+ domainIbGibs: [r1_alpha_v0_source.ibGib]
896
+ });
897
+ const r4_alpha_source_tipAddr = r4_alpha_sourceKV[alpha_tjpAddr];
898
+
899
+ const r4_alpha_destKV = await senderCoordinator.getKnowledgeMap({
900
+ space: destSpace,
901
+ metaspace,
902
+ domainIbGibs: [r1_alpha_v0_source.ibGib]
903
+ });
904
+ const r4_alpha_dest_tipAddr = r4_alpha_destKV[alpha_tjpAddr];
905
+
906
+ const r4_beta_sourceKV = await senderCoordinator.getKnowledgeMap({
907
+ space: sourceSpace,
908
+ metaspace,
909
+ domainIbGibs: [r2_beta_v0_source.ibGib]
910
+ });
911
+ const r4_beta_source_tipAddr = r4_beta_sourceKV[beta_tjpAddr];
912
+
913
+ const r4_beta_destKV = await senderCoordinator.getKnowledgeMap({
914
+ space: destSpace,
915
+ metaspace,
916
+ domainIbGibs: [r2_beta_v0_source.ibGib]
917
+ });
918
+ const r4_beta_dest_tipAddr = r4_beta_destKV[beta_tjpAddr];
919
+ if (!r4_beta_dest_tipAddr) {
920
+ ifWe(sir, 'r4_beta_dest_tipAddr is falsy?', async () => {
921
+ iReckon(sir, true).asTo('fail').isGonnaBeFalse();
922
+ });
923
+ return; /* <<<< returns early */
924
+ }
925
+
926
+ const r4_gamma_sourceKV = await senderCoordinator.getKnowledgeMap({
927
+ space: sourceSpace,
928
+ metaspace,
929
+ domainIbGibs: [r4_gamma_v0_source.ibGib]
930
+ });
931
+ const r4_gamma_source_tipAddr = r4_gamma_sourceKV[gamma_tjpAddr];
932
+
933
+ const r4_gamma_destKV = await senderCoordinator.getKnowledgeMap({
934
+ space: destSpace,
935
+ metaspace,
936
+ domainIbGibs: [r4_gamma_v0_source.ibGib]
937
+ });
938
+ const r4_gamma_dest_tipAddr = r4_gamma_destKV[gamma_tjpAddr];
939
+
940
+ await ifWe(sir, 'r4 tip addrs match (alpha, beta, gamma)', async () => {
941
+ iReckon(sir, r4_alpha_source_tipAddr).asTo('alpha source/dest have same tip addrs').isGonnaBe(r4_alpha_dest_tipAddr);
942
+ iReckon(sir, r4_beta_source_tipAddr).asTo('beta source/dest have same tip addrs').isGonnaBe(r4_beta_dest_tipAddr);
943
+ iReckon(sir, r4_gamma_source_tipAddr).asTo('gamma source/dest have same tip addrs').isGonnaBe(r4_gamma_dest_tipAddr);
944
+ });
945
+
946
+ // Fetch tips
947
+ if (!r4_alpha_source_tipAddr) {
948
+ throw new Error(`r4_alpha_source_tipAddr is null/undefined (E: 5e4d3c2b1a0f9e8d7c6b5a4e3f2d1c0b)`);
949
+ }
950
+ const resGet_r4_alpha_tip = await getFromSpace({ space: sourceSpace, addr: r4_alpha_source_tipAddr });
951
+ const r4_alpha_tipIbGib = resGet_r4_alpha_tip.ibGibs![0] as IbGib_V1<TestData>;
952
+
953
+ if (!r4_beta_source_tipAddr) {
954
+ throw new Error(`r4_beta_source_tipAddr is null/undefined (E: 2a1b0c9d8e7f6a5b4c3d2e1f0a9b8c7d)`);
955
+ }
956
+ const resGet_r4_beta_tip = await getFromSpace({ space: sourceSpace, addr: r4_beta_source_tipAddr });
957
+ const r4_beta_tipIbGib = resGet_r4_beta_tip.ibGibs![0] as IbGib_V1<TestData>;
958
+
959
+ if (!r4_gamma_source_tipAddr) {
960
+ throw new Error(`r4_gamma_source_tipAddr is null/undefined (E: 7f6e5d4c3b2a1e0f9d8c7b6a5e4f3d2c)`);
961
+ }
962
+ const resGet_r4_gamma_tip = await getFromSpace({ space: sourceSpace, addr: r4_gamma_source_tipAddr });
963
+ const r4_gamma_tipIbGib = resGet_r4_gamma_tip.ibGibs![0] as IbGib_V1<TestData>;
964
+
965
+ await ifWe(sir, 'r4 alpha has complete chain of edits and gamma relation', async () => {
966
+ // Should have new graft point with different addr than either pre-graft version
967
+ iReckon(sir, r4_alpha_source_tipAddr)
968
+ .asTo(`Alpha R4 tip should NOT be r4_alpha_v7_source`)
969
+ .not.isGonnaBe(r4_alpha_v7_source.addr);
970
+ iReckon(sir, r4_alpha_source_tipAddr)
971
+ .asTo(`Alpha R4 tip should NOT be r4_alpha_v5_dest`)
972
+ .not.isGonnaBe(r4_alpha_v5_dest.addr);
973
+
974
+ // Check alpha has ALL fields from R1-R4
975
+ // R1: commonField
976
+ // R2 source: fieldA, R2 dest: fieldB
977
+ // R3 source: fieldC (in graft), R3 dest: fieldD (in graft)
978
+ // R4 source: fieldE, fieldF (in chain), R4 dest: fieldG (in graft)
979
+ const r4_source_alpha_v5_mut8Info = r4_alpha_v5_source.infos[0] as TestMut8Info;
980
+ const r4_source_alpha_v7_mut8Info = r4_alpha_v7_source.infos[0] as TestMut8Info;
981
+ const r4_dest_alpha_mut8Info = r4_alpha_v5_dest.infos[0] as TestMut8Info;
982
+
983
+ iReckon(sir, r4_alpha_tipIbGib.data![r4_source_alpha_v5_mut8Info.key!])
984
+ .asTo(`Alpha R4 tip has source fieldE`)
985
+ .isGonnaBe(r4_source_alpha_v5_mut8Info.value!);
986
+ iReckon(sir, r4_alpha_tipIbGib.data![r4_source_alpha_v7_mut8Info.key!])
987
+ .asTo(`Alpha R4 tip has source fieldF`)
988
+ .isGonnaBe(r4_source_alpha_v7_mut8Info.value!);
989
+ iReckon(sir, r4_alpha_tipIbGib.data![r4_dest_alpha_mut8Info.key!])
990
+ .asTo(`Alpha R4 tip has dest fieldG`)
991
+ .isGonnaBe(r4_dest_alpha_mut8Info.value!);
992
+
993
+ // Verify alpha has gamma in relations
994
+ const gammaAddr = getIbGibAddr({ ibGib: r4_gamma_v0_source.ibGib });
995
+ const alphaRel8ns = r4_alpha_tipIbGib.rel8ns?.[TEST_REL8N_NAME] || [];
996
+ iReckon(sir, alphaRel8ns.includes(gammaAddr))
997
+ .asTo('Alpha has gamma in testrel8n')
998
+ .isGonnaBeTrue();
999
+ });
1000
+
1001
+ await ifWe(sir, 'r4 beta has all edits', async () => {
1002
+ // Beta should have new graft from R4
1003
+ iReckon(sir, r4_beta_source_tipAddr)
1004
+ .asTo(`Beta R4 tip should NOT be r4_beta_v2_source (source version pre-graft)`)
1005
+ .not.isGonnaBe(r4_beta_v2_source.addr);
1006
+ iReckon(sir, r4_beta_source_tipAddr)
1007
+ .asTo(`Beta R4 tip should NOT be r4_beta_v2_dest (dest version pre-graft)`)
1008
+ .not.isGonnaBe(r4_beta_v2_dest.addr);
1009
+
1010
+ // Check beta has ALL fields: betaFieldA (R3 source), betaFieldB (R3 dest), betaFieldC (R4 dest), betaFieldD (R4 source)
1011
+ const r4_source_beta_mut8Info = r4_beta_v2_source.infos[0] as TestMut8Info;
1012
+ const r4_dest_beta_mut8Info = r4_beta_v2_dest.infos[0] as TestMut8Info;
1013
+
1014
+ iReckon(sir, r4_beta_tipIbGib.data![r4_source_beta_mut8Info.key!])
1015
+ .asTo(`Beta R4 tip has source betaFieldD`)
1016
+ .isGonnaBe(r4_source_beta_mut8Info.value!);
1017
+ iReckon(sir, r4_beta_tipIbGib.data![r4_dest_beta_mut8Info.key!])
1018
+ .asTo(`Beta R4 tip has dest betaFieldC`)
1019
+ .isGonnaBe(r4_dest_beta_mut8Info.value!);
1020
+ });
1021
+
1022
+ await ifWe(sir, 'r4 gamma synced with deps', async () => {
1023
+ const [gamma_dest] = await getIbGibsFromCache_fallbackToSpaces({
1024
+ addrs: [r4_gamma_v0_source.addr],
1025
+ space: destSpace,
1026
+ });
1027
+ iReckon(sir, gamma_dest).asTo('gamma exists in dest').isGonnaBeTruthy();
1028
+ if (gamma_dest) {
1029
+ try {
1030
+ const depGraph_gamma_source = await getDependencyGraph({
1031
+ ibGib: r4_gamma_v0_source.ibGib,
1032
+ live: true,
1033
+ space: sourceSpace
1034
+ });
1035
+ const depGraph_gamma_dest = await getDependencyGraph({
1036
+ ibGib: gamma_dest,
1037
+ live: true,
1038
+ space: destSpace
1039
+ });
1040
+ const gammaDepsAreEqual = graphsAreEquivalent({
1041
+ graphA: depGraph_gamma_source,
1042
+ graphB: depGraph_gamma_dest,
1043
+ slowButThorough: true,
1044
+ });
1045
+ iReckon(sir, gammaDepsAreEqual).asTo('gamma dep graph equal').isGonnaBeTrue();
1046
+ } catch (error) {
1047
+ console.error(`${lc} ${extractErrorMsg(error)}`);
1048
+ iReckon(sir, true).asTo('ERROR: gamma dep graph check failed').isGonnaBeFalse();
1049
+ }
1050
+ }
1051
+ });
1052
+
1053
+ await ifWe(sir, 'r4 all timelines dep graphs synced', async () => {
1054
+ // Verify alpha dep graphs
1055
+ const [alpha_dest] = await getIbGibsFromCache_fallbackToSpaces({
1056
+ addrs: [r4_alpha_source_tipAddr],
1057
+ space: destSpace,
1058
+ });
1059
+ iReckon(sir, alpha_dest).asTo('alpha exists in dest').isGonnaBeTruthy();
1060
+ if (alpha_dest) {
1061
+ try {
1062
+ const depGraph_alpha_source = await getDependencyGraph({
1063
+ ibGib: r1_alpha_v0_source.ibGib,
1064
+ live: true,
1065
+ space: sourceSpace
1066
+ });
1067
+ const depGraph_alpha_dest = await getDependencyGraph({
1068
+ ibGib: alpha_dest,
1069
+ live: true,
1070
+ space: destSpace
1071
+ });
1072
+ const alphaDepsAreEqual = graphsAreEquivalent({
1073
+ graphA: depGraph_alpha_source,
1074
+ graphB: depGraph_alpha_dest,
1075
+ slowButThorough: true,
1076
+ });
1077
+ iReckon(sir, alphaDepsAreEqual).asTo('alpha dep graph equal after R4').isGonnaBeTrue();
1078
+ } catch (error) {
1079
+ console.error(`${lc} ${extractErrorMsg(error)}`);
1080
+ iReckon(sir, true).asTo('ERROR: alpha dep graph check failed').isGonnaBeFalse();
1081
+ }
1082
+ }
1083
+
1084
+ // Verify beta dep graphs
1085
+ const [beta_dest] = await getIbGibsFromCache_fallbackToSpaces({
1086
+ addrs: [r4_beta_dest_tipAddr],
1087
+ space: destSpace,
1088
+ });
1089
+ iReckon(sir, beta_dest).asTo('beta exists in dest').isGonnaBeTruthy();
1090
+ if (beta_dest) {
1091
+ try {
1092
+ const depGraph_beta_source = await getDependencyGraph({
1093
+ ibGib: r2_beta_v0_source.ibGib,
1094
+ live: true,
1095
+ space: sourceSpace
1096
+ });
1097
+ const depGraph_beta_dest = await getDependencyGraph({
1098
+ ibGib: beta_dest,
1099
+ live: true,
1100
+ space: destSpace
1101
+ });
1102
+ const betaDepsAreEqual = graphsAreEquivalent({
1103
+ graphA: depGraph_beta_source,
1104
+ graphB: depGraph_beta_dest,
1105
+ slowButThorough: true,
1106
+ });
1107
+ iReckon(sir, betaDepsAreEqual).asTo('beta dep graph equal after R4').isGonnaBeTrue();
1108
+ } catch (error) {
1109
+ console.error(`${lc} ${extractErrorMsg(error)}`);
1110
+ iReckon(sir, true).asTo('ERROR: beta dep graph check failed').isGonnaBeFalse();
1111
+ }
1112
+ }
1113
+ });
1114
+
1115
+ } catch (error) {
1116
+ console.error(`${lc} ${extractErrorMsg(error)}`);
1117
+ iReckon(sir, true).asTo('R4 verify post errored out').isGonnaBeFalse();
1118
+ }
490
1119
  });
491
1120
 
492
- // #endregion Round 3: Multiple Timeline Conflicts
1121
+ // #endregion Round 4: Chain Edits After Graft
493
1122
  });