@ibgib/core-gib 0.1.21 → 0.1.22

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 (113) hide show
  1. package/dist/sync/sync-conflict.respec.mjs +24 -22
  2. package/dist/sync/sync-conflict.respec.mjs.map +1 -1
  3. package/dist/sync/sync-constants.d.mts +8 -8
  4. package/dist/sync/sync-constants.d.mts.map +1 -1
  5. package/dist/sync/sync-constants.mjs +3 -3
  6. package/dist/sync/sync-constants.mjs.map +1 -1
  7. package/dist/sync/sync-helpers.d.mts +2 -0
  8. package/dist/sync/sync-helpers.d.mts.map +1 -1
  9. package/dist/sync/sync-helpers.mjs +11 -9
  10. package/dist/sync/sync-helpers.mjs.map +1 -1
  11. package/dist/sync/sync-innerspace-constants.respec.mjs +5 -1
  12. package/dist/sync/sync-innerspace-constants.respec.mjs.map +1 -1
  13. package/dist/sync/sync-innerspace-deep-updates.respec.mjs +5 -1
  14. package/dist/sync/sync-innerspace-deep-updates.respec.mjs.map +1 -1
  15. package/dist/sync/sync-innerspace-dest-ahead.respec.mjs +8 -4
  16. package/dist/sync/sync-innerspace-dest-ahead.respec.mjs.map +1 -1
  17. package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs +5 -1
  18. package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs.map +1 -1
  19. package/dist/sync/sync-innerspace-partial-update.respec.mjs +5 -1
  20. package/dist/sync/sync-innerspace-partial-update.respec.mjs.map +1 -1
  21. package/dist/sync/sync-innerspace.respec.mjs +5 -1
  22. package/dist/sync/sync-innerspace.respec.mjs.map +1 -1
  23. package/dist/sync/sync-peer/sync-peer-constants.d.mts +2 -0
  24. package/dist/sync/sync-peer/sync-peer-constants.d.mts.map +1 -0
  25. package/dist/sync/sync-peer/sync-peer-constants.mjs +2 -0
  26. package/dist/sync/sync-peer/sync-peer-constants.mjs.map +1 -0
  27. package/dist/sync/sync-peer/sync-peer-helpers.d.mts +2 -0
  28. package/dist/sync/sync-peer/sync-peer-helpers.d.mts.map +1 -0
  29. package/dist/sync/sync-peer/sync-peer-helpers.mjs +2 -0
  30. package/dist/sync/sync-peer/sync-peer-helpers.mjs.map +1 -0
  31. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.d.mts +8 -0
  32. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.d.mts.map +1 -0
  33. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mjs +8 -0
  34. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mjs.map +1 -0
  35. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-helpers.d.mts +18 -0
  36. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-helpers.d.mts.map +1 -0
  37. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-helpers.mjs +54 -0
  38. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-helpers.mjs.map +1 -0
  39. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-types.d.mts +80 -0
  40. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-types.d.mts.map +1 -0
  41. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-types.mjs +5 -0
  42. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-types.mjs.map +1 -0
  43. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts +43 -0
  44. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts.map +1 -0
  45. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs +229 -0
  46. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs.map +1 -0
  47. package/dist/sync/sync-peer/sync-peer-types.d.mts +12 -0
  48. package/dist/sync/sync-peer/sync-peer-types.d.mts.map +1 -1
  49. package/dist/sync/sync-peer/sync-peer-v1.d.mts +15 -7
  50. package/dist/sync/sync-peer/sync-peer-v1.d.mts.map +1 -1
  51. package/dist/sync/sync-peer/sync-peer-v1.mjs +105 -24
  52. package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
  53. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts +5 -8
  54. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts.map +1 -1
  55. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs +34 -18
  56. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs.map +1 -1
  57. package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts +26 -22
  58. package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts.map +1 -1
  59. package/dist/sync/sync-saga-context/sync-saga-context-types.mjs +1 -9
  60. package/dist/sync/sync-saga-context/sync-saga-context-types.mjs.map +1 -1
  61. package/dist/sync/sync-saga-coordinator.d.mts +23 -33
  62. package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
  63. package/dist/sync/sync-saga-coordinator.mjs +271 -163
  64. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  65. package/dist/sync/sync-types.d.mts +15 -3
  66. package/dist/sync/sync-types.d.mts.map +1 -1
  67. package/dist/witness/light-witness-base-v1.d.mts.map +1 -1
  68. package/dist/witness/light-witness-base-v1.mjs +2 -0
  69. package/dist/witness/light-witness-base-v1.mjs.map +1 -1
  70. package/dist/witness/space/inner-space/inner-space-v1.mjs +1 -1
  71. package/dist/witness/space/inner-space/inner-space-v1.mjs.map +1 -1
  72. package/package.json +1 -1
  73. package/src/sync/README.md +31 -22
  74. package/src/sync/sync-conflict.respec.mts +23 -19
  75. package/src/sync/sync-constants.mts +4 -5
  76. package/src/sync/sync-helpers.mts +11 -7
  77. package/src/sync/sync-innerspace-constants.respec.mts +5 -1
  78. package/src/sync/sync-innerspace-deep-updates.respec.mts +5 -1
  79. package/src/sync/sync-innerspace-dest-ahead.respec.mts +7 -3
  80. package/src/sync/sync-innerspace-multiple-timelines.respec.mts +5 -1
  81. package/src/sync/sync-innerspace-partial-update.respec.mts +8 -2
  82. package/src/sync/sync-innerspace.respec.mts +5 -1
  83. package/src/sync/sync-peer/sync-peer-constants.mts +0 -0
  84. package/src/sync/sync-peer/sync-peer-helpers.mts +0 -0
  85. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mts +8 -0
  86. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-helpers.mts +72 -0
  87. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-types.mts +87 -0
  88. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mts +242 -0
  89. package/src/sync/sync-peer/sync-peer-types.mts +13 -1
  90. package/src/sync/sync-peer/sync-peer-v1.mts +93 -27
  91. package/src/sync/sync-saga-context/sync-saga-context-helpers.mts +47 -29
  92. package/src/sync/sync-saga-context/sync-saga-context-types.mts +29 -30
  93. package/src/sync/sync-saga-coordinator.mts +280 -170
  94. package/src/sync/sync-types.mts +17 -3
  95. package/src/witness/light-witness-base-v1.mts +2 -1
  96. package/src/witness/space/inner-space/inner-space-v1.mts +1 -1
  97. package/test_output.log +0 -0
  98. package/tmp.md +62 -44
  99. package/dist/sync/sync-local-spaces.respec.d.mts +0 -2
  100. package/dist/sync/sync-local-spaces.respec.d.mts.map +0 -1
  101. package/dist/sync/sync-local-spaces.respec.mjs +0 -159
  102. package/dist/sync/sync-local-spaces.respec.mjs.map +0 -1
  103. package/dist/sync/sync-peer/sync-peer-innerspace-v1.d.mts +0 -42
  104. package/dist/sync/sync-peer/sync-peer-innerspace-v1.d.mts.map +0 -1
  105. package/dist/sync/sync-peer/sync-peer-innerspace-v1.mjs +0 -194
  106. package/dist/sync/sync-peer/sync-peer-innerspace-v1.mjs.map +0 -1
  107. package/dist/sync/sync-saga-coordinator.respec.d.mts +0 -2
  108. package/dist/sync/sync-saga-coordinator.respec.d.mts.map +0 -1
  109. package/dist/sync/sync-saga-coordinator.respec.mjs +0 -40
  110. package/dist/sync/sync-saga-coordinator.respec.mjs.map +0 -1
  111. package/src/sync/sync-local-spaces.respec.mts +0 -200
  112. package/src/sync/sync-peer/sync-peer-innerspace-v1.mts +0 -240
  113. package/src/sync/sync-saga-coordinator.respec.mts +0 -52
