@ibgib/core-gib 0.1.28 → 0.1.30

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 (76) hide show
  1. package/.vscode/launch.json +17 -1
  2. package/dist/common/meta-stone/meta-stone-helper.d.mts.map +1 -1
  3. package/dist/common/meta-stone/meta-stone-helper.mjs +30 -12
  4. package/dist/common/meta-stone/meta-stone-helper.mjs.map +1 -1
  5. package/dist/common/meta-stone/meta-stone-types.d.mts +5 -2
  6. package/dist/common/meta-stone/meta-stone-types.d.mts.map +1 -1
  7. package/dist/sync/strategies/conflict-optimistic.d.mts +16 -0
  8. package/dist/sync/strategies/conflict-optimistic.d.mts.map +1 -1
  9. package/dist/sync/strategies/conflict-optimistic.mjs +28 -1
  10. package/dist/sync/strategies/conflict-optimistic.mjs.map +1 -1
  11. package/dist/sync/sync-conflict.respec.mjs +5 -5
  12. package/dist/sync/sync-conflict.respec.mjs.map +1 -1
  13. package/dist/sync/sync-helpers.d.mts +4 -4
  14. package/dist/sync/sync-helpers.d.mts.map +1 -1
  15. package/dist/sync/sync-helpers.mjs +12 -8
  16. package/dist/sync/sync-helpers.mjs.map +1 -1
  17. package/dist/sync/sync-innerspace-constants.respec.mjs +36 -36
  18. package/dist/sync/sync-innerspace-constants.respec.mjs.map +1 -1
  19. package/dist/sync/sync-innerspace-deep-updates.respec.mjs +3 -1
  20. package/dist/sync/sync-innerspace-deep-updates.respec.mjs.map +1 -1
  21. package/dist/sync/sync-innerspace-dest-ahead.respec.mjs +62 -9
  22. package/dist/sync/sync-innerspace-dest-ahead.respec.mjs.map +1 -1
  23. package/dist/sync/sync-innerspace.respec.mjs +45 -16
  24. package/dist/sync/sync-innerspace.respec.mjs.map +1 -1
  25. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts +0 -9
  26. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts.map +1 -1
  27. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs +25 -43
  28. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs.map +1 -1
  29. package/dist/sync/sync-peer/sync-peer-v1.mjs +2 -2
  30. package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
  31. package/dist/sync/sync-saga-coordinator.d.mts +15 -10
  32. package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
  33. package/dist/sync/sync-saga-coordinator.mjs +304 -163
  34. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  35. package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts +3 -3
  36. package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts.map +1 -1
  37. package/dist/sync/sync-types.d.mts +12 -18
  38. package/dist/sync/sync-types.d.mts.map +1 -1
  39. package/dist/sync/sync-types.mjs +15 -21
  40. package/dist/sync/sync-types.mjs.map +1 -1
  41. package/dist/timeline/timeline-api.d.mts +12 -0
  42. package/dist/timeline/timeline-api.d.mts.map +1 -1
  43. package/dist/timeline/timeline-api.mjs +26 -0
  44. package/dist/timeline/timeline-api.mjs.map +1 -1
  45. package/dist/witness/space/inner-space/inner-space-v1.d.mts +19 -0
  46. package/dist/witness/space/inner-space/inner-space-v1.d.mts.map +1 -1
  47. package/dist/witness/space/inner-space/inner-space-v1.mjs +189 -30
  48. package/dist/witness/space/inner-space/inner-space-v1.mjs.map +1 -1
  49. package/dist/witness/space/inner-space/inner-space-v1.respec.mjs +9 -0
  50. package/dist/witness/space/inner-space/inner-space-v1.respec.mjs.map +1 -1
  51. package/dist/witness/space/space-helper.d.mts.map +1 -1
  52. package/dist/witness/space/space-helper.mjs +2 -1
  53. package/dist/witness/space/space-helper.mjs.map +1 -1
  54. package/package.json +2 -1
  55. package/src/common/meta-stone/meta-stone-helper.mts +25 -11
  56. package/src/common/meta-stone/meta-stone-types.mts +5 -2
  57. package/src/sync/README.md +4 -4
  58. package/src/sync/docs/architecture.md +6 -6
  59. package/src/sync/strategies/conflict-optimistic.mts +41 -4
  60. package/src/sync/sync-conflict.respec.mts +5 -5
  61. package/src/sync/sync-helpers.mts +13 -9
  62. package/src/sync/sync-innerspace-constants.respec.mts +39 -39
  63. package/src/sync/sync-innerspace-deep-updates.respec.mts +5 -5
  64. package/src/sync/sync-innerspace-dest-ahead.respec.mts +73 -9
  65. package/src/sync/sync-innerspace.respec.mts +17 -16
  66. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mts +23 -60
  67. package/src/sync/sync-peer/sync-peer-v1.mts +2 -2
  68. package/src/sync/sync-saga-coordinator.mts +231 -173
  69. package/src/sync/sync-saga-message/sync-saga-message-types.mts +3 -3
  70. package/src/sync/sync-types.mts +19 -26
  71. package/src/timeline/timeline-api.mts +51 -11
  72. package/src/witness/space/inner-space/inner-space-v1.mts +191 -29
  73. package/src/witness/space/inner-space/inner-space-v1.respec.mts +13 -0
  74. package/src/witness/space/space-helper.mts +3 -2
  75. package/test_output.log +0 -0
  76. package/tmp.md +170 -62
@@ -2,12 +2,13 @@ import { extractErrorMsg, getUUID, // so our timestamp in ticks as a string are
2
2
  pretty, delay, } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
3
3
  import { getIbGibAddr } from "@ibgib/ts-gib/dist/helper.mjs";
4
4
  import { Factory_V1 } from "@ibgib/ts-gib/dist/V1/factory.mjs";
5
+ import { GLOBAL_LOG_A_LOT } from "../core-constants.mjs";
5
6
  import { putInSpace, getLatestAddrs, getFromSpace } from "../witness/space/space-helper.mjs";
6
7
  import { SyncStage, SYNC_ATOM, SYNC_MSG_REL8N_NAME, SYNC_SAGA_PAYLOAD_ADDRS_DOMAIN, } from "./sync-constants.mjs";
7
- import { appendToTimeline, createTimeline } from "../timeline/timeline-api.mjs";
8
+ import { appendToTimeline, createTimeline, getHistoryAddrs } from "../timeline/timeline-api.mjs";
8
9
  import { SyncConflictStrategy, SyncMode, SYNC_CONFLICT_STRATEGY_VALID_VALUES, } from "./sync-types.mjs";
9
- import { getFullSyncSagaHistory, getSyncIb, getTempSpaceName, isPastFrame, putInSpace_dnasThenNonDnas, validateFullSyncSagaHistory } from "./sync-helpers.mjs";
10
- import { getDeltaDependencyGraph, getDependencyGraph, toFlatGraph } from "../common/other/graph-helper.mjs";
10
+ import { getSyncSagaFrameOrigin, getFullSyncSagaHistory, getSyncIb, getTempSpaceName, isPastFrame, putInSpace_dnasThenNonDnas, validateFullSyncSagaHistory } from "./sync-helpers.mjs";
11
+ import { getDeltaDependencyGraph, getDependencyGraph } from "../common/other/graph-helper.mjs";
11
12
  import { getSyncSagaMessageIb } from "./sync-saga-message/sync-saga-message-helpers.mjs";
