@ibgib/core-gib 0.1.27 → 0.1.29

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 (48) hide show
  1. package/dist/common/meta-stone/meta-stone-helper.d.mts.map +1 -1
  2. package/dist/common/meta-stone/meta-stone-helper.mjs +19 -7
  3. package/dist/common/meta-stone/meta-stone-helper.mjs.map +1 -1
  4. package/dist/sync/sync-helpers.d.mts +11 -5
  5. package/dist/sync/sync-helpers.d.mts.map +1 -1
  6. package/dist/sync/sync-helpers.mjs +33 -9
  7. package/dist/sync/sync-helpers.mjs.map +1 -1
  8. package/dist/sync/sync-innerspace-constants.respec.mjs +36 -36
  9. package/dist/sync/sync-innerspace-constants.respec.mjs.map +1 -1
  10. package/dist/sync/sync-innerspace-deep-updates.respec.mjs +5 -3
  11. package/dist/sync/sync-innerspace-deep-updates.respec.mjs.map +1 -1
  12. package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs +2 -2
  13. package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs.map +1 -1
  14. package/dist/sync/sync-innerspace-partial-update.respec.mjs +3 -3
  15. package/dist/sync/sync-innerspace-partial-update.respec.mjs.map +1 -1
  16. package/dist/sync/sync-innerspace.respec.mjs +49 -20
  17. package/dist/sync/sync-innerspace.respec.mjs.map +1 -1
  18. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts +0 -9
  19. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts.map +1 -1
  20. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs +13 -42
  21. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs.map +1 -1
  22. package/dist/sync/sync-peer/sync-peer-v1.mjs +2 -2
  23. package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
  24. package/dist/sync/sync-saga-coordinator.d.mts +23 -159
  25. package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
  26. package/dist/sync/sync-saga-coordinator.mjs +508 -172
  27. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  28. package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts +12 -17
  29. package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts.map +1 -1
  30. package/dist/sync/sync-types.d.mts +18 -23
  31. package/dist/sync/sync-types.d.mts.map +1 -1
  32. package/dist/sync/sync-types.mjs +15 -21
  33. package/dist/sync/sync-types.mjs.map +1 -1
  34. package/package.json +1 -1
  35. package/src/common/meta-stone/meta-stone-helper.mts +17 -7
  36. package/src/sync/sync-helpers.mts +36 -13
  37. package/src/sync/sync-innerspace-constants.respec.mts +39 -39
  38. package/src/sync/sync-innerspace-deep-updates.respec.mts +6 -6
  39. package/src/sync/sync-innerspace-multiple-timelines.respec.mts +1 -1
  40. package/src/sync/sync-innerspace-partial-update.respec.mts +2 -2
  41. package/src/sync/sync-innerspace.respec.mts +20 -19
  42. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mts +11 -58
  43. package/src/sync/sync-peer/sync-peer-v1.mts +2 -2
  44. package/src/sync/sync-saga-coordinator.mts +472 -191
  45. package/src/sync/sync-saga-message/sync-saga-message-types.mts +13 -18
  46. package/src/sync/sync-types.mts +26 -33
  47. package/test_output.log +0 -0
  48. package/tmp.md +170 -62
@@ -2,11 +2,12 @@ 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
8
  import { appendToTimeline, createTimeline } from "../timeline/timeline-api.mjs";
8
9
  import { SyncConflictStrategy, SyncMode, SYNC_CONFLICT_STRATEGY_VALID_VALUES, } from "./sync-types.mjs";
9
- import { getSyncIb, getTempSpaceName, isPastFrame } from "./sync-helpers.mjs";
10
+ import { getSyncSagaFrameOrigin, getFullSyncSagaHistory, getSyncIb, getTempSpaceName, isPastFrame, putInSpace_dnasThenNonDnas, validateFullSyncSagaHistory } from "./sync-helpers.mjs";
10
11
  import { getDeltaDependencyGraph, getDependencyGraph, toFlatGraph } 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";
@@ -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).
@@ -171,7 +171,12 @@ export class SyncSagaCoordinator {
171
171
  if (logalot) {
172
172
  console.log(`${lc} Handler returned null (Saga End). (I: 43da8bb6c846b1fe7766332643be0e26)`);
173
173
  }
174
- return null;
174
+ // does this ever hit now?
175
+ return null; /* <<<< returns early */
176
+ }
177
+ else if (contextResult.nextFrameInfo?.sagaComplete) {
178
+ // this is the current proper workflow I believe as of 01/22/2026
179
+ return null; /* <<<< returns early */
175
180
  }
176
181
  // #region error conditions throw
177
182
  if (contextResult.errorMsg) {
@@ -180,9 +185,6 @@ export class SyncSagaCoordinator {
180
185
  else if (!contextResult.nextFrameInfo) {
181
186
  throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo falsy? (E: 5740542f5eb8ccb41dfec188d87c1e26)`);
182
187
  }
183
- else if (contextResult.nextFrameInfo?.responseWasNull) {
184
- throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo.responseWasNull? logic flow should not have gotten here. (E: ae06748d8c0c5e70c92322c8fb0cb426)`);
185
- }
186
188
  // #endregion error conditions throw
187
189
  // create the return context
188
190
  const { frame, payloadIbGibsDomain } = contextResult.nextFrameInfo;
@@ -405,8 +407,13 @@ export class SyncSagaCoordinator {
405
407
  metaspace,
406
408
  });
407
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) {
408
415
  if (logalot) {
409
- console.log(`${lc} Handler returned null (Saga End). (I: faae22abc818ba9b28ac6d2881cd7826)`);
416
+ console.log(`${lc} Handler returned null (Saga End). (I: 123bf9e7dca8886de72553a8d4f29e26)`);
410
417
  }
411
418
  break;
412
419
  }
@@ -417,9 +424,6 @@ export class SyncSagaCoordinator {
417
424
  else if (!contextResult.nextFrameInfo) {
418
425
  throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo falsy? (E: c287a82e823e662a77923278e2418826)`);
419
426
  }
420
- else if (contextResult.nextFrameInfo?.responseWasNull) {
421
- throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo.responseWasNull? logic flow should not have gotten here. (E: 104a32381db816b7183435e805b3d626)`);
422
- }
423
427
  // #endregion error conditions throw
424
428
  // we have another frame to process and send out, with possibly
425
429
  // payload domain ibgibs as well
@@ -728,14 +732,19 @@ export class SyncSagaCoordinator {
728
732
  sagaContext,
729
733
  sagaIbGib,
730
734
  srcGraph,
731
- metaspace,
732
- mySpace,
733
- myTempSpace,
735
+ metaspace, mySpace, myTempSpace,
734
736
  identity,
735
737
  });