@@ -4,10 +4,11 @@ import {
4
4
  getTimestamp, // so our timestamp strings are uniform
5
5
  getTimestampInTicks, // so our timestamp in ticks as a string are uniform
6
6
  pretty,
7
- clone
7
+ clone,
8
+ unique,
8
9
  } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
9
10
  import { getIbGibAddr } from "@ibgib/ts-gib/dist/helper.mjs";
10
- import { splitPerTjpAndOrDna, getTimelinesGroupedByTjp } from "../common/other/ibgib-helper.mjs";
11
+ import { splitPerTjpAndOrDna, getTimelinesGroupedByTjp, isIbGib } from "../common/other/ibgib-helper.mjs";
11
12
  import { Factory_V1 } from "@ibgib/ts-gib/dist/V1/factory.mjs";
12
13
  import { IbGib_V1, IbGibRel8ns_V1 } from "@ibgib/ts-gib/dist/V1/types.mjs";
13
14
  import { isPrimitive } from "@ibgib/ts-gib/dist/V1/transforms/transform-helper.mjs";
@@ -18,7 +19,7 @@ import { putInSpace, getLatestAddrs, getFromSpace } from "../witness/space/space
18
19
  import { KeystoneIbGib_V1 } from "../keystone/keystone-types.mjs";
19
20
  import { KeystoneService_V1 } from "../keystone/keystone-service-v1.mjs";
20
21
  import { MetaspaceService } from "../witness/space/metaspace/metaspace-types.mjs";
21
- import { SyncStage, SYNC_ATOM, SYNC_MSG_REL8N_NAME } from "./sync-constants.mjs";
22
+ import { SyncStage, SYNC_ATOM, SYNC_MSG_REL8N_NAME, SYNC_SAGA_PAYLOAD_ADDRS_DOMAIN } from "./sync-constants.mjs";
22
23
  import { appendToTimeline, createTimeline, Rel8nInfo, Rel8nRemovalInfo } from "../timeline/timeline-api.mjs";