12
13
  import { SYNC_SAGA_MSG_ATOM } from "./sync-saga-message/sync-saga-message-constants.mjs";
13
14
  import { splitPerTjpAndOrDna, getTimelinesGroupedByTjp, isIbGib } from "../common/other/ibgib-helper.mjs";
@@ -16,9 +17,8 @@ import { newupSubject, } from "../common/pubsub/subject/subject-helper.mjs";
16
17
  import { mergeDivergentTimelines } from "./strategies/conflict-optimistic.mjs";
17
18
  import { getSyncSagaMessageFromFrame } from "./sync-saga-message/sync-saga-message-helpers.mjs";
18
19
  import { fnObs } from "../common/pubsub/observer/observer-helper.mjs";
19
- // const logalot = GLOBAL_LOG_A_LOT || true;
20
- const logalot = true;
21
- const logalotControlDomain = true;
20
+ const logalot = GLOBAL_LOG_A_LOT;
21
+ const logalotControlDomain = false;
22
22
  const lcControlDomain = '[ControlDomain]';
23
23
  /**
24
24
  * Orchestrates the synchronization process between two spaces (Source and Destination).
@@ -407,8 +407,13 @@ export class SyncSagaCoordinator {
407
407
  metaspace,
408
408
  });
409
409
  if (!contextResult) {
410
+ // should this ever hit?
411
+ console.error(`${lc} NAG ERROR (DOES NOT THROW): does this ever hit now? (E: e04d02efc2a8e72a88b79f1f0f95ca26)`);
412
+ break;
413
+ }
414
+ else if (contextResult.nextFrameInfo?.sagaComplete) {
410
415
  if (logalot) {
411
- console.log(`${lc} Handler returned null (Saga End). (I: faae22abc818ba9b28ac6d2881cd7826)`);
416
+ console.log(`${lc} Handler returned null (Saga End). (I: 123bf9e7dca8886de72553a8d4f29e26)`);
412
417
  }
413
418
  break;
414
419
  }
@@ -419,9 +424,6 @@ export class SyncSagaCoordinator {
419
424
  else if (!contextResult.nextFrameInfo) {
420
425
  throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo falsy? (E: c287a82e823e662a77923278e2418826)`);
421
426
  }
422
- else if (contextResult.nextFrameInfo?.sagaComplete) {
423
- throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo.sagaComplete? logic flow should not have gotten here. (E: 104a32381db816b7183435e805b3d626)`);
424
- }
425
427
  // #endregion error conditions throw
426
428
  // we have another frame to process and send out, with possibly
427
429
  // payload domain ibgibs as well
@@ -439,11 +441,11 @@ export class SyncSagaCoordinator {
439
441
  }
440
442
  }
441
443
  /**
442
- * Helper to get Knowledge Vector for specific domain ibGibs or TJPs.
444
+ * Helper to get Knowledge Map for specific domain ibGibs or TJPs.
443
445
  * Useful for testing and external validation.
444
446
  */