736
738
  break;
737
739
  case SyncStage.commit:
738
- 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
+ });
739
748
  break;
740
749
  default:
741
750
  throw new Error(`${lc} (UNEXPECTED) Unknown sync stage: ${stage} (E: 9c2b4c8a6d34469f8263544710183355)`);
@@ -777,7 +786,9 @@ export class SyncSagaCoordinator {
777
786
  if (logalot) {
778
787
  console.log(`${lc} starting... (I: 9d88dcad0408c029e898a4bcf3b08426)`);
779
788
  }
780
- console.log(`${lc} [TEST DEBUG] Receiver mySpace: ${mySpace.ib}`);
789
+ if (logalot) {
790
+ console.log(`${lc} [TEST DEBUG] Receiver mySpace: ${mySpace.ib}`);
791
+ }
781
792
  // Extract Init Data
782
793
  const initData = messageData; // Using renamed variable for clarity
783
794
  if (initData.stage !== SyncStage.init) {
@@ -825,7 +836,9 @@ export class SyncSagaCoordinator {
825
836
  console.log(`${lc} remoteKV: ${pretty(remoteKV)} (I: 9f957862356dfeae183c200854e86e26)`);
826
837
  }
827
838
  const remoteTjps = Object.keys(remoteKV);
828
- console.log(`${lc} [TEST DEBUG] remoteTjps: ${JSON.stringify(remoteTjps)}`);
839
+ if (logalot) {
840
+ console.log(`${lc} [TEST DEBUG] remoteTjps: ${JSON.stringify(remoteTjps)}`);
841
+ }
829
842
  if (logalot) {
830
843
  console.log(`${lc} remoteTjps: ${pretty(remoteTjps)} (I: 86ea4c53db0dc184c8b253386c402126)`);
831
844
  }
@@ -844,7 +857,9 @@ export class SyncSagaCoordinator {
844
857
  throw new Error(`(UNEXPECTED) resGetLatestAddrs.data.latestAddrsMap falsy? (E: 16bc386dd51d0ff53a49620b1e641826)`);
845
858
  }
846
859
  localLatestAddrsMap = resGetLatestAddrs.data.latestAddrsMap;
847
- console.log(`${lc} [TEST DEBUG] localKV: ${JSON.stringify(localLatestAddrsMap)}`);
860
+ if (logalot) {
861
+ console.log(`${lc} [TEST DEBUG] localKV: ${JSON.stringify(localLatestAddrsMap)}`);
862
+ }
848
863
  if (logalot) {
849
864
  console.log(`${lc} localKV: ${pretty(localLatestAddrsMap)} (I: 980975642cbccd8018cf0cd808d30826)`);
850
865
  }
@@ -855,7 +870,9 @@ export class SyncSagaCoordinator {
855
870
  const localAddr = localLatestAddrsMap[tjp];
856
871
  if (!localAddr) {
857
872
  // We (Receiver) don't have this timeline at all. Request it.
858
- 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
+ }
859
876
  deltaRequestAddrInfos.push({
860
877
  addr: remoteAddr,
861
878
  tjpAddr: tjp,
@@ -867,10 +884,14 @@ export class SyncSagaCoordinator {
867
884
  // we do have this timeline...
868
885
  if (localAddr === remoteAddr) {
869
886
  // ...already synced
870
- 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
+ }
871
890
  continue;
872
891
  }
873
- 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
+ }
874
895
  // we have this timeline but it's not synced...
875
896
  // We're executing on receiver. Check if Remote (Sender) is in
876
897
  // our past, and if so, we are ahead and need to push the delta
@@ -883,7 +904,9 @@ export class SyncSagaCoordinator {
883
904
  if (remoteIsInPast) {
884
905
  // we're ahead, so push the delta of what the sender doesn't
885
906
  // have (we have full knowledge)
886
- 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
+ }
887
910
  const deltaGraph = await getDeltaDependencyGraph({
888
911
  ibGibAddr: localAddr,
889
912
  live: false, // always live: false right?
@@ -919,7 +942,9 @@ export class SyncSagaCoordinator {
919
942
  }
920
943
  if (localIsInPast) {
921
944
  // Fast-Forward: We update to remote's tip.
922
- console.log(`${lc} [TEST DEBUG] TJP ${tjp}: Local is in past - requesting delta`);
945
+ if (logalot) {
946
+ console.log(`${lc} [TEST DEBUG] TJP ${tjp}: Local is in past - requesting delta`);
947
+ }
923
948
  deltaRequestAddrInfos.push({
924
949
  addr: remoteAddr,
925
950
  tjpAddr: tjp,
@@ -928,7 +953,9 @@ export class SyncSagaCoordinator {
928
953
  }
929
954
  else {
930
955
  // DIVERGENCE: Both have changes the other doesn't know about.
931
- console.log(`${lc} [TEST DEBUG] TJP ${tjp}: DIVERGENCE DETECTED! conflictStrategy=${conflictStrategy}`);
956
+ if (logalot) {
957
+ console.log(`${lc} [TEST DEBUG] TJP ${tjp}: DIVERGENCE DETECTED! conflictStrategy=${conflictStrategy}`);
958
+ }
932
959
  if (conflictStrategy === 'abort') {
933
960
  // Abort Strategy: We will treat this as terminal.
934
961
  // But for Unified Ack, we just mark it terminal in the list?
@@ -1132,13 +1159,17 @@ export class SyncSagaCoordinator {
1132
1159
  // #region sanity/validation
1133
1160
  // 1. Check for Conflicts
1134
1161
  const conflicts = ackData.conflicts || [];
1135
- console.log(`${lc} [CONFLICT DEBUG] Received conflicts from Ack: ${conflicts.length}`);
1136
- if (conflicts.length > 0) {
1162
+ if (logalot) {
1163
+ console.log(`${lc} [CONFLICT DEBUG] Received conflicts from Ack: ${conflicts.length}`);
1164
+ }
1165
+ if (logalot && conflicts.length > 0) {
1137
1166
  console.log(`${lc} [CONFLICT DEBUG] Conflicts detail: ${JSON.stringify(conflicts, null, 2)}`);
1138
1167
  }
1139
1168
  const terminalConflicts = conflicts.filter(c => c.terminal);
1140
1169
  if (terminalConflicts.length > 0) {
1141
- console.warn(`${lc} Received terminal conflicts from Ack: ${JSON.stringify(terminalConflicts)}`);
1170
+ if (logalot) {
1171
+ console.warn(`${lc} Received terminal conflicts from Ack: ${JSON.stringify(terminalConflicts)}`);
1172
+ }
1142
1173
  // Terminal failure. Sender should probably Commit(Fail) or just Abort.
1143
1174
  // For now, throw to trigger abort.
1144
1175
  throw new Error(`${lc} Peer reported terminal conflicts. (E: 23a0096ee05a2ccfa89334e8f156b426)`);
@@ -1151,7 +1182,9 @@ export class SyncSagaCoordinator {
1151
1182
  */
1152
1183
  const outgoingDeltaAddrRequestInfos = []; // Additional requests for merging
1153
1184
  if (conflicts.length > 0) {
1154
- console.log(`${lc} [CONFLICT DEBUG] Processing ${conflicts.length} non-terminal conflicts`);
1185
+ if (logalot) {
1186
+ console.log(`${lc} [CONFLICT DEBUG] Processing ${conflicts.length} non-terminal conflicts`);
1187
+ }
1155
1188
  // We need to resolve these.
1156
1189
  // Strategy:
1157
1190
  // 1. Analyze Divergence (Sender vs Receiver)
@@ -1259,10 +1292,14 @@ export class SyncSagaCoordinator {
1259
1292
  // console.log(`${lc} [CONFLICT DEBUG] No receiver-only frames found for this conflict`);
1260
1293
  // }
1261
1294
  }
1262
- console.log(`${lc} [CONFLICT DEBUG] Finished processing ${conflicts.length} conflicts. outgoingDeltaAddrRequestInfos: ${outgoingDeltaAddrRequestInfos.length}`);
1295
+ if (logalot) {
1296
+ console.log(`${lc} [CONFLICT DEBUG] Finished processing ${conflicts.length} conflicts. outgoingDeltaAddrRequestInfos: ${outgoingDeltaAddrRequestInfos.length}`);
1297
+ }
1263
1298
  }
1264
1299
  else {
1265
- console.log(`${lc} [CONFLICT DEBUG] No optimistic conflicts to process`);
1300
+ if (logalot) {
1301
+ console.log(`${lc} [CONFLICT DEBUG] No optimistic conflicts to process`);
1302
+ }
1266
1303
  }
1267
1304
  // 2. Prepare Delta Payload (What Receiver Requesting + Our Conflict Logic)
1268
1305
  /**
@@ -1333,69 +1370,6 @@ export class SyncSagaCoordinator {
1333
1370
  }
1334
1371
  }
1335
1372
  }
1336
- async getPayloadsForRequestedInfos({ deltaRequestAddrInfos, mySpace, }) {
1337
- const lc = `${this.lc}[${this.getPayloadsForRequestedInfos.name}]`;
1338
- try {
1339
- if (logalot) {
1340
- console.log(`${lc} starting... (I: 4fe13d0d80050f20a8b74ba80cee5826)`);
1341
- }
1342
- /**
1343
- * graph of ibgibs we will send to the receiver. addr-based, so will
1344
- * already be unique (no need to call `unique` on the domains
1345
- * ibgibs)
1346
- */
1347
- const outgoingPayloadIbGibsDomainGraph = {};
1348
- for (const { addr, latestAddrAlreadyHave } of deltaRequestAddrInfos) {
1349
- let deltaDepGraph;
1350
- if (latestAddrAlreadyHave) {
1351
- // already has some, so only get the delta
1352
- // remember: if we didn't have the other's latest addr, then
1353
- // this would be in the conflicts not requested addrs
1354
- deltaDepGraph = await getDeltaDependencyGraph({
1355
- ibGibAddr: addr,
1356
- latestCommonFrameAddr: latestAddrAlreadyHave,
1357
- space: mySpace,
1358
- live: true,
1359
- });
1360
- }
1361
- else {
1362
- // doesn't have anything, so get the entire dependency graph
1363
- // INEFFICIENT: we've already gotten all of the domain
1364
- // dependencies in initDomainGraph, but getDependencyGraph
1365
- // only works against a space so we are going to rerun this.
1366
- // an optimization would be to adapt/create a new
1367
- // getDependencyGraph to work against an existing flat ibgib
1368
- // map.
1369
- deltaDepGraph = await getDependencyGraph({
1370
- ibGibAddr: addr,
1371
- space: mySpace,
1372
- live: true,
1373
- });
1374
- }
1375
- const depGraphSize = Object.keys(deltaDepGraph).length;
1376
- if (depGraphSize === 0) {
1377
- throw new Error(`(UNEXPECTED) couldn't get requested addrs in mySpace (${mySpace.ib})? How did the receiver know to ask for these addrs if they weren't in our original graph? (E: 281eaebcdf77dd73e8245b2872100826)`);
1378
- }
1379
- else {
1380
- // we have dependencies!
1381
- Object.values(deltaDepGraph).forEach(x => {
1382
- outgoingPayloadIbGibsDomainGraph[getIbGibAddr({ ibGib: x })] = x;
1383
- });
1384
- }
1385
- }
1386
- const result = Object.values(outgoingPayloadIbGibsDomainGraph);
1387
- return result;
1388
- }
1389
- catch (error) {
1390
- console.error(`${lc} ${extractErrorMsg(error)}`);
1391
- throw error;
1392
- }
1393
- finally {
1394
- if (logalot) {
1395
- console.log(`${lc} complete.`);
1396
- }
1397
- }
1398
- }
1399
1373
  /**
1400
1374
  * Handles the `Delta` frame.
1401
1375
  *
@@ -1425,51 +1399,71 @@ export class SyncSagaCoordinator {
1425
1399
  console.log(`${lc} deltaData: ${pretty(deltaData)} (I: a76008681df458cfbcdc4848f825a826)`);
1426
1400
  }
1427
1401
  // #endregion validate/sanity
1428
- console.log(`${lc} [CONFLICT DEBUG] deltaData.payloadAddrs count: ${deltaData.payloadAddrs?.length || 0}`);
1402
+ if (logalot) {
1403
+ console.log(`${lc} [CONFLICT DEBUG] deltaData.payloadAddrs count: ${deltaData.payloadAddrs?.length || 0}`);
1404
+ }
1429
1405
  const peerProposesCommit = deltaData.proposeCommit || false;
1430
1406
  /**
1431
1407
  * these are already in the local temp space
1432
1408
  */
1433
1409
  const receivedPayloadIbGibs = sagaContext.payloadIbGibsDomain ?? [];
1434
1410
  // 2. Fulfill Peer Requests (Outgoing Payload with Delta Dependencies)
1435
- console.log(`${lc} [CONFLICT DEBUG] Fulfilling ${(deltaData.deltaRequestAddrInfos || []).length} peer requests`);
1411
+ if (logalot) {
1412
+ console.log(`${lc} [CONFLICT DEBUG] Fulfilling ${(deltaData.deltaRequestAddrInfos || []).length} peer requests`);
1413
+ }
1436
1414
  const outgoingPayload = await this.getPayloadsForRequestedInfos({
1437
1415
  deltaRequestAddrInfos: deltaData.deltaRequestAddrInfos || [],
1438
1416
  mySpace,
1439
1417
  });
1440
- console.log(`${lc} [CONFLICT DEBUG] Outgoing payload size (with deps): ${outgoingPayload.length}`);
1418
+ if (logalot) {
1419
+ console.log(`${lc} [CONFLICT DEBUG] Outgoing payload size (with deps): ${outgoingPayload.length}`);
1420
+ }
1441
1421
  // 3. Execute Merges (If applicable)
1442
1422
  // Check if we have pending conflicts that we CAN resolve now that we have data.
1443
1423
  // We look at the Saga History (Ack Frame) to find conflicts.
1444
1424
  // Optimization: Do this only if we received payloads.
1445
1425
  const mergeResultIbGibs = [];
1446
- console.log(`${lc} [CONFLICT DEBUG] Checking for merge. receivedPayloadIbGibs.length: ${receivedPayloadIbGibs.length}`);
1426
+ if (logalot) {
1427
+ console.log(`${lc} [CONFLICT DEBUG] Checking for merge. receivedPayloadIbGibs.length: ${receivedPayloadIbGibs.length}`);
1428
+ }
1447
1429
  if (receivedPayloadIbGibs.length > 0) {
1448
- console.log(`${lc} [TEST DEBUG] Received Payloads (${receivedPayloadIbGibs.length}). Checking for conflicts/merges...`);
1430
+ if (logalot) {
1431
+ console.log(`${lc} [TEST DEBUG] Received Payloads (${receivedPayloadIbGibs.length}). Checking for conflicts/merges...`);
1432
+ }
1449
1433
  // Find the Ack frame in history to get conflicts
1450
1434
  // Optimization: Batch fetch history from `sagaIbGib.rel8ns.past`
1451
1435
  // V1 timelines carry full history in `past`.
1452
1436
  const pastAddrs = sagaIbGib.rel8ns?.past || [];
1453
- console.log(`${lc} [TEST DEBUG] pastAddrs count: ${pastAddrs.length}`);
1454
- let ackData;
1455
- if (pastAddrs.length > 0) {
1456
- // Batch fetch all past frames
1457
- const resPast = await getFromSpace({ addrs: pastAddrs, space: myTempSpace });
1458
- if (resPast.success && resPast.ibGibs) {
1459
- // Iterate backwards (most recent first) to find the latest Ack
1460
- for (let i = resPast.ibGibs.length - 1; i >= 0; i--) {
1461
- const pastFrame = resPast.ibGibs[i];
1462
- const messageStone = await getSyncSagaMessageFromFrame({
1463
- frameIbGib: pastFrame,
1464
- space: myTempSpace
1465
- });
1466
- if (messageStone?.data?.stage === SyncStage.ack) {
1467
- ackData = messageStone.data;
1468
- console.log(`${lc} [TEST DEBUG] Found Ack Frame. Conflicts: ${ackData.conflicts?.length || 0}`);
1469
- break;
1470
- }
1471
- }
1472
- }
1437
+ if (logalot) {
1438
+ console.log(`${lc} [TEST DEBUG] pastAddrs count: ${pastAddrs.length}`);
1439
+ }
1440
+ const sagaHistory = await getFullSyncSagaHistory({
1441
+ sagaIbGib,
1442
+ space: mySpace,
1443
+ });
1444
+ // #region validate/sanity sagaHistory
1445
+ if (sagaHistory.length === 0) {
1446
+ throw new Error(`(UNEXPECTED) sagaHistory.length is 0? We're in handleDeltaFrame. So we should have at least init and ack. (E: 815735c9cf756b275719bf434f180826)`);
1447
+ }
1448
+ if (sagaHistory.length === 1) {
1449
+ throw new Error(`(UNEXPECTED) sagaHistory.length is 1? We're in handleDeltaFrame. So we should have at least init and ack. (E: 0e4ef8e3ed088e83b2cdcd18ecea9826)`);
1450
+ }
1451
+ // #endregion validate/sanity sagaHistory
1452
+ const ackGraphs = sagaHistory.filter(x => x.msgStones.at(0).data.stage === SyncStage.ack);
1453
+ // #region validate/sanity ackGraphs
1454
+ if (ackGraphs.length > 1) {
1455
+ throw new Error(`(UNEXPECTED) more than one ack stage found in sagaHistory? we're expecting exactly one. (E: 7150983bb3a841caf8acd60826ba4f26)`);
1456
+ }
1457
+ else if (ackGraphs.length === 0) {
1458
+ throw new Error(`(UNEXPECTED) couldn't find ack stage in sagaHistory? (E: 7d2da859196b86de28e7c8183af1e826)`);
1459
+ }
1460
+ if (ackGraphs[0].msgStones.length !== 1) {
1461
+ throw new Error(`(UNEXPECTED) ackGraph has more than one msg stone? only one expected right now. (E: f07d388abff8d26f98cbf6e8d3932826)`);
1462
+ }
1463
+ // #endregion validate/sanity ackGraphs
1464
+ const ackData = ackGraphs[0].msgStones[0].data;
1465
+ if (!ackData) {
1466
+ throw new Error(`(UNEXPECTED) ackData falsy? (E: f9af88427f66a8db1ba868b810e8b826)`);
1473
1467
  }
1474
1468
  if (ackData && ackData.conflicts) {
1475
1469
  const optimisticConflicts = ackData.conflicts.filter(c => !c.terminal);
@@ -1481,9 +1475,13 @@ export class SyncSagaCoordinator {
1481
1475
  // We blindly attempt merge if we have both tips accessible?
1482
1476
  // We need `receiverTip` (localAddr in Ack) and `senderTip` (remoteAddr).
1483
1477
  // Check if we have receiverTip in space
1484
- console.log(`${lc} [CONFLICT DEBUG] Attempting merge for conflict. ReceiverTip: ${receiverTip}, SenderTip: ${senderTip}`);
1478
+ if (logalot) {
1479
+ console.log(`${lc} [CONFLICT DEBUG] Attempting merge for conflict. ReceiverTip: ${receiverTip}, SenderTip: ${senderTip}`);
1480
+ }
1485
1481
  const resRecTip = await getFromSpace({ addr: receiverTip, space: myTempSpace }); // Check myTempSpace for incoming data
1486
- console.log(`${lc} [CONFLICT DEBUG] ReceiverTip found in myTempSpace: ${!!resRecTip.ibGibs?.[0]}`);
1482
+ if (logalot) {
1483
+ console.log(`${lc} [CONFLICT DEBUG] ReceiverTip found in myTempSpace: ${!!resRecTip.ibGibs?.[0]}`);
1484
+ }
1487
1485
  if (resRecTip.success && resRecTip.ibGibs?.[0]) {
1488
1486
  // We have the tip!
1489
1487
  // Do we have the full history?
@@ -1498,7 +1496,9 @@ export class SyncSagaCoordinator {
1498
1496
  metaspace,
1499
1497
  });
1500
1498
  if (mergeResult) {
1501
- console.log(`${lc} [TEST DEBUG] Merge success! New Tip: ${getIbGibAddr({ ibGib: mergeResult })}`);
1499
+ if (logalot) {
1500
+ console.log(`${lc} [TEST DEBUG] Merge success! New Tip: ${getIbGibAddr({ ibGib: mergeResult })}`);
1501
+ }
1502
1502
  if (logalot) {
1503
1503
  console.log(`${lc} Merge success! New Tip: ${getIbGibAddr({ ibGib: mergeResult })}`);
1504
1504
  }
@@ -1507,7 +1507,7 @@ export class SyncSagaCoordinator {
1507
1507
  }
1508
1508
  }
1509
1509
  catch (e) {
1510
- console.error(`${lc} Merge failed: ${e}`);
1510
+ console.error(`${lc} (NOT THROWN) Merge failed: ${e} (E: 491b464fc6f4857f52ff3df213105826)`);
1511
1511
  // If merge fails, we might Abort or just continue?
1512
1512
  }
1513
1513
  }
@@ -1529,17 +1529,7 @@ export class SyncSagaCoordinator {
1529
1529
  stage: SyncStage.delta,
1530
1530
  payloadAddrs: outgoingPayload.map(p => getIbGibAddr({ ibGib: p })),
1531
1531
  requests: hasMyRequests ? myRequests : undefined,
1532
- proposeCommit: !hasMyRequests // If we are sending data but have no requests, we VALIDATE PROPOSAL?
1533
- // Wait. If we send data, we are NOT committing yet.
1534
- // We are sending data. The OTHER side must ingest it.
1535
- // So proposeCommit = true?
1536
- // "Here is the data. I'm done. If you are good, let's commit."
1537
- // Yes.
1538
1532
  };
1539
- // BUT if `peerProposesCommit` was true, and we are sending data, we are effectively rejecting/delaying it.
1540
- // We just send the Delta. Peer receives it, ingests, sees ProposeCommit=True (from us), and then Commits.
1541
- // So yes, proposeCommit = true.
1542
- responseDeltaData.proposeCommit = true;
1543
1533
  const deltaStone = await this.createSyncMsgStone({
1544
1534
  data: responseDeltaData,
1545
1535
  localSpace: mySpace,
@@ -1552,41 +1542,43 @@ export class SyncSagaCoordinator {
1552
1542
  localSpace: mySpace,
1553
1543
  metaspace,
1554
1544
  });
1555
- // Build control payloads: frame + its dependencies (msg stone, identity)
1556
- const payloadIbGibsControl = [deltaFrame, deltaStone];
1557
- if (identity) {
1558
- payloadIbGibsControl.push(identity);
1559
- }
1560
- // return { frame: deltaFrame, payloadIbGibsControl, payloadIbGibsDomain: outgoingPayload };
1561
1545
  return { frame: deltaFrame, payloadIbGibsDomain: outgoingPayload };
1562
- // throw new Error(`not implemented (E: 2b38a8afb6d84efcee5ab51673387826)`);
1563
1546
  }
1564
1547
  else {
1565
1548
  // We have nothing to send.
1566
1549
  if (peerProposesCommit) {
1567
1550
  // Peer is done. We are done. -> Commit.
1568
- const commitData = {
1569
- sagaId: deltaData.sagaId,
1570
- stage: SyncStage.commit,
1571
- success: true,
1572
- };
1573
- const commitStone = await this.createSyncMsgStone({
1574
- data: commitData,
1575
- localSpace: mySpace,
1576
- metaspace
1551
+ // one last validate entire history?
1552
+ const history = await getFullSyncSagaHistory({
1553
+ sagaIbGib,
1554
+ space: mySpace,
1577
1555
  });
1578
- const commitFrame = await this.evolveSyncSagaIbGib({
1579
- prevSagaIbGib: sagaIbGib,
1580
- msgStones: [commitStone],
1581
- sessionIdentity: identity,
1582
- localSpace: mySpace,
1583
- metaspace
1556
+ const validationErrors = await validateFullSyncSagaHistory({
1557
+ history,
1584
1558
  });
1585
- // Build control payloads for commit
1586
- const commitCtrlPayloads = [commitFrame, commitStone];
1587
- if (identity) {
1588
- commitCtrlPayloads.push(identity);
1559
+ if (validationErrors.length > 0) {
1560
+ const errorCommitFrame = await this.createCommitFrame({
1561
+ sagaIbGib,
1562
+ errors: validationErrors,
1563
+ metaspace, mySpace,
1564
+ identity,
1565
+ });
1566
+ return { frame: errorCommitFrame, }; /* <<<< returns early */
1589
1567
  }
1568
+ await this.executeLocalCommit({
1569
+ sagaHistory: history,
1570
+ deltaFrame: sagaIbGib,
1571
+ localTempSpace: myTempSpace,
1572
+ localSpace: mySpace,
1573
+ metaspace,
1574
+ });
1575
+ const commitFrame = await this.createCommitFrame({
1576
+ sagaIbGib,
1577
+ errors: undefined,
1578
+ metaspace,
1579
+ mySpace,
1580
+ identity,
1581
+ });
1590
1582
  return { frame: commitFrame, };
1591
1583
  }
1592
1584
  else {
@@ -1660,24 +1652,187 @@ export class SyncSagaCoordinator {
1660
1652
  }
1661
1653
  }
1662
1654
  }
1663
- async handleCommitFrame({ sagaIbGib, mySpace, myTempSpace, metaspace, identity, }) {
1664
- const lc = `${this.lc}[${this.handleCommitFrame.name}]`;
1655
+ /**
1656
+ * should throw if fails
1657
+ */
1658
+ async executeLocalCommit({ deltaFrame, commitFrame, sagaHistory, metaspace, localSpace, localTempSpace, identity, }) {
1659
+ const lc = `${this.lc}[${this.executeLocalCommit.name}]`;
1665
1660
  try {
1666
1661
  if (logalot) {
1667
- console.log(`${lc} starting... (I: e179573bdd881202f8ba3168da1c3826)`);
1662
+ console.log(`${lc} starting... (I: 6734980446b86a63c1af6e2e206de826)`);
1663
+ }
1664
+ if (!deltaFrame && !commitFrame) {
1665
+ 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)`);
1666
+ }
1667
+ else if (deltaFrame && commitFrame) {
1668
+ 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)`);
1669
+ }
1670
+ /**
1671
+ * Sync has a two-stage commit. The first is from a delta frame with
1672
+ * `proposeCommit: true`. That produces a commit frame, which on the
1673
+ * other end triggers the second leg.
1674
+ */
1675
+ const isFirstCommitLeg = !!deltaFrame;
1676
+ const currentFrame = isFirstCommitLeg ? deltaFrame : commitFrame;
1677
+ if (!currentFrame) {
1678
+ throw new Error(`(UNEXPECTED) !currentFrame? something wrong with my logic. (E: 4ec0ce6625cc1d677bc902c839ca1a26)`);
1679
+ }
1680
+ /**
1681
+ * we only want to register new ibgibs from the other end, so we
1682
+ * will compare the history payloads/push offers with the context
1683
+ * that provided those payloads.
1684
+ *
1685
+ * So we will filter out the history that we produced, which should
1686
+ * leave us only with externally created payload addrs.
1687
+ *
1688
+ * NOTE: I have this at the beginning of the function PURELY to get
1689
+ * a log value in to understand the context of this function's
1690
+ * output.
1691
+ */
1692
+ const currentFrameOrigin = getSyncSagaFrameOrigin({ sagaFrame: currentFrame });
1693
+ if (logalot) {
1694
+ console.log(`${lc} currentFrameOrigin: ${currentFrameOrigin} (I: 3add8f8390c89743ae554bd3cc60b826)`);
1695
+ }
1696
+ // #region validate/sanity
1697
+ if (!currentFrame.data) {
1698
+ throw new Error(`(UNEXPECTED) currentFrame.data falsy? (E: a8be68d48668d93d992d793834823826)`);
1668
1699
  }
1669
- // Sender Logic (Finalizing):
1670
- // If we are here, we received a Commit frame from the Peer.
1671
- // This implies the Peer has successfully committed.
1672
- // We should now:
1673
- // 1. Validate (implicitly done by receiving valid frame)
1674
- // 2. Perform our own cleanup (Temp -> Dest, if applicable)
1675
- // 3. Return null to signal saga completion.
1676
- // Note: Currently we don't have explicit cleanup logic implemented here yet (TODO).
1700
+ // #endregion validate/sanity
1701
+ // * move all payload addrs from temp space to local space
1702
+ // * register each and every iteration of each timeline (including
1703
+ // stones, which are like their own sealed timeline of length 1)
1704
+ const allPayloadAddrsDomainTransferred = [];
1705
+ const fnAddPayloadAddr = (addr) => {
1706
+ if (!allPayloadAddrsDomainTransferred.includes(addr)) {
1707
+ allPayloadAddrsDomainTransferred.push(addr);
1708
+ }
1709
+ };
1710
+ sagaHistory.filter(x => {
1711
+ const frameExecutionContext = getSyncSagaFrameOrigin({ sagaFrame: x.sagaIbGib });
1712
+ return currentFrameOrigin === frameExecutionContext;
1713
+ }).forEach(x => {
1714
+ if (!x.sagaIbGib.data) {
1715
+ throw new Error(`(UNEXPECTED) sagaIbGib.data falsy? (E: 34d7f8cdee14717ce828878d98f89826)`);
1716
+ }
1717
+ if (logalot) {
1718
+ console.log(`${lc}[${currentFrameOrigin}] history slice: ${pretty(x)} (I: e5a9436fb66b0df3183bd6d81be2ca26)`);
1719
+ }
1720
+ x.msgStones.forEach(msgStone => {
1721
+ if (!msgStone.data) {
1722
+ throw new Error(`(UNEXPECTED) msgStone.data falsy? (E: 21406101f91847514cc759c8a7382f26)`);
1723
+ }
1724
+ if (msgStone.data.stage === SyncStage.ack) {
1725
+ const ackData = msgStone.data;
1726
+ if (ackData.pushOfferInfos && ackData.pushOfferInfos.length > 0) {
1727
+ ackData.pushOfferInfos.forEach(info => {
1728
+ info.addrs.forEach(addr => fnAddPayloadAddr(addr));
1729
+ });
1730
+ }
1731
+ }
1732
+ else if (msgStone.data.stage === SyncStage.delta) {
1733
+ const deltaData = msgStone.data;
1734
+ if (deltaData.payloadAddrsDomain && deltaData.payloadAddrsDomain.length > 0) {
1735
+ deltaData.payloadAddrsDomain.forEach(addr => fnAddPayloadAddr(addr));
1736
+ }
1737
+ }
1738
+ });
1739
+ });
1677
1740
  if (logalot) {
1678
- console.log(`${lc} Peer committed. Finalizing saga locally. Saga Complete.`);
1741
+ console.log(`${lc}[${currentFrameOrigin}] allPayloadAddrsDomainTransferred: ${allPayloadAddrsDomainTransferred.length > 0 ? allPayloadAddrsDomainTransferred.join(', ') : 'none'} (I: a1950eb3ca95bdc9ec18a4b8823e9826)`);
1742
+ }
1743
+ // at this point, we have a list of ALL payload addrs retrieved.
1744
+ let allPayloadIbGibsDomainTransferred = [];
1745
+ if (allPayloadAddrsDomainTransferred.length > 0) {
1746
+ const resGetAllTransferred = await getFromSpace({ addrs: allPayloadAddrsDomainTransferred, space: localTempSpace });
1747
+ if (resGetAllTransferred.success && resGetAllTransferred.ibGibs && resGetAllTransferred.ibGibs.length === allPayloadAddrsDomainTransferred.length) {
1748
+ allPayloadIbGibsDomainTransferred = resGetAllTransferred.ibGibs.concat();
1749
+ }
1750
+ else {
1751
+ // errored out, gather info
1752
+ if (!resGetAllTransferred.rawResultIbGib) {
1753
+ throw new Error(`(UNEXPECTED) !resGetAllTransferred.rawResultIbGib falsy? (E: dc6cf8729668f4fbe8c024f887d97a26)`);
1754
+ }
1755
+ const { addrsNotFound, addrsErrored, errors } = resGetAllTransferred.rawResultIbGib.data;
1756
+ 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)`);
1757
+ }
1758
+ }
1759
+ // now we have all ibgibs transferred, first put them all the local space
1760
+ if (allPayloadIbGibsDomainTransferred.length === 0) {
1761
+ // nothing was synced
1762
+ if (logalot) {
1763
+ console.log(`${lc}[${currentFrameOrigin}] no changes on this end (I: fa30d18e83a87ee9e8487fbb5d632b26)`);
1764
+ }
1765
+ }
1766
+ else {
1767
+ if (logalot) {
1768
+ console.log(`${lc}[${currentFrameOrigin}] ${allPayloadIbGibsDomainTransferred.length} changes detected (I: fa30d18e83a87ee9e8487fbb5d632b26)`);
1769
+ }
1770
+ if (logalot) {
1771
+ console.log(`${lc} put all into localSpace (${localSpace.ib}) starting... (I: d5e0d9870e380b61e80c729660058826)`);
1772
+ }
1773
+ const { payload_Dnas, payload_NonDnas } = await putInSpace_dnasThenNonDnas({
1774
+ ibGibs: allPayloadIbGibsDomainTransferred,
1775
+ space: localSpace
1776
+ });
1777
+ if (logalot) {
1778
+ console.log(`${lc} put all into localSpace (${localSpace.ib}) complete. (I: d5e0d9870e380b61e80c729660058826)`);
1779
+ }
1780
+ const { mapWithTjp_NoDna, mapWithTjp_YesDna, mapWithoutTjps } = splitPerTjpAndOrDna({ ibGibs: payload_NonDnas, filterPrimitives: true });
1781
+ // first register all non-tjp stones
1782
+ if (logalot) {
1783
+ console.log(`${lc} register mapWithoutTjps starting... (I: 2b84d8f8dda85adde88696d8419bf726)`);
1784
+ }
1785
+ const nontjps = Object.values(mapWithoutTjps);
1786
+ for (const nontjp of nontjps) {
1787
+ if (logalot) {
1788
+ console.log(`${lc} registering ${getIbGibAddr({ ibGib: nontjp })} (I: 4647b4f42d27cffe0fbfce8846755826)`);
1789
+ }
1790
+ await metaspace.registerNewIbGib({
1791
+ ibGib: nontjp,
1792
+ space: localSpace,
1793
+ });
1794
+ }
1795
+ if (logalot) {
1796
+ console.log(`${lc} mapWithoutTjps complete. (I: 2b84d8f8dda85adde88696d8419bf726)`);
1797
+ }
1798
+ // next register each timeline in order...
1799
+ // ...first the ones without dna...
1800
+ if (logalot) {
1801
+ console.log(`${lc} register mapWithTjp_NoDna starting... (I: 96e648e4db382499b8bfaa1b37c24826)`);
1802
+ }
1803
+ const timelinesByTjpAddr_NoDna = getTimelinesGroupedByTjp({ ibGibs: Object.values(mapWithTjp_NoDna) });
1804
+ const tjpAddrs_NoDna = Object.keys(timelinesByTjpAddr_NoDna);
1805
+ for (const tjpAddr_NoDna of tjpAddrs_NoDna) {
1806
+ const timelineIbGibs = timelinesByTjpAddr_NoDna[tjpAddr_NoDna];
1807
+ for (const ibGib of timelineIbGibs) {
1808
+ await metaspace.registerNewIbGib({
1809
+ ibGib,
1810
+ space: localSpace,
1811
+ });
1812
+ }
1813
+ }
1814
+ if (logalot) {
1815
+ console.log(`${lc} register mapWithTjp_NoDna complete. (I: 96e648e4db382499b8bfaa1b37c24826)`);
1816
+ }
1817
+ // ...then the ones WITH dna.
1818
+ if (logalot) {
1819
+ console.log(`${lc} register mapWithTjp_YesDna starting... (I: d54a820e9442dee4681f6228a6795926)`);
1820
+ }
1821
+ const timelinesByTjpAddr_YesDna = getTimelinesGroupedByTjp({ ibGibs: Object.values(mapWithTjp_YesDna) });
1822
+ const tjpAddrs_YesDna = Object.keys(timelinesByTjpAddr_YesDna);
1823
+ for (const tjpAddr_YesDna of tjpAddrs_YesDna) {
1824
+ const timelineIbGibs = timelinesByTjpAddr_YesDna[tjpAddr_YesDna];
1825
+ for (const ibGib of timelineIbGibs) {
1826
+ await metaspace.registerNewIbGib({
1827
+ ibGib,
1828
+ space: localSpace,
1829
+ });
1830
+ }
1831
+ }
1832
+ if (logalot) {
1833
+ console.log(`${lc} register mapWithTjp_YesDna complete. (I: d54a820e9442dee4681f6228a6795926)`);
1834
+ }
1679
1835
  }
1680
- return { responseWasNull: true };
1681
1836
  }
1682
1837
  catch (error) {
1683
1838
  console.error(`${lc} ${extractErrorMsg(error)}`);
@@ -1689,6 +1844,124 @@ export class SyncSagaCoordinator {
1689
1844
  }
1690
1845
  }
1691
1846
  }
1847
+ async createCommitFrame({ sagaIbGib, errors, metaspace, mySpace, identity, }) {
1848
+ const lc = `[${this.createCommitFrame.name}]`;
1849
+ try {
1850
+ if (logalot) {
1851
+ console.log(`${lc} starting... (I: 48fc57c023f80122135a284855757526)`);
1852
+ }
1853
+ const commitData = errors && errors.length > 0 ?
1854
+ {
1855
+ // errored
1856
+ sagaId: sagaIbGib.data.uuid,
1857
+ stage: SyncStage.commit,
1858
+ success: false,
1859
+ errors,
1860
+ } :
1861
+ {
1862
+ // not errored
1863
+ sagaId: sagaIbGib.data.uuid,
1864
+ stage: SyncStage.commit,
1865
+ success: true,
1866
+ };
1867
+ const commitStone = await this.createSyncMsgStone({
1868
+ data: commitData,
1869
+ localSpace: mySpace,
1870
+ metaspace
1871
+ });
1872
+ const commitFrame = await this.evolveSyncSagaIbGib({
1873
+ prevSagaIbGib: sagaIbGib,
1874
+ msgStones: [commitStone],
1875
+ sessionIdentity: identity,
1876
+ localSpace: mySpace,
1877
+ metaspace,
1878
+ });
1879
+ return commitFrame;
1880
+ }
1881
+ catch (error) {
1882
+ console.error(`${lc} ${extractErrorMsg(error)}`);
1883
+ throw error;
1884
+ }
1885
+ finally {
1886
+ if (logalot) {
1887
+ console.log(`${lc} complete.`);
1888
+ }
1889
+ }
1890
+ }
1891
+ async handleCommitFrame({ sagaIbGib, mySpace, myTempSpace, metaspace, identity, }) {
1892
+ const lc = `${this.lc}[${this.handleCommitFrame.name}]`;
1893
+ try {
1894
+ if (logalot) {
1895
+ console.log(`${lc} starting... (I: e179573bdd881202f8ba3168da1c3826)`);
1896
+ }
1897
+ if (!sagaIbGib.data) {
1898
+ throw new Error(`(UNEXPECTED) sagaIbGib.data falsy? (E: cbc31dbb7d28b5b8c8cddb510d7d2826)`);
1899
+ }
1900
+ if (sagaIbGib.data.errors && sagaIbGib.data.errors.length > 0) {
1901
+ // our saga errored out but we already committed the darn
1902
+ // changes previously
1903
+ 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)`);
1904
+ }
1905
+ else {
1906
+ // Sender Logic (Finalizing):
1907
+ // If we are here, we received a Commit frame from the Peer.
1908
+ // This implies the Peer has successfully committed.
1909
+ // We should now:
1910
+ // 1. Validate (implicitly done by receiving valid frame)
1911
+ // 2. Perform our own cleanup (Temp -> Dest, if applicable)
1912
+ // 3. Return saga completion.
1913
+ // one last validate entire history ?
1914
+ const history = await getFullSyncSagaHistory({
1915
+ sagaIbGib,
1916
+ space: mySpace,
1917
+ });
1918
+ const validationErrors = await validateFullSyncSagaHistory({
1919
+ history,
1920
+ });
1921
+ if (validationErrors.length > 0) {
1922
+ const errorCommitFrame = await this.createCommitFrame({
1923
+ sagaIbGib,
1924
+ metaspace,
1925
+ mySpace,
1926
+ identity,
1927
+ errors: validationErrors,
1928
+ });
1929
+ return { frame: errorCommitFrame, }; /* <<<< returns early */
1930
+ }
1931
+ await this.executeLocalCommit({
1932
+ commitFrame: sagaIbGib,
1933
+ sagaHistory: history,
1934
+ localSpace: mySpace,
1935
+ localTempSpace: myTempSpace,
1936
+ metaspace,
1937
+ });
1938
+ // todo: implement explicit cleanup logic here and in peer
1939
+ console.error(`${lc} NAG ERROR (NOT THROWN): implement cleanup logic, including add a cleanup method to the peer (E: 3a9a24befb98a981a88fbdbf52920e26)`);
1940
+ if (logalot) {
1941
+ console.log(`${lc} Peer committed. Finalizing saga locally. Saga Complete.`);
1942
+ }
1943
+ // the holy grail!
1944
+ return { sagaComplete: true };
1945
+ }
1946
+ }
1947
+ catch (error) {
1948
+ const emsg = `${lc} ${extractErrorMsg(error)}`;
1949
+ console.error(emsg);
1950
+ const errorCommitFrame = await this.createCommitFrame({
1951
+ sagaIbGib,
1952
+ errors: [emsg],
1953
+ metaspace,
1954
+ mySpace,
1955
+ identity,
1956
+ });
1957
+ return { frame: errorCommitFrame };
1958
+ }
1959
+ finally {
1960
+ if (logalot) {
1961
+ console.log(`${lc} complete.`);
1962
+ }
1963
+ }
1964
+ }
1692
1965
  // #endregion Handlers
1693
1966
  async createSyncMsgStone({ data, localSpace, metaspace, }) {
1694
1967
  const lc = `${this.lc}[${this.createSyncMsgStone.name}]`;
@@ -1720,6 +1993,69 @@ export class SyncSagaCoordinator {
1720
1993
  }
1721
1994
  }
1722
1995
  }
1996
+ async getPayloadsForRequestedInfos({ deltaRequestAddrInfos, mySpace, }) {
1997
+ const lc = `${this.lc}[${this.getPayloadsForRequestedInfos.name}]`;
1998
+ try {
1999
+ if (logalot) {
2000
+ console.log(`${lc} starting... (I: 4fe13d0d80050f20a8b74ba80cee5826)`);
2001
+ }
2002
+ /**
2003
+ * graph of ibgibs we will send to the receiver. addr-based, so will
2004
+ * already be unique (no need to call `unique` on the domains
2005
+ * ibgibs)
2006
+ */
2007
+ const outgoingPayloadIbGibsDomainGraph = {};
2008
+ for (const { addr, latestAddrAlreadyHave } of deltaRequestAddrInfos) {
2009
+ let deltaDepGraph;
2010
+ if (latestAddrAlreadyHave) {
2011
+ // already has some, so only get the delta
2012
+ // remember: if we didn't have the other's latest addr, then
2013
+ // this would be in the conflicts not requested addrs
2014
+ deltaDepGraph = await getDeltaDependencyGraph({
2015
+ ibGibAddr: addr,
2016
+ latestCommonFrameAddr: latestAddrAlreadyHave,
2017
+ space: mySpace,
2018
+ live: true,
2019
+ });
2020
+ }
2021
+ else {
2022
+ // doesn't have anything, so get the entire dependency graph
2023
+ // INEFFICIENT: we've already gotten all of the domain
2024
+ // dependencies in initDomainGraph, but getDependencyGraph
2025
+ // only works against a space so we are going to rerun this.
2026
+ // an optimization would be to adapt/create a new
2027
+ // getDependencyGraph to work against an existing flat ibgib
2028
+ // map.
2029
+ deltaDepGraph = await getDependencyGraph({
2030
+ ibGibAddr: addr,
2031
+ space: mySpace,
2032
+ live: true,
2033
+ });
2034
+ }
2035
+ const depGraphSize = Object.keys(deltaDepGraph).length;
2036
+ if (depGraphSize === 0) {
2037
+ throw new Error(`(UNEXPECTED) couldn't get requested addrs in mySpace (${mySpace.ib})? How did the receiver know to ask for these addrs if they weren't in our original graph? (E: 281eaebcdf77dd73e8245b2872100826)`);
2038
+ }
2039
+ else {
2040
+ // we have dependencies!
2041
+ Object.values(deltaDepGraph).forEach(x => {
2042
+ outgoingPayloadIbGibsDomainGraph[getIbGibAddr({ ibGib: x })] = x;
2043
+ });
2044
+ }
2045
+ }
2046
+ const result = Object.values(outgoingPayloadIbGibsDomainGraph);
2047
+ return result;
2048
+ }
2049
+ catch (error) {
2050
+ console.error(`${lc} ${extractErrorMsg(error)}`);
2051
+ throw error;
2052
+ }
2053
+ finally {
2054
+ if (logalot) {
2055
+ console.log(`${lc} complete.`);
2056
+ }
2057
+ }
2058
+ }
1723
2059
  /**
1724
2060
  * Evolves the saga timeline with a new frame.
1725
2061
  */