23
24
  import {
24
25
  SyncData_V1, SyncIbGib_V1, SyncInitData, SyncConflictStrategy,
@@ -26,7 +27,7 @@ import {
26
27
  SyncOptions,
27
28
  } from "./sync-types.mjs";
28
29
  import { getSyncIb, isPastFrame } from "./sync-helpers.mjs";
29
- import { getSyncSagaDependencyGraph } from "./sync-helpers.mjs";
30
+ import { getSyncSagaDependencyGraph as getSyncSagaDependencyGraphForThisFrameOnly } from "./sync-helpers.mjs";
30
31
  import { getDependencyGraph } from "../common/other/graph-helper.mjs";
31
32
  import {
32
33
  SyncSagaMessageData_V1, SyncSagaMessageInitData_V1,
@@ -37,16 +38,33 @@ import { getSyncSagaMessageIb } from "./sync-saga-message/sync-saga-message-help
37
38
  import { SYNC_SAGA_MSG_ATOM } from "./sync-saga-message/sync-saga-message-constants.mjs";
38
39
  import { SyncSagaInfo } from "./sync-types.mjs";
39
40
  import { SyncPeerWitness } from "./sync-peer/sync-peer-types.mjs";
40
- import { SyncSagaContextIbGib_V1, SyncSagaContextCmd } from "./sync-saga-context/sync-saga-context-types.mjs";
41
+ import { SyncSagaContextIbGib_V1, } from "./sync-saga-context/sync-saga-context-types.mjs";
41
42
  import { createSyncSagaContext } from "./sync-saga-context/sync-saga-context-helpers.mjs";
42
- import { newupSubject } from "../common/pubsub/subject/subject-helper.mjs";
43
+ import { newupSubject, } from "../common/pubsub/subject/subject-helper.mjs";
43
44
  import { SubjectWitness } from "../common/pubsub/subject/subject-types.mjs";
44
45
 
45
46
  import { mergeDivergentTimelines } from "./strategies/conflict-optimistic.mjs";
46
47
  import { getSyncSagaMessageFromFrame } from "./sync-saga-message/sync-saga-message-helpers.mjs";
48
+ import { fnObs } from "../common/pubsub/observer/observer-helper.mjs";
49
+ import { SubscriptionWitness } from "../common/pubsub/subscription/subscription-types.mjs";
50
+ import { ErrorIbGib_V1 } from "../common/error/error-types.mjs";
51
+ import { SyncPeerInnerspace_V1 } from "./sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs";
47
52
 
48
53
 
49
- const logalot = GLOBAL_LOG_A_LOT || true;
54
+ // const logalot = GLOBAL_LOG_A_LOT || true;
55
+ const logalot = false;
56
+ const logalotControlDomain = true;
57
+ const lcControlDomain = '[ControlDomain]';
58
+
59
+ /**
60
+ * Result of handling a saga frame.
61
+ * Separates control and domain payloads.
62
+ */
63
+ export interface HandleSagaFrameResult {
64
+ frame: SyncIbGib_V1;
65
+ payloadIbGibsControl?: IbGib_V1[];
66
+ payloadIbGibsDomain?: IbGib_V1[];
67
+ }
50
68
 
51
69
  /**
52
70
  * Orchestrates the synchronization process between two spaces (Source and Destination).
@@ -157,6 +175,13 @@ export class SyncSagaCoordinator {
157
175
  });
158
176
 
159
177
  // 4. EXECUTE SAGA LOOP (FSM)
178
+ // Inject tempSpace into peer so it can pull control payloads to the right place
179
+ // if ('opts' in peer && peer.opts) {
180
+ if (!peer.data) { throw new Error(`(UNEXPECTED) peer.data falsy? (E: 8546a884c82ffb1999e95d9867da2826)`); }
181
+ if (peer.data.classname === SyncPeerInnerspace_V1.name) {
182
+ // (peer as SyncPeerInnerspace_V1).senderTempSpace = tempSpace;
183
+ }
184
+
160
185
  const syncedIbGibs = await this.executeSagaLoop({
161
186
  initialFrame: initFrame,
162
187
  srcGraph,
@@ -260,7 +285,6 @@ export class SyncSagaCoordinator {
260
285
  srcGraph: { [addr: string]: IbGib_V1 },
261
286
  peer: SyncPeerWitness,
262
287
  sessionIdentity?: KeystoneIbGib_V1,
263
- // updates$: Subject_V1<SyncSagaContextIbGib_V1>,
264
288
  updates$: SubjectWitness<SyncSagaContextIbGib_V1>,
265
289
  localSpace: IbGibSpaceAny,
266
290
  tempSpace: IbGibSpaceAny,
@@ -271,144 +295,213 @@ export class SyncSagaCoordinator {
271
295
  // The current frame we just generated (e.g., Init or Delta Request)
272
296
  let currentFrame: SyncIbGib_V1 | null = initialFrame;
273
297
  // The payload we need to attach to the message (data we are sending)
274
- let nextPayloadIbGibs: IbGib_V1[] = [];
298
+ let nextDomainIbGibs: IbGib_V1[] = [];
275
299
  // Accumulator for all data we've successfully pulled from the remote
276
300
  const allReceivedIbGibs: IbGib_V1[] = [];
277
301
 
278
302
  while (currentFrame) {
279
303
  // A. Create Context (Request)
280
304
  // 1. Calculate Full Dependency Graph (including Ancestors/DNA)
281
- // We must do this BEFORE creating the Context so we can list them all in payloadAddrs.
282
- const allDeps: IbGib_V1[] = [];
305
+ // TODO: adjust this algorithm to only do the dependencies that the other end doesn't need (diff between tip and LCA)
306
+ // We must do this BEFORE creating the Context so we can list them
307
+ // all in payloadAddrsDomain and payloadAddrsControl.
308
+ // const depsDomainIbGibs: IbGib_V1[] = [];
309
+ // const depsControlIbGibs: IbGib_V1[] = [];
310
+ const payloadIbGibsControl: IbGib_V1[] = [];
311
+ const payloadIbGibsDomain: IbGib_V1[] = [];
283
312
 
284
313
  // A. Payload (Standard Deep Deps)
285
- for (const item of nextPayloadIbGibs) {
286
- let graph = await getDependencyGraph({ ibGib: item, space: localSpace });
287
- if (!graph) {
288
- graph = await getDependencyGraph({ ibGib: item, space: tempSpace });
314
+ for (const nextDomainIbGib of nextDomainIbGibs) {
315
+ let nextDomainIbGibGraph = await getDependencyGraph({ ibGib: nextDomainIbGib, space: localSpace });
316
+ if (!nextDomainIbGibGraph) {
317
+ nextDomainIbGibGraph = await getDependencyGraph({ ibGib: nextDomainIbGib, space: tempSpace });
289
318
  }
290
319
 
291
- if (graph) {
292
- allDeps.push(...Object.values(graph));
320
+ if (nextDomainIbGibGraph) {
321
+ payloadIbGibsDomain.push(...Object.values(nextDomainIbGibGraph));
293
322
  } else {
294
- allDeps.push(item);
323
+ throw new Error(`(UNEXPECTED) we couldn't get the graph for a known domain ibgib? nextDomainIbGib addr: ${getIbGibAddr({ ibGib: nextDomainIbGib })} (E: 01b3e4db8768b5b77db72e486f4f7826)`);
295
324
  }
296
325
  }
297
- if (logalot) {
298
- // console.log(`${lc} allDeps count: ${allDeps.length}`);
299
- }
326
+ if (logalot) { console.log(`${lc} payloadIbGibsDomain count: ${payloadIbGibsDomain.length} (I: 2beda8ca7dc5ac0f48ed9e25e704b826)`); }
300
327
 
301
328
  // B. Frames (Shallow Sync Deps)
302
329
  if (currentFrame) {
303
- const deps = await getSyncSagaDependencyGraph({ ibGib: currentFrame, space: tempSpace });
304
- if (deps) allDeps.push(...deps);
330
+ const depsCurrentFrame = await getSyncSagaDependencyGraphForThisFrameOnly({ ibGib: currentFrame, space: tempSpace });
331
+ if (depsCurrentFrame.length > 0) {
332
+ depsCurrentFrame.forEach(x => payloadIbGibsControl.push(x));
333
+ } else {
334
+ throw new Error(`(UNEXPECTED) couldn't get deps for currentFrame? currentFrame: ${JSON.stringify(currentFrame)} (E: 06344d07adc80d80b809211171444d26)`);
335
+ }
305
336
  }
306
337
 
307
338
  // 2. Create Context (Envelope)
308
- // Use the FULL dependency list as the payload manifest
309
- const payloadAddrs = allDeps.map(p => getIbGibAddr({ ibGib: p }));
339
+ const domainPayloadsMap = new Map<string, IbGib_V1>();
340
+ const sublc = `${lc}[peer.payloadIbGibsDomainReceived$]`;
341
+ let subscription: SubscriptionWitness;
342
+ if (peer && peer.payloadIbGibsDomainReceived$) {
343
+ // Subscribe to stream
344
+ subscription = await peer.payloadIbGibsDomainReceived$.subscribe(fnObs({
345
+ next: async (ibgib: IbGib_V1) => {
346
+ if (logalot) { console.log(`${sublc} next fired. (I: 2b4bdf502a38a90ba33d9711e7cb7826)`); }
347
+ const addr = getIbGibAddr({ ibGib: ibgib });
348
+ if (logalotControlDomain) { console.log(`${lc}${lcControlDomain} DOMAIN STREAM RECEIVED <- observable: ${addr} (I: d69ee80fcaece272483ec33b2d289826)`); }
349
+ domainPayloadsMap.set(addr, ibgib);
350
+ },
351
+ error: async (e: string | Error | ErrorIbGib_V1) => {
352
+ if (isIbGib(e)) {
353
+ console.error(`${sublc} error fired. error: ${JSON.stringify((e as IbGib_V1).data)} (E: 01cc08ba05ad99682831174fd7c31a26)`);
354
+ } else {
355
+ console.dir(e);
356
+ console.error(`${sublc} error fired. error: ${extractErrorMsg(e)} (E: 73d3d61464e8e4ce4cd6efd8b9675826)`);
357
+ }
358
+ },
359
+ complete: async () => {
360
+ if (logalot) { console.log(`${sublc} complete fired. (I: a47218aa9e4433fdb97c068880a45826)`); }
361
+ await subscription.unsubscribe();
362
+ },
363
+ }));
364
+ }
310
365
 
366
+ // 2b. Request Context
311
367
  const requestCtx = await createSyncSagaContext({
312
- cmd: SyncSagaContextCmd.process,
313
368
  sagaFrame: currentFrame,
314
369
  sessionKeystones: sessionIdentity ? [sessionIdentity] : undefined,
315
- payloadAddrs: payloadAddrs.length > 0 ? payloadAddrs : undefined,
370
+ payloadIbGibsDomain,
316
371
  });
317
372
 
318
- // Add Context Deps
319
- if (requestCtx) {
320
- const deps = await getSyncSagaDependencyGraph({ ibGib: requestCtx, space: tempSpace });
321
- if (deps) allDeps.push(...deps);
373
+ // Log what we're sending
374
+ if (logalotControlDomain) {
375
+ const controlAddrs = payloadIbGibsControl.map(p => getIbGibAddr({ ibGib: p }));
376
+ const domainAddrs = payloadIbGibsDomain.map(p => getIbGibAddr({ ibGib: p }));
377
+ console.log(`${lc}${lcControlDomain} SENDER TRANSMIT -> peer.witness (I: b3c4d5e6f7a8b9c0)`);
378
+ console.log(`${lc}${lcControlDomain} Context: ${getIbGibAddr({ ibGib: requestCtx })}`);
379
+ console.log(`${lc}${lcControlDomain} Frame: ${getIbGibAddr({ ibGib: currentFrame })}`);
380
+ console.log(`${lc}${lcControlDomain} CONTROL Payloads (${controlAddrs.length}): ${controlAddrs.join(', ') || '(none)'}`);
381
+ console.log(`${lc}${lcControlDomain} DOMAIN Payloads (${domainAddrs.length}): ${domainAddrs.join(', ') || '(none)'}`);
322
382
  }
323
383
 
384
+ // Add Context Deps
385
+ // do we need to add requestCtx to the payload ibgibs?
386
+ // if (requestCtx) {
387
+ // const deps = await getSyncSagaDependencyGraphForThisFrameOnly({ ibGib: requestCtx, space: tempSpace });
388
+ // if (deps) { deps.forEach(x => payloadIbGibsControl.push(x)); }
389
+ // }
390
+
324
391
  // 3. Identity (if exists)
325
392
  // Identity might be deep? Keystone? Usually self-contained or shallow references.
326
393
  if (sessionIdentity) {
327
- allDeps.push(sessionIdentity);
394
+ payloadIbGibsControl.push(sessionIdentity);
328
395
  }
329
396
 
330
- if (allDeps.length > 0) {
331
- await putInSpace({
332
- space: localSpace,
333
- ibGibs: allDeps
334
- });
397
+ // we only put the **CONTROL** payload ibgibs in localSpace. we
398
+ // don't put any domain ibgibs into this durable space until the
399
+ // final commit phase.
400
+ // The requestCtx envelope itself also goes to localSpace so transfer can find it.
401
+ await putInSpace({ space: localSpace, ibGib: requestCtx });
402
+ if (payloadIbGibsControl.length > 0) {
403
+ await putInSpace({ space: localSpace, ibGibs: payloadIbGibsControl });
335
404
  }
336
405
 
337
406
  // B. Transmit
338
407
  // if (logalot) { console.log(`${lc} transmitting... requestCtx: ${pretty(requestCtx)} (I: 8cf20817c66899abdb1e76df50356826)`); }
339
- updates$.next(requestCtx);
408
+ updates$.next(requestCtx); // spins off (don't remove this comment!)
409
+
340
410
  const responseCtx = await peer.witness(requestCtx);
341
411
 
342
412
  // C. Handle Response
343
413
  if (!responseCtx) {
344
- // Check if we just sent a Commit frame. If so, peer's silence is success/expected.
345
414
  if (currentFrame) {
415
+ // Check for Commit (Peer silence expected)
346
416
  const msg = await getSyncSagaMessageFromFrame({ frameIbGib: currentFrame, space: localSpace });
347
- if (logalot) { console.log(`${lc} Checking currentFrame stage: ${msg?.data?.stage} (Expected: ${SyncStage.commit})`); }
348
417
  if (msg?.data?.stage === SyncStage.commit) {
349
418
  if (logalot) { console.log(`${lc} Sender sent Commit. Peer returned no response. Saga Complete.`); }
350
419
  currentFrame = null;
351
420
  break;
421
+ } else {
422
+ throw new Error(`(UNEXPECTED) responseCtx falsy and currentFrame truthy, but we're not in the commit stage? This may be expected ultimately, but atow I am not seeing this as being expected. (E: cc34498962bd370deeff351fac939f26)`);
352
423
  }
424
+ } else {
425
+ throw new Error(`(UNEXPECTED) no response and currentFrame falsy? (E: 8d1085ea2f28cfc3f9c922649864a826)`);
353
426
  }
354
-
355
- throw new Error(`responseCtx falsy. Peer returned no response context (E: c099d8073b48d85e881f917835158f26)`);
356
- // console.warn(`${lc} Peer returned no response context. Ending loop.`);
357
- // currentFrame = null;
358
- // break;
359
427
  }
360
428
 
361
- if (logalot) {
362
- console.log(`${lc} received responseCtx: ${pretty(responseCtx)} (I: 8f35c8b7a9e886aa9743d38bee907826)`);
363
- }
429
+ // ---------------------------------------------------------------------
430
+ // 2d. HANDLE RESPONSE
431
+ // ---------------------------------------------------------------------
432
+ if (!responseCtx.data) { throw new Error(`(UNEXPECTED) responseCtx.data falsy? (E: a969992bae53ab18a827ec58aec15826)`); }
433
+ updates$.next(responseCtx); // spins off -- don't remove this comment!
364
434
 
365
- updates$.next(responseCtx);
435
+ // Extract expected domain addresses from response context
436
+ const responsePayloadAddrsDomain = responseCtx.data[SYNC_SAGA_PAYLOAD_ADDRS_DOMAIN] as string[] || [];
366
437
 
367
- // D. Extract Remote Frame & React
368
- const remoteFrameAddr = responseCtx.rel8ns?.sagaFrame?.[0];
369
- if (!remoteFrameAddr) {
370
- // If the remote didn't send a saga frame, we can't continue the protocol.
371
- throw new Error(`${lc} Peer response has no sagaFrame. Ending loop. (E: 0224e84a83e1c7ee288aaed6bdc40826)`);
438
+ // TODO: check if we are validating the responseCtx in sync peer. I'm thinking that we must, because we can't start the domain ibgibs until we know the response's control ibgibs are valid.
439
+
440
+ // Poll for them if needed
441
+ if (responsePayloadAddrsDomain.length > 0) {
442
+ await this.pollForDomainPayloads({
443
+ expectedAddrs: responsePayloadAddrsDomain,
444
+ domainPayloadsMap,
445
+ tempSpace,
446
+ });
372
447
  }
373
448
 
374
- // We look in localSpace first (where Peer delivers), then tempSpace.
375
- let resRemoteFrame = await getFromSpace({ addr: remoteFrameAddr, space: localSpace });
376
- if (!resRemoteFrame.success || !resRemoteFrame.ibGibs?.length) {
377
- // Fallback to tempSpace just in case
378
- resRemoteFrame = await getFromSpace({ addr: remoteFrameAddr, space: tempSpace });
449
+ // Extract Response Frame
450
+ const responseFrameAddr = responseCtx.rel8ns?.sagaFrame?.[0];
451
+ if (!responseFrameAddr) { throw new Error(`${lc} Peer response missing sagaFrame (E: 83a0)`); }
452
+
453
+ // Log what we received back
454
+ if (logalotControlDomain) {
455
+ const responseControlAddrs = responseCtx.data?.['@payloadAddrsControl'] as string[] || [];
456
+ console.log(`${lc}${lcControlDomain} SENDER RECEIVED <- peer.witness (I: c4d5e6f7a8b9c0d1)`);
457
+ console.log(`${lc}${lcControlDomain} Response Context: ${getIbGibAddr({ ibGib: responseCtx })}`);
458
+ console.log(`${lc}${lcControlDomain} Response Frame: ${responseFrameAddr}`);
459
+ console.log(`${lc}${lcControlDomain} CONTROL Payloads (${responseControlAddrs.length}): ${responseControlAddrs.join(', ') || '(none)'}`);
460
+ console.log(`${lc}${lcControlDomain} DOMAIN Payloads (${responsePayloadAddrsDomain.length}): ${responsePayloadAddrsDomain.join(', ') || '(none)'}`);
379
461
  }
380
- const remoteFrame = resRemoteFrame.ibGibs?.[0];
381
462
 
382
- if (!remoteFrame) { throw new Error(`Could not resolve remote frame: ${remoteFrameAddr}`); }
383
- // if (logalot) { console.log(`${lc} remoteFrame: ${pretty(remoteFrame)}`); } // leave this in for later use if needed
463
+ // Get response frame from localSpace (SyncPeer puts it there)
464
+ let resResponseFrame = await getFromSpace({ space: localSpace, addr: responseFrameAddr });
465
+ if (!resResponseFrame.success || !resResponseFrame.ibGibs?.length) {
466
+ // Fallback to tempSpace
467
+ resResponseFrame = await getFromSpace({ space: tempSpace, addr: responseFrameAddr });
468
+ }
469
+ const responseFrame = resResponseFrame.ibGibs?.[0] as any;
470
+ if (!responseFrame) throw new Error(`${lc} Response frame not found (E: 7c2a)`);
471
+
472
+ // Handle Response Frame
473
+ const handleResult = await this.handleSagaFrame({
474
+ sagaIbGib: responseFrame,
475
+ srcGraph: {},
476
+ destSpace: localSpace,
477
+ tempSpace,
478
+ metaspace,
479
+ domainPayloadsMap,
480
+ expectedDomainAddrs: responsePayloadAddrsDomain,
481
+ });
384
482
 
385
- // Ensure remote frame and its dependencies are in tempSpace
386
- // The Peer delivered them to localSpace, but handleSagaFrame works in tempSpace.
387
- const remoteDeps = await getSyncSagaDependencyGraph({ ibGib: remoteFrame, space: localSpace });
388
- if (remoteDeps && remoteDeps.length > 0) {
389
- await putInSpace({ space: tempSpace, ibGibs: remoteDeps });
483
+ if (!handleResult) {
484
+ if (logalot) { console.log(`${lc} Handler returned null (Saga End).`); }
485
+ break;
390
486
  }
391
487
 
488
+ currentFrame = handleResult.frame;
392
489
 
393
- // React (Reducer)
394
- // This processes the FRAME we just got from the peer.
395
- // i.e., We Sent Init -> Got Ack. This calls handleAckFrame.
396
- // i.e., We Sent Delta -> Got Delta. This calls handleDeltaFrame.
397
- const result = await this.handleSagaFrame({
398
- sagaIbGib: remoteFrame as SyncIbGib_V1,
399
- srcGraph,
400
- destSpace: localSpace, // Query existing data from localSpace (Source)
401
- tempSpace: tempSpace, // Transaction space for saga frames
402
- identity: sessionIdentity,
403
- metaspace
404
- });
490
+ // Collect next DOMAIN payloads for the NEXT request
491
+ // Control payloads are handled separately by ensureSagaFrameInBothSpaces
492
+ nextDomainIbGibs = [...(handleResult.payloadIbGibsDomain || [])];
405
493
 
406
- currentFrame = result?.frame || null;
407
- nextPayloadIbGibs = result?.payloadIbGibs || []; // Payload to send in NEXT Ping
408
- if (result?.receivedPayloadIbGibs) {
409
- // Keep track of what we received for final merge
410
- allReceivedIbGibs.push(...result.receivedPayloadIbGibs);
494
+ // Log handler output for next iteration
495
+ if (logalotControlDomain) {
496
+ const handlerControlAddrs = (handleResult.payloadIbGibsControl || []).map(p => getIbGibAddr({ ibGib: p }));
497
+ const handlerDomainAddrs = nextDomainIbGibs.map(p => getIbGibAddr({ ibGib: p }));
498
+ console.log(`${lc}${lcControlDomain} HANDLER RESULT -> next iteration (I: d5e6f7a8b9c0d1e2)`);
499
+ console.log(`${lc}${lcControlDomain} Next Frame: ${getIbGibAddr({ ibGib: currentFrame })}`);
500
+ console.log(`${lc}${lcControlDomain} CONTROL for next (${handlerControlAddrs.length}): ${handlerControlAddrs.join(', ') || '(none)'} (saved via ensureSagaFrameInBothSpaces)`);
501
+ console.log(`${lc}${lcControlDomain} DOMAIN for next (${handlerDomainAddrs.length}): ${handlerDomainAddrs.join(', ') || '(none)'}`);
411
502
  }
503
+
504
+ // Note: currentFrame is automatically added to dependencies at start of next loop via B. Frames logic.
412
505
  }
413
506
 
414
507
  return allReceivedIbGibs;
@@ -432,7 +525,7 @@ export class SyncSagaCoordinator {
432
525
  const lc = `${this.lc}[${this.getKnowledgeVector.name}]`;
433
526
  try {
434
527
  if (logalot) { console.log(`${lc} starting... (I: e184f8a7818666febfbbd2d841ed3826)`); }
435
- console.dir(space)
528
+ // console.dir(space);
436
529
 
437
530
  if (!(domainIbGibs && domainIbGibs.length > 0) &&
438
531
  !(tjpAddrs && tjpAddrs.length > 0)
@@ -451,19 +544,19 @@ export class SyncSagaCoordinator {
451
544
  tjps = tjpAddrs;
452
545
  } else if (domainIbGibs && domainIbGibs.length > 0) {
453
546
  // Extract TJPs from domain Ibgibs
454
- if (logalot) { console.log(`${lc} domainIbGibs (${domainIbGibs.length}) provided. (I: a378995a0658af1f086ac1f297486c26)`); }
547
+ // if (false) { console.log(`${lc} domainIbGibs (${domainIbGibs.length}) provided. (I: a378995a0658af1f086ac1f297486c26)`); }
455
548
 
456
549
  const { mapWithTjp_YesDna, mapWithTjp_NoDna } =
457
550
  splitPerTjpAndOrDna({ ibGibs: domainIbGibs });
458
- if (logalot) { console.log(`${lc}[TEST DEBUG] mapWithTjp_YesDna: ${JSON.stringify(mapWithTjp_YesDna)} (I: 287e22897148298e185712c8d50cfb26)`); }
459
- if (logalot) { console.log(`${lc}[TEST DEBUG] mapWithTjp_NoDna: ${JSON.stringify(mapWithTjp_NoDna)} (I: 1bdc62656294aed0f9df334647dc7326)`); }
551
+ if (false) { console.log(`${lc}[TEST DEBUG] mapWithTjp_YesDna: ${JSON.stringify(mapWithTjp_YesDna)} (I: 287e22897148298e185712c8d50cfb26)`); }
552
+ if (false) { console.log(`${lc}[TEST DEBUG] mapWithTjp_NoDna: ${JSON.stringify(mapWithTjp_NoDna)} (I: 1bdc62656294aed0f9df334647dc7326)`); }
460
553
 
461
554
  const allWithTjp = [...Object.values(mapWithTjp_YesDna), ...Object.values(mapWithTjp_NoDna)];
462
555
  const timelineMap = getTimelinesGroupedByTjp({ ibGibs: allWithTjp });
463
- if (logalot) { console.log(`${lc}[TEST DEBUG] timelineMap: ${JSON.stringify(timelineMap)} (I: 2cc04898e5f85179fb1ac7f827abc426)`); }
556
+ if (false) { console.log(`${lc}[TEST DEBUG] timelineMap: ${JSON.stringify(timelineMap)} (I: 2cc04898e5f85179fb1ac7f827abc426)`); }
464
557
 
465
558
  tjps = Object.keys(timelineMap);
466
- if (logalot) { console.log(`${lc}[TEST DEBUG] tjps: ${tjps} (I: 3dd548667cbd967c68e57c88dc570826)`); }
559
+ if (false) { console.log(`${lc}[TEST DEBUG] tjps: ${tjps} (I: 3dd548667cbd967c68e57c88dc570826)`); }
467
560
  } else {
468
561
  // No info provided. Return empty? Or throw?
469
562
  // User test context implied "everything", but implementation requires scope.
@@ -473,14 +566,14 @@ export class SyncSagaCoordinator {
473
566
 
474
567
  if (tjps.length === 0) { return {}; }
475
568
 
476
- if (logalot) { console.log(`${lc} getting latest addrs for tjps: ${tjps} (I: d4e7080b8ba8187c583b82fd91ac0626)`); }
569
+ if (false) { console.log(`${lc} getting latest addrs for tjps: ${tjps} (I: d4e7080b8ba8187c583b82fd91ac0626)`); }
477
570
 
478
571
  const res = await getLatestAddrs({ space, tjpAddrs: tjps });
479
572
  if (!res.data || !res.data.latestAddrsMap) {
480
573
  throw new Error(`${lc} Failed to get latest addrs. (E: 7a8b9c0d)`);
481
574
  }
482
575
 
483
- if (logalot) { console.log(`${lc}[TEST DEBUG] res.data.latestAddrsMap: ${JSON.stringify(res.data.latestAddrsMap)} (I: a8e128bdf80898ac2e6d8021a5bff726)`); }
576
+ // if (false) { console.log(`${lc}[TEST DEBUG] res.data.latestAddrsMap: ${JSON.stringify(res.data.latestAddrsMap)} (I: a8e128bdf80898ac2e6d8021a5bff726)`); }
484
577
 
485
578
  return res.data.latestAddrsMap;
486
579
  } catch (error) {
@@ -622,18 +715,64 @@ export class SyncSagaCoordinator {
622
715
  }
623
716
 
624
717
  /**
625
- * Reacts to an incoming saga frame and dispatches to appropriate handler.
626
- *
627
- * @remarks
628
- * **Execution Context**: **Universal (Both Sender and Receiver)**.
629
- *
630
- * This method acts as the "Reducer" for the Sync FSM. It determines the current stage
631
- * based on the incoming frame and delegates to the appropriate handler.
632
- *
633
- * * If running on **Receiver**: Handles `Init` (via `handleInitFrame`).
634
- * * If running on **Sender**: Handles `Ack` (via `handleAckFrame`).
635
- * * If running on **Either**: Handles `Delta` (via `handleDeltaFrame`) or `Commit`.
718
+ * Helper to poll for streaming domain payloads and put them in the
719
+ * local {@link tempSpace}.
636
720
  */
721
+ protected async pollForDomainPayloads({
722
+ expectedAddrs,
723
+ domainPayloadsMap,
724
+ tempSpace,
725
+ }: {
726
+ expectedAddrs: string[],
727
+ domainPayloadsMap: Map<string, IbGib_V1>,
728
+ tempSpace: IbGibSpaceAny,
729
+ }): Promise<void> {
730
+ const lc = `${this.lc}[${this.pollForDomainPayloads.name}]`;
731
+ try {
732
+ if (logalot) { console.log(`${lc} starting... (I: 26dce86bfca572939885798802d6e926)`); }
733
+
734
+ let pending = [...expectedAddrs];
735
+ const start = Date.now();
736
+ /**
737
+ * This needs
738
+ */
739
+ const timeoutMs = 5 * 60 * 1000; // 5 minutes...arbitrary at this point. This needs to be pulled out and improved eesh.
740
+
741
+ while (pending.length > 0) {
742
+ if (Date.now() - start > timeoutMs) {
743
+ throw new Error(`Timeout waiting for payloads: ${pending.join(', ')} (E: 46e1683c9578095261aaf798bd5e1826)`);
744
+ }
745
+
746
+ const stillPending: string[] = [];
747
+ const found: IbGib_V1[] = [];
748
+
749
+ for (const addr of pending) {
750
+ if (domainPayloadsMap.has(addr)) {
751
+ found.push(domainPayloadsMap.get(addr)!);
752
+ domainPayloadsMap.delete(addr);
753
+ } else {
754
+ stillPending.push(addr);
755
+ }
756
+ }
757
+
758
+ if (found.length > 0) {
759
+ await putInSpace({ space: tempSpace, ibGibs: found });
760
+ }
761
+
762
+ pending = stillPending;
763
+
764
+ if (pending.length > 0) {
765
+ await new Promise(resolve => setTimeout(resolve, 50));
766
+ }
767
+ }
768
+ } catch (error) {
769
+ console.error(`${lc} ${extractErrorMsg(error)}`);
770
+ throw error;
771
+ } finally {
772
+ if (logalot) { console.log(`${lc} complete.`); }
773
+ }
774
+ }
775
+
637
776
  async handleSagaFrame({
638
777
  sagaIbGib,
639
778
  srcGraph,
@@ -650,7 +789,9 @@ export class SyncSagaCoordinator {
650
789
  identity?: KeystoneIbGib_V1,
651
790
  identitySecret?: string,
652
791
  metaspace: MetaspaceService,
653
- }): Promise<{ frame: SyncIbGib_V1, payloadIbGibs?: IbGib_V1[], receivedPayloadIbGibs?: IbGib_V1[] } | null> {
792
+ domainPayloadsMap?: Map<string, IbGib_V1>,
793
+ expectedDomainAddrs?: string[],
794
+ }): Promise<HandleSagaFrameResult | null> {
654
795
  const lc = `${this.lc}[${this.handleSagaFrame.name}]`;
655
796
  try {
656
797
  if (logalot) { console.log(`${lc} starting... (I: 5deec8a1f7a6d263c88cd458ad990826)`); }
@@ -717,7 +858,7 @@ export class SyncSagaCoordinator {
717
858
  metaspace: MetaspaceService,
718
859
  identity?: KeystoneIbGib_V1,
719
860
  identitySecret?: string,
720
- }): Promise<{ frame: SyncIbGib_V1, payloadIbGibs?: IbGib_V1[] } | null> {
861
+ }): Promise<HandleSagaFrameResult | null> {
721
862
  const lc = `${this.lc}[${this.handleInitFrame.name}]`;
722
863
  console.log(`${lc} [TEST DEBUG] Received destSpace: ${destSpace.data?.name || destSpace.ib} (uuid: ${destSpace.data?.uuid || '[no uuid]'})`);
723
864
  if (logalot) { console.log(`${lc} starting...`); }
@@ -1002,7 +1143,11 @@ export class SyncSagaCoordinator {
1002
1143
 
1003
1144
  // if (logalot) { console.log(`${lc} ackFrame created: ${pretty(ackFrame)} (I: be24480592eec478086bb3da49286826)`); }
1004
1145
 
1005
- return { frame: ackFrame };
1146
+ // Build control payloads: frame + its dependencies (msg stone, identity)
1147
+ const payloadIbGibsControl: IbGib_V1[] = [ackFrame, ackStone];
1148
+ if (identity) { payloadIbGibsControl.push(identity); }
1149
+
1150
+ return { frame: ackFrame, payloadIbGibsControl };
1006
1151
  }
1007
1152
 
1008
1153
  /**
@@ -1031,7 +1176,7 @@ export class SyncSagaCoordinator {
1031
1176
  tempSpace: IbGibSpaceAny,
1032
1177
  metaspace: MetaspaceService,
1033
1178
  identity?: KeystoneIbGib_V1,
1034
- }): Promise<{ frame: SyncIbGib_V1, payloadIbGibs?: IbGib_V1[] } | null> {
1179
+ }): Promise<HandleSagaFrameResult | null> {
1035
1180
  const lc = `${this.lc}[${this.handleAckFrame.name}]`;
1036
1181
  try {
1037
1182
  if (logalot) { console.log(`${lc} starting... (I: 605b6860e898267a5b50c6d85704be26)`); }
@@ -1130,62 +1275,7 @@ export class SyncSagaCoordinator {
1130
1275
  // PULL these frames from Peer into Local Space
1131
1276
  // (Validation: We trust peer for now / verification happens on put)
1132
1277
  for (const addr of receiverOnlyAddrs) {
1133
- // This 'pull' is a sync-peer method?
1134
- // The Coordinator 'peer' passed in 'sync()' might be needed here?
1135
- // Wait, `handleAckFrame` doesn't have reference to `peer`?
1136
- // It only has `space`, `metaspace`.
1137
- // The `peer` is held by the `executeSagaLoop`.
1138
-
1139
- // PROBLEM: `handleAckFrame` is pure logic on the Space/Data?
1140
- // No, it's a method on Coordinator.
1141
- // But `executeSagaLoop` calls it.
1142
- // We might need to return "Requirements" to the loop?
1143
-
1144
- // Checking return type: `{ frame: SyncIbGib_V1, payloadIbGibs?: ... }`
1145
- // It returns the NEXT frame (Delta).
1146
-
1147
- // If we need to fetch data, we are blocked.
1148
- // We can't easily "Pull" here without the Peer reference.
1149
-
1150
- // OPTION A: Pass `peer` to `handleAckFrame`.
1151
- // OPTION B: Return a strict list of "MissingDeps" and let Loop handle it.
1152
-
1153
- // Let's assume we can resolve this by adding `peer` to signature or using `metaspace` if it's a peer-witness?
1154
- // No, Peer is ephemeral connection.
1155
-
1156
- // Let's add `peer` to `handleAckFrame` signature?
1157
- // It breaks the pattern of just handling frame + space.
1158
-
1159
- // ALTERNATIVE: Use the `Delta` frame to request data?
1160
- // `SyncSagaMessageDeltaData` has `requests?: string[]`.
1161
- // Sender sends Delta Frame.
1162
- // Does Receiver handle Delta Requests?
1163
- // `handleDeltaFrame` (Receiver) -> checks `requests`.
1164
- // YES.
1165
-
1166
- // So Sender puts `receiverOnlyAddrs` into `deltaFrame.requests`.
1167
- // Receiver sees them, fetches them, and includes them in the Response (Commit?).
1168
- // Wait, Init->Ack->Delta->Commit.
1169
- // If Receiver sends data in Commit, that's "too late" for Sender to Merge in THIS saga round?
1170
- // Unless Commit is not the end?
1171
-
1172
- // Or we do a "Delta 2" loop?
1173
-
1174
- // "Iterative Resolution Loop" from plan.
1175
- // If we request data in Delta, Receiver sends it in Commit (or Delta-Response).
1176
- // Sender gets Commit. Sees data. Merges.
1177
- // Then Sender needs to Send the MERGE result.
1178
- // Needs another Push/Delta.
1179
-
1180
- // REFINED FLOW:
1181
- // 1. Sender sends Delta Frame with `requests: [receiverOnlyAddrs]`.
1182
- // 2. Receiver responds (Commit? or Ack 2?) with Payload (Divergent Frames).
1183
- // 3. Sender handles response -> Merges.
1184
- // 4. Sender sends Commit (containing Merge Frame).
1185
-
1186
- // Issue: Current state machine is Init->Ack->Delta->Commit.
1187
- // We need to keep Saga open.
1188
- // If Sender sends Delta with requests, does it transition to Commit?
1278
+ console.error(`${lc} [CONFLICT DEBUG] NOT IMPLEMENTED (E: e6bf1a9d2758c469bb2f97514062d826)`);
1189
1279
  }
1190
1280
 
1191
1281
  // Compute DELTA dependencies for each receiver-only frame
@@ -1371,7 +1461,11 @@ export class SyncSagaCoordinator {
1371
1461
 
1372
1462
  if (logalot) { console.log(`${lc} Delta Frame created. Rel8ns: ${JSON.stringify(deltaFrame.rel8ns)}`); }
1373
1463
 
1374
- return { frame: deltaFrame, payloadIbGibs };
1464
+ // Build control payloads: frame + its dependencies (msg stone, identity)
1465
+ const payloadIbGibsControl: IbGib_V1[] = [deltaFrame, deltaStone];
1466
+ if (identity) { payloadIbGibsControl.push(identity); }
1467
+
1468
+ return { frame: deltaFrame, payloadIbGibsControl, payloadIbGibsDomain: payloadIbGibs };
1375
1469
  } catch (error) {
1376
1470
  console.error(`${lc} ${extractErrorMsg(error)}`);
1377
1471
  throw error;
@@ -1404,7 +1498,7 @@ export class SyncSagaCoordinator {
1404
1498
  tempSpace: IbGibSpaceAny,
1405
1499
  metaspace: MetaspaceService,
1406
1500
  identity?: KeystoneIbGib_V1,
1407
- }): Promise<{ frame: SyncIbGib_V1, payloadIbGibs?: IbGib_V1[], receivedPayloadIbGibs?: IbGib_V1[] } | null> {
1501
+ }): Promise<HandleSagaFrameResult | null> {
1408
1502
  const lc = `${this.lc}[${this.handleDeltaFrame.name}]`;
1409
1503
  if (logalot) { console.log(`${lc} starting...`); }
1410
1504
 
@@ -1629,7 +1723,11 @@ export class SyncSagaCoordinator {
1629
1723
  // IMMEDIATELY persist to both spaces for audit trail
1630
1724
  await this.ensureSagaFrameInBothSpaces({ frame: deltaFrame, destSpace, tempSpace, metaspace });
1631
1725
 
1632
- return { frame: deltaFrame, payloadIbGibs: outgoingPayload, receivedPayloadIbGibs };
1726
+ // Build control payloads: frame + its dependencies (msg stone, identity)
1727
+ const payloadIbGibsControl: IbGib_V1[] = [deltaFrame, deltaStone];
1728
+ if (identity) { payloadIbGibsControl.push(identity); }
1729
+
1730
+ return { frame: deltaFrame, payloadIbGibsControl, payloadIbGibsDomain: outgoingPayload };
1633
1731
 
1634
1732
  } else {
1635
1733
  // We have nothing to send.
@@ -1659,7 +1757,11 @@ export class SyncSagaCoordinator {
1659
1757
  // IMMEDIATELY persist to both spaces for audit trail
1660
1758
  await this.ensureSagaFrameInBothSpaces({ frame: commitFrame, destSpace, tempSpace, metaspace });
1661
1759
 
1662
- return { frame: commitFrame, receivedPayloadIbGibs };
1760
+ // Build control payloads for commit
1761
+ const commitCtrlPayloads: IbGib_V1[] = [commitFrame, commitStone];
1762
+ if (identity) { commitCtrlPayloads.push(identity); }
1763
+
1764
+ return { frame: commitFrame, payloadIbGibsControl: commitCtrlPayloads };
1663
1765
 
1664
1766
  } else {
1665
1767
  // peer did NOT propose commit (maybe they just sent data/requests and didn't ready flag).
@@ -1718,10 +1820,18 @@ export class SyncSagaCoordinator {
1718
1820
  // IMMEDIATELY persist to both spaces for audit trail
1719
1821
  await this.ensureSagaFrameInBothSpaces({ frame: commitFrame, destSpace, tempSpace, metaspace });
1720
1822
 
1721
- return { frame: commitFrame, receivedPayloadIbGibs };
1823
+ // Build control payloads for commit
1824
+ const commitCtrlPayloads2: IbGib_V1[] = [commitFrame, commitStone];
1825
+ if (identity) { commitCtrlPayloads2.push(identity); }
1826
+
1827
+ return { frame: commitFrame, payloadIbGibsControl: commitCtrlPayloads2 };
1722
1828
  }
1723
1829
 
1724
- return { frame: deltaFrame, receivedPayloadIbGibs };
1830
+ // Build control payloads for delta propose
1831
+ const deltaCtrlPayloads: IbGib_V1[] = [deltaFrame, deltaStone];
1832
+ if (identity) { deltaCtrlPayloads.push(identity); }
1833
+
1834
+ return { frame: deltaFrame, payloadIbGibsControl: deltaCtrlPayloads };
1725
1835
  }
1726
1836
  }
1727
1837
  }
@@ -1739,7 +1849,7 @@ export class SyncSagaCoordinator {
1739
1849
  tempSpace: IbGibSpaceAny,
1740
1850
  metaspace: MetaspaceService,
1741
1851
  identity?: KeystoneIbGib_V1,
1742
- }): Promise<{ frame: SyncIbGib_V1, payloadIbGibs?: IbGib_V1[] } | null> {
1852
+ }): Promise<HandleSagaFrameResult | null> {
1743
1853
  const lc = `${this.lc}[${this.handleCommitFrame.name}]`;
1744
1854
  if (logalot) { console.log(`${lc} Commit received.`); }
1745
1855