445
- async getKnowledgeVector({ space, metaspace, domainIbGibs, tjpAddrs, }) {
446
- const lc = `${this.lc}[${this.getKnowledgeVector.name}]`;
447
+ async getKnowledgeMap({ space, metaspace, domainIbGibs, tjpAddrs, }) {
448
+ const lc = `${this.lc}[${this.getKnowledgeMap.name}]`;
447
449
  try {
448
450
  if (logalot) {
449
451
  console.log(`${lc} starting... (I: e184f8a7818666febfbbd2d841ed3826)`);
@@ -484,7 +486,7 @@ export class SyncSagaCoordinator {
484
486
  else {
485
487
  // No info provided. Return empty? Or throw?
486
488
  // User test context implied "everything", but implementation requires scope.
487
- console.warn(`${lc} No domainIbGibs or tjpAddrs provided. Returning empty KV.`);
489
+ console.warn(`${lc} No domainIbGibs or tjpAddrs provided. Returning empty Knowledge.`);
488
490
  return {};
489
491
  }
490
492
  if (tjps.length === 0) {
@@ -538,7 +540,7 @@ export class SyncSagaCoordinator {
538
540
  * @remarks
539
541
  * **Execution Context**: **Sender (Local)**.
540
542
  *
541
- * Generates the first frame containing the Knowledge Vector of the Local Space.
543
+ * Generates the first frame containing the Knowledge Map of the Local Space.
542
544
  * This is sent to the Receiver to begin Gap Analysis.
543
545
  */
544
546
  async createInitFrame({ sagaId, sessionIdentity, domainIbGibs, conflictStrategy, metaspace, localSpace, tempSpace, }) {
@@ -553,17 +555,17 @@ export class SyncSagaCoordinator {
553
555
  const { timelinesMap: srcTimelinesMap, fullGraph, stones: srcStones, } = analysis;
554
556
  // we need to store the fullGraph in our tempSpace for later...
555
557
  await putInSpace({ ibGibs: Object.values(fullGraph), space: tempSpace });
556
- // populate our knowledge vector with tjp -> latest addr/tip in timeline
557
- const knowledgeVector = {};
558
+ // populate our knowledge map with tjp -> latest addr/tip in timeline
559
+ const knowledgeMap = {};
558
560
  Object.keys(srcTimelinesMap).forEach(tjp => {
559
561
  const timeline = srcTimelinesMap[tjp];
560
562
  const tip = timeline.at(-1);
561
- knowledgeVector[tjp] = getIbGibAddr({ ibGib: tip });
563
+ knowledgeMap[tjp] = getIbGibAddr({ ibGib: tip });
562
564
  });
563
565
  const initData = {
564
566
  sagaId,
565
567
  stage: SyncStage.init,
566
- knowledgeVector,
568
+ knowledgeMap: knowledgeMap,
567
569
  identity: sessionIdentity, // KeystoneIbGib is already public data
568
570
  mode: SyncMode.sync,
569
571
  stones: srcStones.map(s => getIbGibAddr({ ibGib: s })),
@@ -670,16 +672,21 @@ export class SyncSagaCoordinator {
670
672
  *
671
673
  * ## 1. Sender
672
674
  *
673
- * On the sender, this is called within the {@link executeSagaLoop} which
674
- * initiates and drives the sync.
675
+ * On the sender, this is called repeatedly within the the sync saga
676
+ * coordinator's {@link executeSagaLoop} which initiates and drives the
677
+ * overall sync process. This loop continues until there are no more frames
678
+ * to be exchanged between endpoints.
675
679
  *
676
680
  * ## 2. Receiver
677
681
  *
678
- * On the receiver, this is called directly by the receiving endpoint. That
679
- * endpoint's job is basically to get these things collocated and prepared
680
- * to make this call.
682
+ * On the receiver, this is called directly from {@link continueSync}, which
683
+ * itself is called either directly by the concrete sync peer or from within
684
+ * the receiving node endpoint. That endpoint's job is basically to get
685
+ * these things collocated and prepared to make this call.
681
686
  *
682
- * This is a one-off on the receiver.
687
+ * In contrast to the sender, this can be thought of as a one-off on the
688
+ * receiver, since the sender's {@link executeSagaLoop} is what actually
689
+ * drives the ping-pong process.
683
690
  */
684
691
  async handleResponseSagaContext({ sagaContext, initDomainGraph, mySpace, myTempSpace, identity, identitySecret, metaspace, }) {
685
692
  const lc = `${this.lc}[${this.handleResponseSagaContext.name}]`;
@@ -699,10 +706,6 @@ export class SyncSagaCoordinator {
699
706
  if (logalot) {
700
707
  console.log(`${lc} handling frame stage: ${stage}`);
701
708
  }
702
- /**
703
- * don't like this name, need to refactor
704
- */
705
- const srcGraph = toFlatGraph({ ibGibs: sagaContext.payloadIbGibsDomain }) ?? {};
706
709
  let nextFrameInfo;
707
710
  switch (stage) {
708
711
  case SyncStage.init:
@@ -729,15 +732,19 @@ export class SyncSagaCoordinator {
729
732
  nextFrameInfo = await this.handleDeltaFrame({
730
733
  sagaContext,
731
734
  sagaIbGib,
732
- srcGraph,
733
- metaspace,
734
- mySpace,
735
- myTempSpace,
735
+ metaspace, mySpace, myTempSpace,
736
736
  identity,
737
737
  });
738
738
  break;
739
739
  case SyncStage.commit:
740
- nextFrameInfo = await this.handleCommitFrame({ sagaIbGib, metaspace, mySpace: mySpace, myTempSpace: myTempSpace, identity, });
740
+ if (logalot) {
741
+ console.log(`${lc}[${getSyncSagaFrameOrigin({ sagaFrame: sagaIbGib })}] mySpace.ib: ${mySpace.ib} (I: 5b270996d848907238d817fffa64a126)`);
742
+ }
743
+ nextFrameInfo = await this.handleCommitFrame({
744
+ sagaIbGib,
745
+ metaspace, mySpace, myTempSpace,
746
+ identity,
747
+ });
741
748
  break;
742
749
  default:
743
750
  throw new Error(`${lc} (UNEXPECTED) Unknown sync stage: ${stage} (E: 9c2b4c8a6d34469f8263544710183355)`);
@@ -766,7 +773,7 @@ export class SyncSagaCoordinator {
766
773
  * **Execution Context**: **Receiver (Remote)**.
767
774
  *
768
775
  * The Receiver performs Gap Analysis here:
769
- * 1. Compares Sender's Knowledge Vector (in `sagaIbGib`) vs Receiver's Local KV.
776
+ * 1. Compares Sender's Knowledge Map (in `sagaIbGib`) vs Receiver's Local Knowledge Map.
770
777
  * 2. Identifies what Sender needs (`pushOfferAddrs`).
771
778
  * 3. Identifies what Receiver needs (`deltaRequestAddrInfos`).
772
779
  * 4. Returns an `Ack` frame containing these lists.
@@ -779,15 +786,17 @@ export class SyncSagaCoordinator {
779
786
  if (logalot) {
780
787
  console.log(`${lc} starting... (I: 9d88dcad0408c029e898a4bcf3b08426)`);
781
788
  }
782
- console.log(`${lc} [TEST DEBUG] Receiver mySpace: ${mySpace.ib}`);
789
+ if (logalot) {
790
+ console.log(`${lc} [TEST DEBUG] Receiver mySpace: ${mySpace.ib}`);
791
+ }
783
792
  // Extract Init Data
784
793
  const initData = messageData; // Using renamed variable for clarity
785
794
  if (initData.stage !== SyncStage.init) {
786
795
  throw new Error(`${lc} Invalid init frame: initData.stage !== SyncStage.init (E: c91be82970e4decc58f56bf8fc1ffc26)`);
787
796
  }
788
797
  // if (logalot) { console.log(`${lc} initData: ${pretty(initData)} (I: 46b0f8441b96ad7a388f1ce3239dd826)`); }
789
- if (!initData || !initData.knowledgeVector) {
790
- throw new Error(`${lc} Invalid init frame: missing knowledgeVector (E: ed02c869e028d2d06841b9c7f80f2826)`);
798
+ if (!initData || !initData.knowledgeMap) {
799
+ throw new Error(`${lc} Invalid init frame: missing knowledgeMap (E: ed02c869e028d2d06841b9c7f80f2826)`);
791
800
  }
792
801
  // Determine Strategy from Saga Data (since V1 stores it in root)
793
802
  const conflictStrategy = sagaIbGib.data.conflictStrategy || SyncConflictStrategy.abort;
@@ -822,12 +831,14 @@ export class SyncSagaCoordinator {
822
831
  /**
823
832
  * "remote" is sender in this case
824
833
  */
825
- const remoteKV = initData.knowledgeVector;
834
+ const remoteKnowledge = initData.knowledgeMap;
826
835
  if (logalot) {
827
- console.log(`${lc} remoteKV: ${pretty(remoteKV)} (I: 9f957862356dfeae183c200854e86e26)`);
836
+ console.log(`${lc} remoteKnowledge: ${pretty(remoteKnowledge)} (I: 9f957862356dfeae183c200854e86e26)`);
837
+ }
838
+ const remoteTjps = Object.keys(remoteKnowledge);
839
+ if (logalot) {
840
+ console.log(`${lc} [TEST DEBUG] remoteTjps: ${JSON.stringify(remoteTjps)}`);
828
841
  }
829
- const remoteTjps = Object.keys(remoteKV);
830
- console.log(`${lc} [TEST DEBUG] remoteTjps: ${JSON.stringify(remoteTjps)}`);
831
842
  if (logalot) {
832
843
  console.log(`${lc} remoteTjps: ${pretty(remoteTjps)} (I: 86ea4c53db0dc184c8b253386c402126)`);
833
844
  }
@@ -846,18 +857,22 @@ export class SyncSagaCoordinator {
846
857
  throw new Error(`(UNEXPECTED) resGetLatestAddrs.data.latestAddrsMap falsy? (E: 16bc386dd51d0ff53a49620b1e641826)`);
847
858
  }
848
859
  localLatestAddrsMap = resGetLatestAddrs.data.latestAddrsMap;
849
- console.log(`${lc} [TEST DEBUG] localKV: ${JSON.stringify(localLatestAddrsMap)}`);
850
860
  if (logalot) {
851
- console.log(`${lc} localKV: ${pretty(localLatestAddrsMap)} (I: 980975642cbccd8018cf0cd808d30826)`);
861
+ console.log(`${lc} [TEST DEBUG] localKnowledge: ${JSON.stringify(localLatestAddrsMap)}`);
862
+ }
863
+ if (logalot) {
864
+ console.log(`${lc} localKnowledge: ${pretty(localLatestAddrsMap)} (I: 980975642cbccd8018cf0cd808d30826)`);
852
865
  }
853
866
  }
854
867
  // 2. Gap Analysis
855
868
  for (const tjp of remoteTjps) {
856
- const remoteAddr = remoteKV[tjp];
869
+ const remoteAddr = remoteKnowledge[tjp];
857
870
  const localAddr = localLatestAddrsMap[tjp];
858
871
  if (!localAddr) {
859
872
  // We (Receiver) don't have this timeline at all. Request it.
860
- console.log(`${lc} [TEST DEBUG] Missing local timeline for TJP: ${tjp}. Requesting remoteAddr: ${remoteAddr}`);
873
+ if (logalot) {
874
+ console.log(`${lc} [TEST DEBUG] Missing local timeline for TJP: ${tjp}. Requesting remoteAddr: ${remoteAddr}`);
875
+ }
861
876
  deltaRequestAddrInfos.push({
862
877
  addr: remoteAddr,
863
878
  tjpAddr: tjp,
@@ -869,10 +884,14 @@ export class SyncSagaCoordinator {
869
884
  // we do have this timeline...
870
885
  if (localAddr === remoteAddr) {
871
886
  // ...already synced
872
- console.log(`${lc} [TEST DEBUG] TJP ${tjp}: Synced (localAddr === remoteAddr)`);
887
+ if (logalot) {
888
+ console.log(`${lc} [TEST DEBUG] TJP ${tjp}: Synced (localAddr === remoteAddr)`);
889
+ }
873
890
  continue;
874
891
  }
875
- console.log(`${lc} [TEST DEBUG] TJP ${tjp}: localAddr=${localAddr}, remoteAddr=${remoteAddr} - checking for divergence...`);
892
+ if (logalot) {
893
+ console.log(`${lc} [TEST DEBUG] TJP ${tjp}: localAddr=${localAddr}, remoteAddr=${remoteAddr} - checking for divergence...`);
894
+ }
876
895
  // we have this timeline but it's not synced...
877
896
  // We're executing on receiver. Check if Remote (Sender) is in
878
897
  // our past, and if so, we are ahead and need to push the delta
@@ -885,7 +904,9 @@ export class SyncSagaCoordinator {
885
904
  if (remoteIsInPast) {
886
905
  // we're ahead, so push the delta of what the sender doesn't
887
906
  // have (we have full knowledge)
888
- console.log(`${lc} [TEST DEBUG] TJP ${tjp}: Remote (sender) is in past - offering push`);
907
+ if (logalot) {
908
+ console.log(`${lc} [TEST DEBUG] TJP ${tjp}: Remote (sender) is in past - offering push`);
909
+ }
889
910
  const deltaGraph = await getDeltaDependencyGraph({
890
911
  ibGibAddr: localAddr,
891
912
  live: false, // always live: false right?
@@ -906,7 +927,6 @@ export class SyncSagaCoordinator {
906
927
  */
907
928
  let localIsInPast = false;
908
929
  try {
909
- // we could
910
930
  localIsInPast = await isPastFrame({
911
931
  olderAddr: localAddr,
912
932
  newerAddr: remoteAddr,
@@ -921,7 +941,9 @@ export class SyncSagaCoordinator {
921
941
  }
922
942
  if (localIsInPast) {
923
943
  // Fast-Forward: We update to remote's tip.
924
- console.log(`${lc} [TEST DEBUG] TJP ${tjp}: Local is in past - requesting delta`);
944
+ if (logalot) {
945
+ console.log(`${lc} [TEST DEBUG] TJP ${tjp}: Local is in past - requesting delta`);
946
+ }
925
947
  deltaRequestAddrInfos.push({
926
948
  addr: remoteAddr,
927
949
  tjpAddr: tjp,
@@ -930,7 +952,9 @@ export class SyncSagaCoordinator {
930
952
  }
931
953
  else {
932
954
  // DIVERGENCE: Both have changes the other doesn't know about.
933
- console.log(`${lc} [TEST DEBUG] TJP ${tjp}: DIVERGENCE DETECTED! conflictStrategy=${conflictStrategy}`);
955
+ if (logalot) {
956
+ console.log(`${lc} [TEST DEBUG] TJP ${tjp}: DIVERGENCE DETECTED! conflictStrategy=${conflictStrategy}`);
957
+ }
934
958
  if (conflictStrategy === 'abort') {
935
959
  // Abort Strategy: We will treat this as terminal.
936
960
  // But for Unified Ack, we just mark it terminal in the list?
@@ -944,26 +968,23 @@ export class SyncSagaCoordinator {
944
968
  reason: 'divergence',
945
969
  terminal: true
946
970
  });
971
+ // todo: create error saga frame for when aborting or other terminal error
947
972
  }
948
973
  else if (conflictStrategy === 'optimistic') {
949
974
  // Optimistic: We want resolve this.
950
975
  // We need to send our history to the Sender so they can Merge.
951
976
  // Fetch Full History for Local Timeline
952
- // Note: We might optimize this to only send "recent" history if we had a KV?
953
- // But for now, get full past.
954
- // Optimization: localKV might not have full history.
955
- // We need to inspect the 'past' of the local tip.
956
- // We need the ACTUAL object to get the past.
957
- // We have localAddr.
958
977
  const resLocalTip = await getFromSpace({ space: mySpace, addr: localAddr });
959
978
  if (!resLocalTip.success || resLocalTip.ibGibs?.length !== 1) {
960
- throw new Error(`couldn't get local tip (${localAddr}) from space (${mySpace.ib}) (E: 83cb88a767e22bbda99c6788bec50526)`);
979
+ throw new Error(`couldn't get local tip (${localAddr}) from space (${mySpace.ib}). errorMsg: ${resLocalTip.errorMsg ?? '[unknown error (E: b3c3d823276300aa384ebdba4a8eb826)]'} (E: 83cb88a767e22bbda99c6788bec50526)`);
961
980
  }
962
981
  const localTip = resLocalTip.ibGibs[0];
963
- if (!localTip) {
964
- throw new Error(`${lc} Failed to load local tip for conflict resolution. (E: c39448ad6b3a72af78339ad877a56826)`);
965
- }
966
- const timelineAddrs = [...(localTip.rel8ns?.past ?? []), localAddr];
982
+ const pastAddrs = await getHistoryAddrs({
983
+ timeline: localTip,
984
+ space: mySpace,
985
+ metaspace,
986
+ });
987
+ const timelineAddrs = [...pastAddrs, localAddr];
967
988
  conflicts.push({
968
989
  tjpAddr: tjp,
969
990
  localAddr,
@@ -1134,15 +1155,21 @@ export class SyncSagaCoordinator {
1134
1155
  // #region sanity/validation
1135
1156
  // 1. Check for Conflicts
1136
1157
  const conflicts = ackData.conflicts || [];
1137
- console.log(`${lc} [CONFLICT DEBUG] Received conflicts from Ack: ${conflicts.length}`);
1138
- if (conflicts.length > 0) {
1158
+ if (logalot) {
1159
+ console.log(`${lc} [CONFLICT DEBUG] Received conflicts from Ack: ${conflicts.length}`);
1160
+ }
1161
+ if (logalot && conflicts.length > 0) {
1139
1162
  console.log(`${lc} [CONFLICT DEBUG] Conflicts detail: ${JSON.stringify(conflicts, null, 2)}`);
1140
1163
  }
1141
1164
  const terminalConflicts = conflicts.filter(c => c.terminal);
1142
1165
  if (terminalConflicts.length > 0) {
1143
- console.warn(`${lc} Received terminal conflicts from Ack: ${JSON.stringify(terminalConflicts)}`);
1144
- // Terminal failure. Sender should probably Commit(Fail) or just Abort.
1145
- // For now, throw to trigger abort.
1166
+ if (logalot) {
1167
+ console.warn(`${lc} Received terminal conflicts from Ack: ${JSON.stringify(terminalConflicts)}`);
1168
+ }
1169
+ // Terminal failure. Sender should probably Commit(Fail) or just
1170
+ // Abort. For now, throw to trigger abort. the incoming ack
1171
+ // frame has already been persisted in local durable space by
1172
+ // now.
1146
1173
  throw new Error(`${lc} Peer reported terminal conflicts. (E: 23a0096ee05a2ccfa89334e8f156b426)`);
1147
1174
  }
1148
1175
  // at this point, if we have conflicts, they are non-terminal
@@ -1153,7 +1180,9 @@ export class SyncSagaCoordinator {
1153
1180
  */
1154
1181
  const outgoingDeltaAddrRequestInfos = []; // Additional requests for merging
1155
1182
  if (conflicts.length > 0) {
1156
- console.log(`${lc} [CONFLICT DEBUG] Processing ${conflicts.length} non-terminal conflicts`);
1183
+ if (logalot) {
1184
+ console.log(`${lc} [CONFLICT DEBUG] Processing ${conflicts.length} non-terminal conflicts`);
1185
+ }
1157
1186
  // We need to resolve these.
1158
1187
  // Strategy:
1159
1188
  // 1. Analyze Divergence (Sender vs Receiver)
@@ -1261,10 +1290,14 @@ export class SyncSagaCoordinator {
1261
1290
  // console.log(`${lc} [CONFLICT DEBUG] No receiver-only frames found for this conflict`);
1262
1291
  // }
1263
1292
  }
1264
- console.log(`${lc} [CONFLICT DEBUG] Finished processing ${conflicts.length} conflicts. outgoingDeltaAddrRequestInfos: ${outgoingDeltaAddrRequestInfos.length}`);
1293
+ if (logalot) {
1294
+ console.log(`${lc} [CONFLICT DEBUG] Finished processing ${conflicts.length} conflicts. outgoingDeltaAddrRequestInfos: ${outgoingDeltaAddrRequestInfos.length}`);
1295
+ }
1265
1296
  }
1266
1297
  else {
1267
- console.log(`${lc} [CONFLICT DEBUG] No optimistic conflicts to process`);
1298
+ if (logalot) {
1299
+ console.log(`${lc} [CONFLICT DEBUG] No optimistic conflicts to process`);
1300
+ }
1268
1301
  }
1269
1302
  // 2. Prepare Delta Payload (What Receiver Requesting + Our Conflict Logic)
1270
1303
  /**
@@ -1345,7 +1378,7 @@ export class SyncSagaCoordinator {
1345
1378
  * 2. **Fulfillment**: Checks `requests`. If Peer requested data, gathers it and prepares `outgoingPayload`.
1346
1379
  * 3. **Completion**: If no more requests, transitions to `Commit`.
1347
1380
  */
1348
- async handleDeltaFrame({ sagaContext, sagaIbGib, srcGraph, mySpace, myTempSpace, metaspace, identity, }) {
1381
+ async handleDeltaFrame({ sagaContext, sagaIbGib, mySpace, myTempSpace, metaspace, identity, }) {
1349
1382
  const lc = `${this.lc}[${this.handleDeltaFrame.name}]`;
1350
1383
  try {
1351
1384
  if (logalot) {
@@ -1364,32 +1397,44 @@ export class SyncSagaCoordinator {
1364
1397
  console.log(`${lc} deltaData: ${pretty(deltaData)} (I: a76008681df458cfbcdc4848f825a826)`);
1365
1398
  }
1366
1399
  // #endregion validate/sanity
1367
- console.log(`${lc} [CONFLICT DEBUG] deltaData.payloadAddrs count: ${deltaData.payloadAddrs?.length || 0}`);
1400
+ if (logalot) {
1401
+ console.log(`${lc} [CONFLICT DEBUG] deltaData.payloadAddrs count: ${deltaData.payloadAddrs?.length || 0}`);
1402
+ }
1368
1403
  const peerProposesCommit = deltaData.proposeCommit || false;
1369
1404
  /**
1370
1405
  * these are already in the local temp space
1371
1406
  */
1372
1407
  const receivedPayloadIbGibs = sagaContext.payloadIbGibsDomain ?? [];
1373
1408
  // 2. Fulfill Peer Requests (Outgoing Payload with Delta Dependencies)
1374
- console.log(`${lc} [CONFLICT DEBUG] Fulfilling ${(deltaData.deltaRequestAddrInfos || []).length} peer requests`);
1409
+ if (logalot) {
1410
+ console.log(`${lc} [CONFLICT DEBUG] Fulfilling ${(deltaData.deltaRequestAddrInfos || []).length} peer requests`);
1411
+ }
1375
1412
  const outgoingPayload = await this.getPayloadsForRequestedInfos({
1376
1413
  deltaRequestAddrInfos: deltaData.deltaRequestAddrInfos || [],
1377
1414
  mySpace,
1378
1415
  });
1379
- console.log(`${lc} [CONFLICT DEBUG] Outgoing payload size (with deps): ${outgoingPayload.length}`);
1416
+ if (logalot) {
1417
+ console.log(`${lc} [CONFLICT DEBUG] Outgoing payload size (with deps): ${outgoingPayload.length}`);
1418
+ }
1380
1419
  // 3. Execute Merges (If applicable)
1381
1420
  // Check if we have pending conflicts that we CAN resolve now that we have data.
1382
1421
  // We look at the Saga History (Ack Frame) to find conflicts.
1383
1422
  // Optimization: Do this only if we received payloads.
1384
1423
  const mergeResultIbGibs = [];
1385
- console.log(`${lc} [CONFLICT DEBUG] Checking for merge. receivedPayloadIbGibs.length: ${receivedPayloadIbGibs.length}`);
1424
+ if (logalot) {
1425
+ console.log(`${lc} [CONFLICT DEBUG] Checking for merge. receivedPayloadIbGibs.length: ${receivedPayloadIbGibs.length}`);
1426
+ }
1386
1427
  if (receivedPayloadIbGibs.length > 0) {
1387
- console.log(`${lc} [TEST DEBUG] Received Payloads (${receivedPayloadIbGibs.length}). Checking for conflicts/merges...`);
1428
+ if (logalot) {
1429
+ console.log(`${lc} [TEST DEBUG] Received Payloads (${receivedPayloadIbGibs.length}). Checking for conflicts/merges...`);
1430
+ }
1388
1431
  // Find the Ack frame in history to get conflicts
1389
1432
  // Optimization: Batch fetch history from `sagaIbGib.rel8ns.past`
1390
1433
  // V1 timelines carry full history in `past`.
1391
1434
  const pastAddrs = sagaIbGib.rel8ns?.past || [];
1392
- console.log(`${lc} [TEST DEBUG] pastAddrs count: ${pastAddrs.length}`);
1435
+ if (logalot) {
1436
+ console.log(`${lc} [TEST DEBUG] pastAddrs count: ${pastAddrs.length}`);
1437
+ }
1393
1438
  const sagaHistory = await getFullSyncSagaHistory({
1394
1439
  sagaIbGib,
1395
1440
  space: mySpace,
@@ -1428,9 +1473,13 @@ export class SyncSagaCoordinator {
1428
1473
  // We blindly attempt merge if we have both tips accessible?
1429
1474
  // We need `receiverTip` (localAddr in Ack) and `senderTip` (remoteAddr).
1430
1475
  // Check if we have receiverTip in space
1431
- console.log(`${lc} [CONFLICT DEBUG] Attempting merge for conflict. ReceiverTip: ${receiverTip}, SenderTip: ${senderTip}`);
1476
+ if (logalot) {
1477
+ console.log(`${lc} [CONFLICT DEBUG] Attempting merge for conflict. ReceiverTip: ${receiverTip}, SenderTip: ${senderTip}`);
1478
+ }
1432
1479
  const resRecTip = await getFromSpace({ addr: receiverTip, space: myTempSpace }); // Check myTempSpace for incoming data
1433
- console.log(`${lc} [CONFLICT DEBUG] ReceiverTip found in myTempSpace: ${!!resRecTip.ibGibs?.[0]}`);
1480
+ if (logalot) {
1481
+ console.log(`${lc} [CONFLICT DEBUG] ReceiverTip found in myTempSpace: ${!!resRecTip.ibGibs?.[0]}`);
1482
+ }
1434
1483
  if (resRecTip.success && resRecTip.ibGibs?.[0]) {
1435
1484
  // We have the tip!
1436
1485
  // Do we have the full history?
@@ -1445,7 +1494,9 @@ export class SyncSagaCoordinator {
1445
1494
  metaspace,
1446
1495
  });
1447
1496
  if (mergeResult) {
1448
- console.log(`${lc} [TEST DEBUG] Merge success! New Tip: ${getIbGibAddr({ ibGib: mergeResult })}`);
1497
+ if (logalot) {
1498
+ console.log(`${lc} [TEST DEBUG] Merge success! New Tip: ${getIbGibAddr({ ibGib: mergeResult })}`);
1499
+ }
1449
1500
  if (logalot) {
1450
1501
  console.log(`${lc} Merge success! New Tip: ${getIbGibAddr({ ibGib: mergeResult })}`);
1451
1502
  }
@@ -1454,7 +1505,7 @@ export class SyncSagaCoordinator {
1454
1505
  }
1455
1506
  }
1456
1507
  catch (e) {
1457
- console.error(`${lc} Merge failed: ${e}`);
1508
+ console.error(`${lc} (NOT THROWN) Merge failed: ${e} (E: 491b464fc6f4857f52ff3df213105826)`);
1458
1509
  // If merge fails, we might Abort or just continue?
1459
1510
  }
1460
1511
  }
@@ -1602,15 +1653,47 @@ export class SyncSagaCoordinator {
1602
1653
  /**
1603
1654
  * should throw if fails
1604
1655
  */
1605
- async executeLocalCommit({ deltaFrame, sagaHistory, metaspace, localSpace, localTempSpace, identity, }) {
1656
+ async executeLocalCommit({ deltaFrame, commitFrame, sagaHistory, metaspace, localSpace, localTempSpace, identity, }) {
1606
1657
  const lc = `${this.lc}[${this.executeLocalCommit.name}]`;
1607
1658
  try {
1608
1659
  if (logalot) {
1609
1660
  console.log(`${lc} starting... (I: 6734980446b86a63c1af6e2e206de826)`);
1610
1661
  }
1662
+ if (!deltaFrame && !commitFrame) {
1663
+ throw new Error(`(UNEXPECTED) !deltaFrame && !commitFrame? we're expecting to execute the commit based off of EITHER a delta OR a commit frame. (E: 10cae319a2685a672866f5583514e326)`);
1664
+ }
1665
+ else if (deltaFrame && commitFrame) {
1666
+ throw new Error(`(UNEXPECTED) deltaFrame && commitFrame? we're expecting to execute the commit based off of EITHER a delta OR a commit frame. (E: b9037b1ed6d8684ac8a5d01328bad826)`);
1667
+ }
1668
+ /**
1669
+ * Sync has a two-stage commit. The first is from a delta frame with
1670
+ * `proposeCommit: true`. That produces a commit frame, which on the
1671
+ * other end triggers the second leg.
1672
+ */
1673
+ const isFirstCommitLeg = !!deltaFrame;
1674
+ const currentFrame = isFirstCommitLeg ? deltaFrame : commitFrame;
1675
+ if (!currentFrame) {
1676
+ throw new Error(`(UNEXPECTED) !currentFrame? something wrong with my logic. (E: 4ec0ce6625cc1d677bc902c839ca1a26)`);
1677
+ }
1678
+ /**
1679
+ * we only want to register new ibgibs from the other end, so we
1680
+ * will compare the history payloads/push offers with the context
1681
+ * that provided those payloads.
1682
+ *
1683
+ * So we will filter out the history that we produced, which should
1684
+ * leave us only with externally created payload addrs.
1685
+ *
1686
+ * NOTE: I have this at the beginning of the function PURELY to get
1687
+ * a log value in to understand the context of this function's
1688
+ * output.
1689
+ */
1690
+ const currentFrameOrigin = getSyncSagaFrameOrigin({ sagaFrame: currentFrame });
1691
+ if (logalot) {
1692
+ console.log(`${lc} currentFrameOrigin: ${currentFrameOrigin} (I: 3add8f8390c89743ae554bd3cc60b826)`);
1693
+ }
1611
1694
  // #region validate/sanity
1612
- if (!deltaFrame.data) {
1613
- throw new Error(`(UNEXPECTED) deltaFrame.data falsy? (E: a8be68d48668d93d992d793834823826)`);
1695
+ if (!currentFrame.data) {
1696
+ throw new Error(`(UNEXPECTED) currentFrame.data falsy? (E: a8be68d48668d93d992d793834823826)`);
1614
1697
  }
1615
1698
  // #endregion validate/sanity
1616
1699
  // * move all payload addrs from temp space to local space
@@ -1622,10 +1705,16 @@ export class SyncSagaCoordinator {
1622
1705
  allPayloadAddrsDomainTransferred.push(addr);
1623
1706
  }
1624
1707
  };
1625
- sagaHistory.forEach(x => {
1708
+ sagaHistory.filter(x => {
1709
+ const frameExecutionContext = getSyncSagaFrameOrigin({ sagaFrame: x.sagaIbGib });
1710
+ return currentFrameOrigin === frameExecutionContext;
1711
+ }).forEach(x => {
1626
1712
  if (!x.sagaIbGib.data) {
1627
1713
  throw new Error(`(UNEXPECTED) sagaIbGib.data falsy? (E: 34d7f8cdee14717ce828878d98f89826)`);
1628
1714
  }
1715
+ if (logalot) {
1716
+ console.log(`${lc}[${currentFrameOrigin}] history slice: ${pretty(x)} (I: e5a9436fb66b0df3183bd6d81be2ca26)`);
1717
+ }
1629
1718
  x.msgStones.forEach(msgStone => {
1630
1719
  if (!msgStone.data) {
1631
1720
  throw new Error(`(UNEXPECTED) msgStone.data falsy? (E: 21406101f91847514cc759c8a7382f26)`);
@@ -1646,58 +1735,101 @@ export class SyncSagaCoordinator {
1646
1735
  }
1647
1736
  });
1648
1737
  });
1738
+ if (logalot) {
1739
+ console.log(`${lc}[${currentFrameOrigin}] allPayloadAddrsDomainTransferred: ${allPayloadAddrsDomainTransferred.length > 0 ? allPayloadAddrsDomainTransferred.join(', ') : 'none'} (I: a1950eb3ca95bdc9ec18a4b8823e9826)`);
1740
+ }
1649
1741
  // at this point, we have a list of ALL payload addrs retrieved.
1650
1742
  let allPayloadIbGibsDomainTransferred = [];
1651
- const resGetAllTransferred = await getFromSpace({ addrs: allPayloadAddrsDomainTransferred, space: localTempSpace });
1652
- if (resGetAllTransferred.success && resGetAllTransferred.ibGibs && resGetAllTransferred.ibGibs.length === allPayloadAddrsDomainTransferred.length) {
1653
- allPayloadIbGibsDomainTransferred = resGetAllTransferred.ibGibs.concat();
1654
- }
1655
- else {
1656
- // errored out, gather info
1657
- if (!resGetAllTransferred.rawResultIbGib) {
1658
- throw new Error(`(UNEXPECTED) !resGetAllTransferred.rawResultIbGib falsy? (E: dc6cf8729668f4fbe8c024f887d97a26)`);
1743
+ if (allPayloadAddrsDomainTransferred.length > 0) {
1744
+ const resGetAllTransferred = await getFromSpace({ addrs: allPayloadAddrsDomainTransferred, space: localTempSpace });
1745
+ if (resGetAllTransferred.success && resGetAllTransferred.ibGibs && resGetAllTransferred.ibGibs.length === allPayloadAddrsDomainTransferred.length) {
1746
+ allPayloadIbGibsDomainTransferred = resGetAllTransferred.ibGibs.concat();
1747
+ }
1748
+ else {
1749
+ // errored out, gather info
1750
+ if (!resGetAllTransferred.rawResultIbGib) {
1751
+ throw new Error(`(UNEXPECTED) !resGetAllTransferred.rawResultIbGib falsy? (E: dc6cf8729668f4fbe8c024f887d97a26)`);
1752
+ }
1753
+ const { addrsNotFound, addrsErrored, errors } = resGetAllTransferred.rawResultIbGib.data;
1754
+ throw new Error(`(UNEXPECTED) we couldn't get all addrs transferred throughout the saga from the tempspace (${localTempSpace.ib})? addrsNotFound: ${addrsNotFound ?? []}. addrsErrored: ${addrsErrored ?? []}. errors: ${errors ?? []}(E: 222e341e634862b4d88ae7282584d826)`);
1659
1755
  }
1660
- const { addrsNotFound, addrsErrored, errors } = resGetAllTransferred.rawResultIbGib.data;
1661
- throw new Error(`(UNEXPECTED) we couldn't get all addrs transferred throughout the saga from the tempspace (${localTempSpace.ib})? addrsNotFound: ${addrsNotFound ?? []}. addrsErrored: ${addrsErrored ?? []}. errors: ${errors ?? []}(E: 222e341e634862b4d88ae7282584d826)`);
1662
1756
  }
1663
1757
  // now we have all ibgibs transferred, first put them all the local space
1664
- const { payload_Dnas, payload_NonDnas } = await putInSpace_dnasThenNonDnas({
1665
- ibGibs: allPayloadIbGibsDomainTransferred,
1666
- space: localSpace
1667
- });
1668
- const { mapWithTjp_NoDna, mapWithTjp_YesDna, mapWithoutTjps } = splitPerTjpAndOrDna({ ibGibs: payload_NonDnas, filterPrimitives: true });
1669
- // first register all non-tjp stones
1670
- const nontjps = Object.values(mapWithoutTjps);
1671
- for (const nontjp of nontjps) {
1672
- await metaspace.registerNewIbGib({
1673
- ibGib: nontjp,
1674
- space: localSpace,
1675
- });
1676
- }
1677
- // next register each timeline in order...
1678
- // ...first the ones without dna...
1679
- const timelinesByTjpAddr_NoDna = getTimelinesGroupedByTjp({ ibGibs: Object.values(mapWithTjp_NoDna) });
1680
- const tjpAddrs_NoDna = Object.keys(timelinesByTjpAddr_NoDna);
1681
- for (const tjpAddr_NoDna of tjpAddrs_NoDna) {
1682
- const timelineIbGibs = timelinesByTjpAddr_NoDna[tjpAddr_NoDna];
1683
- for (const ibGib of timelineIbGibs) {
1684
- await metaspace.registerNewIbGib({
1685
- ibGib,
1686
- space: localSpace,
1687
- });
1758
+ if (allPayloadIbGibsDomainTransferred.length === 0) {
1759
+ // nothing was synced
1760
+ if (logalot) {
1761
+ console.log(`${lc}[${currentFrameOrigin}] no changes on this end (I: fa30d18e83a87ee9e8487fbb5d632b26)`);
1688
1762
  }
1689
1763
  }
1690
- // ...then the ones WITH dna.
1691
- const timelinesByTjpAddr_YesDna = getTimelinesGroupedByTjp({ ibGibs: Object.values(mapWithTjp_YesDna) });
1692
- const tjpAddrs_YesDna = Object.keys(timelinesByTjpAddr_YesDna);
1693
- for (const tjpAddr_YesDna of tjpAddrs_YesDna) {
1694
- const timelineIbGibs = timelinesByTjpAddr_YesDna[tjpAddr_YesDna];
1695
- for (const ibGib of timelineIbGibs) {
1764
+ else {
1765
+ if (logalot) {
1766
+ console.log(`${lc}[${currentFrameOrigin}] ${allPayloadIbGibsDomainTransferred.length} changes detected (I: fa30d18e83a87ee9e8487fbb5d632b26)`);
1767
+ }
1768
+ if (logalot) {
1769
+ console.log(`${lc} put all into localSpace (${localSpace.ib}) starting... (I: d5e0d9870e380b61e80c729660058826)`);
1770
+ }
1771
+ const { payload_Dnas, payload_NonDnas } = await putInSpace_dnasThenNonDnas({
1772
+ ibGibs: allPayloadIbGibsDomainTransferred,
1773
+ space: localSpace
1774
+ });
1775
+ if (logalot) {
1776
+ console.log(`${lc} put all into localSpace (${localSpace.ib}) complete. (I: d5e0d9870e380b61e80c729660058826)`);
1777
+ }
1778
+ const { mapWithTjp_NoDna, mapWithTjp_YesDna, mapWithoutTjps } = splitPerTjpAndOrDna({ ibGibs: payload_NonDnas, filterPrimitives: true });
1779
+ // first register all non-tjp stones
1780
+ if (logalot) {
1781
+ console.log(`${lc} register mapWithoutTjps starting... (I: 2b84d8f8dda85adde88696d8419bf726)`);
1782
+ }
1783
+ const nontjps = Object.values(mapWithoutTjps);
1784
+ for (const nontjp of nontjps) {
1785
+ if (logalot) {
1786
+ console.log(`${lc} registering ${getIbGibAddr({ ibGib: nontjp })} (I: 4647b4f42d27cffe0fbfce8846755826)`);
1787
+ }
1696
1788
  await metaspace.registerNewIbGib({
1697
- ibGib,
1789
+ ibGib: nontjp,
1698
1790
  space: localSpace,
1699
1791
  });
1700
1792
  }
1793
+ if (logalot) {
1794
+ console.log(`${lc} mapWithoutTjps complete. (I: 2b84d8f8dda85adde88696d8419bf726)`);
1795
+ }
1796
+ // next register each timeline in order...
1797
+ // ...first the ones without dna...
1798
+ if (logalot) {
1799
+ console.log(`${lc} register mapWithTjp_NoDna starting... (I: 96e648e4db382499b8bfaa1b37c24826)`);
1800
+ }
1801
+ const timelinesByTjpAddr_NoDna = getTimelinesGroupedByTjp({ ibGibs: Object.values(mapWithTjp_NoDna) });
1802
+ const tjpAddrs_NoDna = Object.keys(timelinesByTjpAddr_NoDna);
1803
+ for (const tjpAddr_NoDna of tjpAddrs_NoDna) {
1804
+ const timelineIbGibs = timelinesByTjpAddr_NoDna[tjpAddr_NoDna];
1805
+ for (const ibGib of timelineIbGibs) {
1806
+ await metaspace.registerNewIbGib({
1807
+ ibGib,
1808
+ space: localSpace,
1809
+ });
1810
+ }
1811
+ }
1812
+ if (logalot) {
1813
+ console.log(`${lc} register mapWithTjp_NoDna complete. (I: 96e648e4db382499b8bfaa1b37c24826)`);
1814
+ }
1815
+ // ...then the ones WITH dna.
1816
+ if (logalot) {
1817
+ console.log(`${lc} register mapWithTjp_YesDna starting... (I: d54a820e9442dee4681f6228a6795926)`);
1818
+ }
1819
+ const timelinesByTjpAddr_YesDna = getTimelinesGroupedByTjp({ ibGibs: Object.values(mapWithTjp_YesDna) });
1820
+ const tjpAddrs_YesDna = Object.keys(timelinesByTjpAddr_YesDna);
1821
+ for (const tjpAddr_YesDna of tjpAddrs_YesDna) {
1822
+ const timelineIbGibs = timelinesByTjpAddr_YesDna[tjpAddr_YesDna];
1823
+ for (const ibGib of timelineIbGibs) {
1824
+ await metaspace.registerNewIbGib({
1825
+ ibGib,
1826
+ space: localSpace,
1827
+ });
1828
+ }
1829
+ }
1830
+ if (logalot) {
1831
+ console.log(`${lc} register mapWithTjp_YesDna complete. (I: d54a820e9442dee4681f6228a6795926)`);
1832
+ }
1701
1833
  }
1702
1834
  }
1703
1835
  catch (error) {
@@ -1760,46 +1892,55 @@ export class SyncSagaCoordinator {
1760
1892
  if (logalot) {
1761
1893
  console.log(`${lc} starting... (I: e179573bdd881202f8ba3168da1c3826)`);
1762
1894
  }
1763
- let resNextSagaFrameInfo;
1764
- // Sender Logic (Finalizing):
1765
- // If we are here, we received a Commit frame from the Peer.
1766
- // This implies the Peer has successfully committed.
1767
- // We should now:
1768
- // 1. Validate (implicitly done by receiving valid frame)
1769
- // 2. Perform our own cleanup (Temp -> Dest, if applicable)
1770
- // 3. Return saga completion.
1771
- // one last validate entire history?
1772
- const history = await getFullSyncSagaHistory({
1773
- sagaIbGib,
1774
- space: mySpace,
1775
- });
1776
- const validationErrors = await validateFullSyncSagaHistory({
1777
- history,
1778
- });
1779
- if (validationErrors.length > 0) {
1780
- const errorCommitFrame = await this.createCommitFrame({
1895
+ if (!sagaIbGib.data) {
1896
+ throw new Error(`(UNEXPECTED) sagaIbGib.data falsy? (E: cbc31dbb7d28b5b8c8cddb510d7d2826)`);
1897
+ }
1898
+ if (sagaIbGib.data.errors && sagaIbGib.data.errors.length > 0) {
1899
+ // our saga errored out but we already committed the darn
1900
+ // changes previously
1901
+ throw new Error(`not implemented...saga errored out on other end but we've already committed our changes. we need to implement undoing our changes, i.e., rollback commit, which basically is deleting all the payloads that we already put in in our previous commit. (E: e8eb789e0c08f0b3cf93607cb73e9f26)`);
1902
+ }
1903
+ else {
1904
+ // Sender Logic (Finalizing):
1905
+ // If we are here, we received a Commit frame from the Peer.
1906
+ // This implies the Peer has successfully committed.
1907
+ // We should now:
1908
+ // 1. Validate (implicitly done by receiving valid frame)
1909
+ // 2. Perform our own cleanup (Temp -> Dest, if applicable)
1910
+ // 3. Return saga completion.
1911
+ // one last validate entire history ?
1912
+ const history = await getFullSyncSagaHistory({
1781
1913
  sagaIbGib,
1914
+ space: mySpace,
1915
+ });
1916
+ const validationErrors = await validateFullSyncSagaHistory({
1917
+ history,
1918
+ });
1919
+ if (validationErrors.length > 0) {
1920
+ const errorCommitFrame = await this.createCommitFrame({
1921
+ sagaIbGib,
1922
+ metaspace,
1923
+ mySpace,
1924
+ identity,
1925
+ errors: validationErrors,
1926
+ });
1927
+ return { frame: errorCommitFrame, }; /* <<<< returns early */
1928
+ }
1929
+ await this.executeLocalCommit({
1930
+ commitFrame: sagaIbGib,
1931
+ sagaHistory: history,
1932
+ localSpace: mySpace,
1933
+ localTempSpace: myTempSpace,
1782
1934
  metaspace,
1783
- mySpace,
1784
- identity,
1785
- errors: validationErrors,
1786
1935
  });
1787
- return { frame: errorCommitFrame, }; /* <<<< returns early */
1788
- }
1789
- await this.executeLocalCommit({
1790
- deltaFrame: sagaIbGib,
1791
- sagaHistory: history,
1792
- localSpace: mySpace,
1793
- localTempSpace: myTempSpace,
1794
- metaspace,
1795
- });
1796
- // todo: implement explicit cleanup logic here and in peer
1797
- console.error(`${lc} NAG ERROR (NOT THROWN): implement cleanup logic, including add a cleanup method to the peer (E: 3a9a24befb98a981a88fbdbf52920e26)`);
1798
- if (logalot) {
1799
- console.log(`${lc} Peer committed. Finalizing saga locally. Saga Complete.`);
1936
+ // todo: implement explicit cleanup logic here and in peer
1937
+ console.error(`${lc} NAG ERROR (NOT THROWN): implement cleanup logic, including add a cleanup method to the peer (E: 3a9a24befb98a981a88fbdbf52920e26)`);
1938
+ if (logalot) {
1939
+ console.log(`${lc} Peer committed. Finalizing saga locally. Saga Complete.`);
1940
+ }
1941
+ // the holy grail!
1942
+ return { sagaComplete: true };
1800
1943
  }
1801
- // the holy grail!
1802
- return { sagaComplete: true };
1803
1944
  }
1804
1945
  catch (error) {
1805
1946
  const emsg = `${lc} ${extractErrorMsg(error)}`;