@ibgib/core-gib 0.1.23 → 0.1.25

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 (67) hide show
  1. package/dist/common/other/graph-helper.d.mts +17 -0
  2. package/dist/common/other/graph-helper.d.mts.map +1 -1
  3. package/dist/common/other/graph-helper.mjs +44 -0
  4. package/dist/common/other/graph-helper.mjs.map +1 -1
  5. package/dist/sync/graft-info/graft-info-helpers.mjs +2 -2
  6. package/dist/sync/graft-info/graft-info-helpers.mjs.map +1 -1
  7. package/dist/sync/sync-conflict.respec.mjs +10 -15
  8. package/dist/sync/sync-conflict.respec.mjs.map +1 -1
  9. package/dist/sync/sync-innerspace-constants.respec.mjs +10 -12
  10. package/dist/sync/sync-innerspace-constants.respec.mjs.map +1 -1
  11. package/dist/sync/sync-innerspace-deep-updates.respec.mjs +10 -12
  12. package/dist/sync/sync-innerspace-deep-updates.respec.mjs.map +1 -1
  13. package/dist/sync/sync-innerspace-dest-ahead.respec.mjs +10 -12
  14. package/dist/sync/sync-innerspace-dest-ahead.respec.mjs.map +1 -1
  15. package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs +9 -12
  16. package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs.map +1 -1
  17. package/dist/sync/sync-innerspace-partial-update.respec.mjs +9 -14
  18. package/dist/sync/sync-innerspace-partial-update.respec.mjs.map +1 -1
  19. package/dist/sync/sync-innerspace.respec.mjs +9 -12
  20. package/dist/sync/sync-innerspace.respec.mjs.map +1 -1
  21. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.d.mts +2 -0
  22. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.d.mts.map +1 -1
  23. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mjs +4 -0
  24. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mjs.map +1 -1
  25. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts +24 -11
  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 +58 -44
  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-types.d.mts +29 -6
  30. package/dist/sync/sync-peer/sync-peer-types.d.mts.map +1 -1
  31. package/dist/sync/sync-peer/sync-peer-v1.d.mts +29 -30
  32. package/dist/sync/sync-peer/sync-peer-v1.d.mts.map +1 -1
  33. package/dist/sync/sync-peer/sync-peer-v1.mjs +105 -198
  34. package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
  35. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts +19 -2
  36. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts.map +1 -1
  37. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs +37 -4
  38. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs.map +1 -1
  39. package/dist/sync/sync-saga-coordinator.d.mts +12 -12
  40. package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
  41. package/dist/sync/sync-saga-coordinator.mjs +281 -218
  42. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  43. package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts +51 -6
  44. package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts.map +1 -1
  45. package/dist/sync/sync-types.d.mts +36 -9
  46. package/dist/sync/sync-types.d.mts.map +1 -1
  47. package/dist/sync/sync-types.mjs +1 -2
  48. package/dist/sync/sync-types.mjs.map +1 -1
  49. package/package.json +1 -1
  50. package/src/common/other/graph-helper.mts +53 -0
  51. package/src/sync/graft-info/graft-info-helpers.mts +3 -3
  52. package/src/sync/sync-conflict.respec.mts +10 -17
  53. package/src/sync/sync-helpers.mts +6 -6
  54. package/src/sync/sync-innerspace-constants.respec.mts +10 -12
  55. package/src/sync/sync-innerspace-deep-updates.respec.mts +10 -12
  56. package/src/sync/sync-innerspace-dest-ahead.respec.mts +10 -12
  57. package/src/sync/sync-innerspace-multiple-timelines.respec.mts +9 -12
  58. package/src/sync/sync-innerspace-partial-update.respec.mts +9 -14
  59. package/src/sync/sync-innerspace.respec.mts +9 -12
  60. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mts +7 -0
  61. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mts +75 -50
  62. package/src/sync/sync-peer/sync-peer-types.mts +35 -11
  63. package/src/sync/sync-peer/sync-peer-v1.mts +136 -196
  64. package/src/sync/sync-saga-context/sync-saga-context-helpers.mts +37 -8
  65. package/src/sync/sync-saga-coordinator.mts +318 -260
  66. package/src/sync/sync-saga-message/sync-saga-message-types.mts +56 -4
  67. package/src/sync/sync-types.mts +46 -13
@@ -5,13 +5,13 @@ import { Factory_V1 } from "@ibgib/ts-gib/dist/V1/factory.mjs";
5
5
  import { putInSpace, getLatestAddrs, getFromSpace } from "../witness/space/space-helper.mjs";
6
6
  import { SyncStage, SYNC_ATOM, SYNC_MSG_REL8N_NAME, SYNC_SAGA_PAYLOAD_ADDRS_DOMAIN } from "./sync-constants.mjs";
7
7
  import { appendToTimeline, createTimeline } from "../timeline/timeline-api.mjs";
8
- import { SyncConflictStrategy, SyncMode, } from "./sync-types.mjs";
8
+ import { SyncConflictStrategy, SyncMode, SYNC_CONFLICT_STRATEGY_VALID_VALUES, } from "./sync-types.mjs";
9
9
  import { getSyncIb, getTempSpaceName, isPastFrame } from "./sync-helpers.mjs";
10
- import { getDependencyGraph, toFlatGraph } from "../common/other/graph-helper.mjs";
10
+ import { getDeltaDependencyGraph, getDependencyGraph, toFlatGraph } from "../common/other/graph-helper.mjs";
11
11
  import { getSyncSagaMessageIb } from "./sync-saga-message/sync-saga-message-helpers.mjs";
12
12
  import { SYNC_SAGA_MSG_ATOM } from "./sync-saga-message/sync-saga-message-constants.mjs";
13
13
  import { splitPerTjpAndOrDna, getTimelinesGroupedByTjp, isIbGib } from "../common/other/ibgib-helper.mjs";
14
- import { createSyncSagaContext } from "./sync-saga-context/sync-saga-context-helpers.mjs";
14
+ import { createSyncSagaContext, validateContextAndSagaFrame } from "./sync-saga-context/sync-saga-context-helpers.mjs";
15
15
  import { newupSubject, } from "../common/pubsub/subject/subject-helper.mjs";
16
16
  import { mergeDivergentTimelines } from "./strategies/conflict-optimistic.mjs";
17
17
  import { getSyncSagaMessageFromFrame } from "./sync-saga-message/sync-saga-message-helpers.mjs";
@@ -95,30 +95,29 @@ export class SyncSagaCoordinator {
95
95
  // Async execution wrapper
96
96
  (async () => {
97
97
  try {
98
- // 2. BOOTSTRAP IDENTITY (Session Keystone)
98
+ // BOOTSTRAP IDENTITY (Session Keystone)
99
99
  const sessionIdentity = useSessionIdentity
100
100
  ? await this.getSessionIdentity({ sagaId, metaspace, tempSpace })
101
101
  : undefined;
102
102
  // if (logalot) { console.log(`${lc} sessionIdentity: ${sessionIdentity ? pretty(sessionIdentity) : 'undefined'} (I: abc01872800b3a66b819a05898bba826)`); }
103
- // 3. CREATE INITIAL FRAME (Stage.init)
104
- const { sagaFrame: initFrame, initialDomainGraph } = await this.createInitFrame({
103
+ // CREATE INITIAL FRAME (Stage.init)
104
+ const { initFrame, initDomainGraph } = await this.createInitFrame({
105
105
  sagaId,
106
106
  sessionIdentity,
107
107
  domainIbGibs,
108
108
  conflictStrategy,
109
109
  metaspace, localSpace, tempSpace,
110
110
  });
111
- // 4. KICK OFF THE PING-PONG SAGA LOOP (FSM)
112
- // commented to compile
113
- // await this.executeSagaLoop({
114
- // initialFrame: initFrame,
115
- // peer,
116
- // sessionIdentity,
117
- // updates$,
118
- // localSpace,
119
- // tempSpace,
120
- // metaspace
121
- // });
111
+ // KICK OFF THE PING-PONG SAGA LOOP (FSM)
112
+ await this.executeSagaLoop({
113
+ initFrame, initDomainGraph,
114
+ peer,
115
+ sessionIdentity,
116
+ updates$,
117
+ localSpace,
118
+ tempSpace,
119
+ metaspace
120
+ });
122
121
  resolveDone();
123
122
  if (!updates$.complete) {
124
123
  throw new Error(`(UNEXPECTED) updates$.complete falsy? (E: d24cd82184aec130c89a320819b39126)`);
@@ -189,45 +188,23 @@ export class SyncSagaCoordinator {
189
188
  * the NEXT request context.
190
189
  * When the Peer responds with data (in the response context), it is resolved and put into `tempSpace`.
191
190
  */
192
- async executeSagaLoop({ initialFrame, initialDomainGraph, peer, sessionIdentity, updates$, localSpace, tempSpace, metaspace }) {
191
+ async executeSagaLoop({ initFrame, initDomainGraph, peer, sessionIdentity, updates$, localSpace, tempSpace, metaspace }) {
193
192
  const lc = `${this.lc}[${this.executeSagaLoop.name}]`;
194
- // The current frame we just generated (e.g., Init or Delta Request)
195
- let currentFrame = initialFrame;
196
- // The payload we need to attach to the message (data we are sending)
193
+ /** The current frame we just generated (e.g., Init or Delta Request) */
194
+ let currentFrame = initFrame;
195
+ /** The **domain** payload we need to transmit (data we are sending) */
197
196
  let nextDomainIbGibs = [];
198
- // First, inject local/tempSpace into peer so it can pull as
199
- // needed...code smell?
200
- peer.senderSpace = localSpace;
201
- peer.senderTempSpace = tempSpace;
202
197
  while (currentFrame) {
203
- // A. Create Context (Request)
204
- // 1. Calculate Full Dependency Graph (including Ancestors/DNA)
205
- // We must do this BEFORE creating the Context so we can list them
206
- // all in payloadAddrsDomain and payloadAddrsControl.
207
- const nextDomainIbGibsAndDeps = [];
208
- // A. Payload (Standard Deep Deps)
209
- // TODO: THIS IS EXTREMELY INEFFICIENT. adjust this algorithm to
210
- // only do the dependencies that the other end doesn't need (diff
211
- // between tip and LCA). This can be done using the information in
212
- // the ack's conflicts array.
213
- for (const nextDomainIbGib of nextDomainIbGibs) {
214
- let nextDomainIbGibGraph = await getDependencyGraph({ ibGib: nextDomainIbGib, space: localSpace });
215
- if (!nextDomainIbGibGraph) {
216
- nextDomainIbGibGraph = await getDependencyGraph({ ibGib: nextDomainIbGib, space: tempSpace });
217
- }
218
- if (nextDomainIbGibGraph) {
219
- nextDomainIbGibsAndDeps.push(...Object.values(nextDomainIbGibGraph));
220
- }
221
- else {
222
- throw new Error(`(UNEXPECTED) we couldn't get the graph for a known domain ibgib? nextDomainIbGib addr: ${getIbGibAddr({ ibGib: nextDomainIbGib })} (E: 01b3e4db8768b5b77db72e486f4f7826)`);
223
- }
224
- }
225
- if (logalot) {
226
- console.log(`${lc} payloadIbGibsDomain count: ${nextDomainIbGibsAndDeps.length} (I: 2beda8ca7dc5ac0f48ed9e25e704b826)`);
227
- }
228
- // 2. Create Context (Envelope)
229
- // set up subscription for response's payload ibgibs (if any)
198
+ // first, prepare for context transmission...
199
+ /**
200
+ * this is used later in pollForDomainPayloads **iif** payloads are
201
+ * received **in the response**, i.e., on the return trip. So if we
202
+ * request addrs, the response should have these addrs and their
203
+ * dependencies. The ibgibs corresponding to these addrs will be
204
+ * streamed and placed into this map.
205
+ */
230
206
  const domainPayloadsMap = new Map();
207
+ // #region set up peer observable for any domainPayloadsMap
231
208
  const sublc = `${lc}[peer.payloadIbGibsDomainReceived$]`;
232
209
  const subscription = await peer.payloadIbGibsDomainReceived$.subscribe(fnObs({
233
210
  next: async (ibgib) => {
@@ -256,38 +233,45 @@ export class SyncSagaCoordinator {
256
233
  await subscription.unsubscribe();
257
234
  },
258
235
  }));
259
- // Create the Request Context...
236
+ // #endregion set up peer observable for any domainPayloadsMap
237
+ // ...create/compose the Request Context itself...
260
238
  const requestCtx = await createSyncSagaContext({
261
239
  sagaFrame: currentFrame,
262
240
  sessionKeystones: sessionIdentity ? [sessionIdentity] : undefined,
263
241
  /**
264
242
  * init frame: empty
265
- *
243
+ * ack frame: possible push offers
244
+ * delta frame: requested ibgibs or commit offer
245
+ * commit frame: empty
266
246
  */
267
- payloadIbGibsDomain: nextDomainIbGibsAndDeps,
247
+ payloadIbGibsDomain: nextDomainIbGibs,
268
248
  localSpace,
269
249
  });
270
- // Log what we're sending
250
+ // #region Log what we're sending
271
251
  if (logalotControlDomain) {
272
- const domainAddrs = nextDomainIbGibsAndDeps.map(p => getIbGibAddr({ ibGib: p }));
273
- console.log(`${lc}${lcControlDomain} SENDER TRANSMIT -> peer.witness (I: b3c4d5e6f7a8b9c0)`);
252
+ const domainAddrs = nextDomainIbGibs.map(p => getIbGibAddr({ ibGib: p }));
253
+ console.log(`${lc}${lcControlDomain} SENDER TRANSMIT -> peer.witness (I: 5b0081803698770f0bf64992220b312)`);
274
254
  console.log(`${lc}${lcControlDomain} Context: ${getIbGibAddr({ ibGib: requestCtx })}`);
275
255
  console.log(`${lc}${lcControlDomain} Frame: ${getIbGibAddr({ ibGib: currentFrame })}`);
276
256
  console.log(`${lc}${lcControlDomain} DOMAIN Payloads (${domainAddrs.length}): ${domainAddrs.join(', ') || '(none)'}`);
277
257
  }
258
+ // #endregion Log what we're sending
278
259
  // update our saga listeners...
279
260
  // if (logalot) { console.log(`${lc} transmitting... requestCtx: ${pretty(requestCtx)} (I: 8cf20817c66899abdb1e76df50356826)`); }
280
- updates$.next(requestCtx); // spins off
281
- // ...And send the context
261
+ updates$.next(requestCtx); // spins off for saga UI updates
262
+ // ...And send the context.
263
+ peer.setOptionalOpts({ senderSpace: localSpace, senderTempSpace: tempSpace, });
282
264
  const responseCtx = await peer.witness(requestCtx);
283
- // C. Handle Response
265
+ // the send returned, but a peer can return a falsy responseCtx, if
266
+ // we just sent a commit to them and they're done. If so, there will
267
+ // necessarily be no payload to wait to receive
284
268
  if (!responseCtx) {
285
269
  if (currentFrame) {
286
270
  // Check for Commit (Peer silence expected)
287
271
  const msg = await getSyncSagaMessageFromFrame({ frameIbGib: currentFrame, space: localSpace });
288
272
  if (msg?.data?.stage === SyncStage.commit) {
289
273
  if (logalot) {
290
- console.log(`${lc} Sender sent Commit. Peer returned no response. Saga Complete.`);
274
+ console.log(`${lc} Sender sent Commit. Peer returned no response. Saga Complete. (I: 26f9ee073858ca78b8284753368b5226)`);
291
275
  }
292
276
  currentFrame = null;
293
277
  break;
@@ -300,19 +284,19 @@ export class SyncSagaCoordinator {
300
284
  throw new Error(`(UNEXPECTED) no response and currentFrame falsy? (E: 8d1085ea2f28cfc3f9c922649864a826)`);
301
285
  }
302
286
  }
303
- // ---------------------------------------------------------------------
304
- // 2d. HANDLE RESPONSE
305
- // ---------------------------------------------------------------------
306
- // at this point, we have received the response context ibgib, but
287
+ // at this point, we did indeed receive a response to analyze. BUT!
288
+ // we have only necessarily received the response context ibgib.
307
289
  // if there were payloads expected to be transferred, they may not
308
290
  // be done yet.
309
291
  if (!responseCtx.data) {
310
292
  throw new Error(`(UNEXPECTED) responseCtx.data falsy? (E: a969992bae53ab18a827ec58aec15826)`);
311
293
  }
312
- updates$.next(responseCtx); // spins off -- don't remove this comment!
294
+ updates$.next(responseCtx); // spins off for saga UI updating
295
+ // validate context
296
+ await validateContextAndSagaFrame;
313
297
  // Extract expected domain addresses from response context
314
298
  const responsePayloadAddrsDomain = responseCtx.data[SYNC_SAGA_PAYLOAD_ADDRS_DOMAIN] || [];
315
- // Poll for them if needed
299
+ // Poll for them if needed. see above jsdocs for domainPayloadsMap
316
300
  if (responsePayloadAddrsDomain.length > 0) {
317
301
  responseCtx.payloadIbGibsDomain = await this.pollForDomainPayloads({
318
302
  expectedAddrs: responsePayloadAddrsDomain,
@@ -321,49 +305,61 @@ export class SyncSagaCoordinator {
321
305
  tempSpace,
322
306
  });
323
307
  }
324
- // at this point, we have received the context AND **all** of the
325
- // domain payloads (if applicable), so we are ready to do the next
326
- // iteration in the saga loop
327
- // Log what we received back
308
+ // #region Log what we received back
328
309
  if (!responseCtx.sagaFrame) {
329
310
  throw new Error(`(UNEXPECTED) responseCtx.sagaFrame falsy? the Peer should have set this when it got the response back from the remote. (E: e650adadf9a2063ec6764a1e31d3d826)`);
330
311
  }
331
312
  if (logalotControlDomain) {
332
313
  const responseControlAddrs = responseCtx.data?.['@payloadAddrsControl'] || [];
333
- console.log(`${lc}${lcControlDomain} SENDER RECEIVED <- peer.witness (I: c4d5e6f7a8b9c0d1)`);
314
+ console.log(`${lc}${lcControlDomain} SENDER RECEIVED <- peer.witness (I: 3dc76a9744d89a4fc3e2f076c2be4826)`);
334
315
  console.log(`${lc}${lcControlDomain} Response Context: ${getIbGibAddr({ ibGib: responseCtx })}`);
335
316
  console.log(`${lc}${lcControlDomain} Response Saga Frame: ${getIbGibAddr({ ibGib: responseCtx.sagaFrame })}`);
336
317
  console.log(`${lc}${lcControlDomain} CONTROL Payloads (${responseControlAddrs.length}): ${responseControlAddrs.join(', ') || '(none)'}`);
337
318
  console.log(`${lc}${lcControlDomain} DOMAIN Payloads (${responsePayloadAddrsDomain.length}): ${responsePayloadAddrsDomain.join(', ') || '(none)'}`);
338
319
  }
339
- // Handle Response Frame
340
- // interface HandleSagaFrameResult {
341
- // frame: SyncIbGib_V1;
342
- // payloadIbGibsDomain?: IbGib_V1[];
343
- // conflictInfos?: SyncSagaConflictInfo;
344
- // }
345
- const handleResult = await this.handleSagaContext({
320
+ // #endregion Log what we received back
321
+ // at this point, we have received the context AND **all** of the
322
+ // domain payloads (if applicable), so we are ready to do the next
323
+ // iteration in the saga loop
324
+ // this is the part that drives the FSM forward, i.e., when we
325
+ // evolve the sync saga ibgib itself to the next frame if we aren't
326
+ // finished/errored out.
327
+ const contextResult = await this.handleResponseSagaContext({
346
328
  sagaContext: responseCtx,
347
329
  mySpace: localSpace,
348
330
  myTempSpace: tempSpace,
349
331
  metaspace,
350
332
  });
351
- if (!handleResult) {
333
+ if (!contextResult) {
352
334
  if (logalot) {
353
- console.log(`${lc} Handler returned null (Saga End).`);
335
+ console.log(`${lc} Handler returned null (Saga End). (I: faae22abc818ba9b28ac6d2881cd7826)`);
354
336
  }
355
337
  break;
356
338
  }
357
- currentFrame = handleResult.frame;
358
- // Collect next DOMAIN payloads for the NEXT request
359
- nextDomainIbGibs = [...(handleResult.payloadIbGibsDomain || [])];
360
- // Log handler output for next iteration
339
+ // #region error conditions throw
340
+ if (contextResult.errorMsg) {
341
+ throw new Error(`Couldn't handle response saga context. errorMsg: ${contextResult.errorMsg} (E: c948e81d513b2a0eb8b8afa878edc626)`);
342
+ }
343
+ else if (!contextResult.nextFrameInfo) {
344
+ throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo falsy? (E: c287a82e823e662a77923278e2418826)`);
345
+ }
346
+ else if (contextResult.nextFrameInfo?.responseWasNull) {
347
+ throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo.responseWasNull? logic flow should not have gotten here. (E: 104a32381db816b7183435e805b3d626)`);
348
+ }
349
+ // #endregion error conditions throw
350
+ // we have another frame to process and send out, with possibly
351
+ // payload domain ibgibs as well
352
+ const { frame, payloadIbGibsDomain, } = contextResult.nextFrameInfo;
353
+ currentFrame = frame;
354
+ nextDomainIbGibs = [...(payloadIbGibsDomain || [])];
355
+ // #region Log handler output for next iteration
361
356
  if (logalotControlDomain) {
362
357
  const handlerDomainAddrs = nextDomainIbGibs.map(p => getIbGibAddr({ ibGib: p }));
363
- console.log(`${lc}${lcControlDomain} HANDLER RESULT -> next iteration (I: d5e6f7a8b9c0d1e2)`);
358
+ console.log(`${lc}${lcControlDomain} HANDLER RESULT -> next iteration (I: 6b0d88c4c28857ccd812381515bd7826)`);
364
359
  console.log(`${lc}${lcControlDomain} Next Frame: ${getIbGibAddr({ ibGib: currentFrame })}`);
365
360
  console.log(`${lc}${lcControlDomain} DOMAIN for next (${handlerDomainAddrs.length}): ${handlerDomainAddrs.join(', ') || '(none)'}`);
366
361
  }
362
+ // #endregion Log handler output for next iteration
367
363
  }
368
364
  }
369
365
  /**
@@ -423,7 +419,7 @@ export class SyncSagaCoordinator {
423
419
  }
424
420
  const res = await getLatestAddrs({ space, tjpAddrs: tjps });
425
421
  if (!res.data || !res.data.latestAddrsMap) {
426
- throw new Error(`${lc} Failed to get latest addrs. (E: 7a8b9c0d)`);
422
+ throw new Error(`${lc} Failed to get latest addrs. (E: 7d395940c0e1419165c5196c39c6c826)`);
427
423
  }
428
424
  // if (false) { console.log(`${lc}[TEST DEBUG] res.data.latestAddrsMap: ${JSON.stringify(res.data.latestAddrsMap)} (I: a8e128bdf80898ac2e6d8021a5bff726)`); }
429
425
  return res.data.latestAddrsMap;
@@ -477,7 +473,7 @@ export class SyncSagaCoordinator {
477
473
  }
478
474
  // Analyze Timelines & Stones
479
475
  const analysis = await this.analyzeDomainIbGibs({ domainIbGibs, space: localSpace });
480
- // if (logalot) { console.log(`${lc} analysis: ${pretty(analysis)}(I: cd00e2be5eccc8976879c888ff2dfb26)`); }
476
+ // if (logalot) { console.log(`${lc} analysis: ${pretty(analysis)}(I: cd00e2be5eccc8976879c888ff2dfb26)`); }
481
477
  const { timelinesMap: srcTimelinesMap, fullGraph, stones: srcStones, } = analysis;
482
478
  // we need to store the fullGraph in our tempSpace for later...
483
479
  await putInSpace({ ibGibs: Object.values(fullGraph), space: tempSpace });
@@ -516,7 +512,7 @@ export class SyncSagaCoordinator {
516
512
  localSpace,
517
513
  });
518
514
  // if (logalot) { console.log(`${lc} sagaFrame (init): ${pretty(sagaFrame)} (I: b3d6a8be69248f18713cc3073cb08626)`); }
519
- return { sagaFrame, initialDomainGraph: fullGraph };
515
+ return { initFrame: sagaFrame, initDomainGraph: fullGraph };
520
516
  }
521
517
  catch (error) {
522
518
  console.error(`${lc} ${extractErrorMsg(error)}`);
@@ -606,8 +602,8 @@ export class SyncSagaCoordinator {
606
602
  *
607
603
  * This is a one-off on the receiver.
608
604
  */
609
- async handleSagaContext({ sagaContext, mySpace, myTempSpace, identity, identitySecret, metaspace, }) {
610
- const lc = `${this.lc}[${this.handleSagaContext.name}]`;
605
+ async handleResponseSagaContext({ sagaContext, mySpace, myTempSpace, identity, identitySecret, metaspace, }) {
606
+ const lc = `${this.lc}[${this.handleResponseSagaContext.name}]`;
611
607
  try {
612
608
  if (logalot) {
613
609
  console.log(`${lc} starting... (I: 5deec8a1f7a6d263c88cd458ad990826)`);
@@ -628,9 +624,10 @@ export class SyncSagaCoordinator {
628
624
  * don't like this name, need to refactor
629
625
  */
630
626
  const srcGraph = toFlatGraph({ ibGibs: sagaContext.payloadIbGibsDomain }) ?? {};
627
+ let nextFrameInfo;
631
628
  switch (stage) {
632
629
  case SyncStage.init:
633
- return await this.handleInitFrame({
630
+ nextFrameInfo = await this.handleInitFrame({
634
631
  sagaIbGib,
635
632
  messageData: messageData,
636
633
  metaspace,
@@ -639,19 +636,25 @@ export class SyncSagaCoordinator {
639
636
  identity,
640
637
  identitySecret
641
638
  });
639
+ break;
642
640
  case SyncStage.ack:
643
- return await this.handleAckFrame({ sagaIbGib, srcGraph, metaspace, destSpace: mySpace, tempSpace: myTempSpace, identity });
641
+ nextFrameInfo = await this.handleAckFrame({ sagaIbGib, srcGraph, metaspace, destSpace: mySpace, tempSpace: myTempSpace, identity });
642
+ break;
644
643
  case SyncStage.delta:
645
- return await this.handleDeltaFrame({ sagaIbGib, srcGraph, metaspace, destSpace: mySpace, tempSpace: myTempSpace, identity, });
644
+ nextFrameInfo = await this.handleDeltaFrame({ sagaIbGib, srcGraph, metaspace, destSpace: mySpace, tempSpace: myTempSpace, identity, });
645
+ break;
646
646
  case SyncStage.commit:
647
- return await this.handleCommitFrame({ sagaIbGib, metaspace, destSpace: mySpace, tempSpace: myTempSpace, identity, });
647
+ nextFrameInfo = await this.handleCommitFrame({ sagaIbGib, metaspace, destSpace: mySpace, tempSpace: myTempSpace, identity, });
648
+ break;
648
649
  default:
649
650
  throw new Error(`${lc} (UNEXPECTED) Unknown sync stage: ${stage} (E: 9c2b4c8a6d34469f8263544710183355)`);
650
651
  }
652
+ return { errorMsg: undefined, nextFrameInfo, };
651
653
  }
652
654
  catch (error) {
653
- console.error(`${lc} ${extractErrorMsg(error)}`);
654
- throw error;
655
+ const errorMsg = `${lc} ${extractErrorMsg(error)}`;
656
+ console.error(errorMsg);
657
+ return { errorMsg };
655
658
  }
656
659
  finally {
657
660
  if (logalot) {
@@ -680,14 +683,11 @@ export class SyncSagaCoordinator {
680
683
  if (logalot) {
681
684
  console.log(`${lc} starting... (I: 9d88dcad0408c029e898a4bcf3b08426)`);
682
685
  }
683
- console.log(`${lc} [TEST DEBUG] Received destSpace: ${mySpace.data?.name || mySpace.ib} (uuid: ${mySpace.data?.uuid || '[no uuid]'})`);
684
- if (logalot) {
685
- console.log(`${lc} starting...`);
686
- }
686
+ console.log(`${lc} [TEST DEBUG] Receiver mySpace: ${mySpace.ib}`);
687
687
  // Extract Init Data
688
688
  const initData = messageData; // Using renamed variable for clarity
689
689
  if (initData.stage !== SyncStage.init) {
690
- throw new Error(`${lc} Invalid init frame: initData.stage !== SyncStage.init (E: 8a2b3c4d5e6f7g8h)`);
690
+ throw new Error(`${lc} Invalid init frame: initData.stage !== SyncStage.init (E: c91be82970e4decc58f56bf8fc1ffc26)`);
691
691
  }
692
692
  // if (logalot) { console.log(`${lc} initData: ${pretty(initData)} (I: 46b0f8441b96ad7a388f1ce3239dd826)`); }
693
693
  if (!initData || !initData.knowledgeVector) {
@@ -697,8 +697,8 @@ export class SyncSagaCoordinator {
697
697
  const conflictStrategy = sagaIbGib.data.conflictStrategy || SyncConflictStrategy.abort;
698
698
  // 2. Gap Analysis
699
699
  const conflicts = [];
700
- const deltaReqAddrs = [];
701
- const pushOfferAddrs = [];
700
+ const deltaRequestAddrInfos = [];
701
+ const pushOfferInfos = [];
702
702
  // First do the consant stones (Non-TJPs)
703
703
  const stones = initData.stones || [];
704
704
  if (stones.length > 0) {
@@ -717,14 +717,14 @@ export class SyncSagaCoordinator {
717
717
  console.log(`${lc} stones missing (requesting): ${addrsNotFound.length}`);
718
718
  }
719
719
  addrsNotFound.forEach(addr => {
720
- if (!deltaReqAddrs.includes(addr)) {
721
- deltaReqAddrs.push(addr);
720
+ if (!deltaRequestAddrInfos.some(x => x.addr === addr)) {
721
+ deltaRequestAddrInfos.push({ addr }); // no tjpAddr
722
722
  }
723
723
  });
724
724
  }
725
725
  }
726
726
  /**
727
- * "remote" local to receiver's context is the sender
727
+ * "remote" is sender in this case
728
728
  */
729
729
  const remoteKV = initData.knowledgeVector;
730
730
  if (logalot) {
@@ -736,7 +736,7 @@ export class SyncSagaCoordinator {
736
736
  console.log(`${lc} remoteTjps: ${pretty(remoteTjps)} (I: 86ea4c53db0dc184c8b253386c402126)`);
737
737
  }
738
738
  // 1. Get Local Latest Addrs for all TJPs
739
- let localKV = {};
739
+ let localLatestAddrsMap = {};
740
740
  if (remoteTjps.length > 0) {
741
741
  // Batch get latest addrs for the TJPs
742
742
  const resGetLatestAddrs = await getLatestAddrs({
@@ -749,52 +749,88 @@ export class SyncSagaCoordinator {
749
749
  if (!resGetLatestAddrs.data.latestAddrsMap) {
750
750
  throw new Error(`(UNEXPECTED) resGetLatestAddrs.data.latestAddrsMap falsy? (E: 16bc386dd51d0ff53a49620b1e641826)`);
751
751
  }
752
- localKV = resGetLatestAddrs.data.latestAddrsMap;
753
- console.log(`${lc} [TEST DEBUG] localKV: ${JSON.stringify(localKV)}`);
752
+ localLatestAddrsMap = resGetLatestAddrs.data.latestAddrsMap;
753
+ console.log(`${lc} [TEST DEBUG] localKV: ${JSON.stringify(localLatestAddrsMap)}`);
754
754
  if (logalot) {
755
- console.log(`${lc} localKV: ${pretty(localKV)} (I: 980975642cbccd8018cf0cd808d30826)`);
755
+ console.log(`${lc} localKV: ${pretty(localLatestAddrsMap)} (I: 980975642cbccd8018cf0cd808d30826)`);
756
756
  }
757
757
  }
758
758
  // 2. Gap Analysis
759
759
  for (const tjp of remoteTjps) {
760
760
  const remoteAddr = remoteKV[tjp];
761
- const localAddr = localKV[tjp];
761
+ const localAddr = localLatestAddrsMap[tjp];
762
762
  if (!localAddr) {
763
763
  // We (Receiver) don't have this timeline at all. Request it.
764
764
  console.log(`${lc} [TEST DEBUG] Missing local timeline for TJP: ${tjp}. Requesting remoteAddr: ${remoteAddr}`);
765
- deltaReqAddrs.push(remoteAddr);
765
+ deltaRequestAddrInfos.push({
766
+ addr: remoteAddr,
767
+ tjpAddr: tjp,
768
+ // we don't have this timeline at all
769
+ // latestAddrAlreadyHave: undefined
770
+ });
766
771
  continue;
767
772
  }
773
+ // we do have this timeline...
768
774
  if (localAddr === remoteAddr) {
769
- // Synced
775
+ // ...already synced
770
776
  console.log(`${lc} [TEST DEBUG] TJP ${tjp}: Synced (localAddr === remoteAddr)`);
771
777
  continue;
772
778
  }
773
779
  console.log(`${lc} [TEST DEBUG] TJP ${tjp}: localAddr=${localAddr}, remoteAddr=${remoteAddr} - checking for divergence...`);
774
- // Check if Remote is in Local's PAST (Local is Ahead -> Push Offer)
775
- // (Sender has older version, Receiver has newer) -> Receiver Offers Push
776
- const isRemoteInPast = await isPastFrame({
780
+ // we have this timeline but it's not synced...
781
+ // We're executing on receiver. Check if Remote (Sender) is in
782
+ // our past, and if so, we are ahead and need to push the delta
783
+ // to remote
784
+ const remoteIsInPast = await isPastFrame({
777
785
  olderAddr: remoteAddr,
778
786
  newerAddr: localAddr,
779
787
  space: mySpace,
780
788
  });
781
- if (isRemoteInPast) {
782
- console.log(`${lc} [TEST DEBUG] TJP ${tjp}: Remote is in past - offering push`);
783
- pushOfferAddrs.push(localAddr);
789
+ if (remoteIsInPast) {
790
+ // we're ahead, so push the delta of what the sender doesn't
791
+ // have (we have full knowledge)
792
+ console.log(`${lc} [TEST DEBUG] TJP ${tjp}: Remote (sender) is in past - offering push`);
793
+ const deltaGraph = await getDeltaDependencyGraph({
794
+ ibGibAddr: localAddr,
795
+ live: false, // always live: false right?
796
+ latestCommonFrameAddr: remoteAddr,
797
+ space: mySpace,
798
+ });
799
+ pushOfferInfos.push({ tjpAddr: tjp, addrs: Object.keys(deltaGraph), });
784
800
  }
785
801
  else {
786
- // Remote is not in our past.
787
- // Either Remote is ahead (Fast-Backward) OR Diverged.
802
+ // Remote tip is not in our past. So, either Remote is
803
+ // ahead (we're in THEIR past, i.e., Fast-Backward) OR
804
+ // Diverged/conflict (we've both made edits).
788
805
  // Check if Local is in Remote's PAST (Remote is Ahead -> Delta Request)
789
- const isLocalInPast = await isPastFrame({
790
- olderAddr: localAddr,
791
- newerAddr: remoteAddr,
792
- space: mySpace,
793
- });
794
- if (isLocalInPast) {
806
+ /**
807
+ * we could first check for existence of remoteAddr in
808
+ * mySpace, but this is quick and easy. If it throws, we
809
+ * don't have it so it can't be in the past.
810
+ */
811
+ let localIsInPast = false;
812
+ try {
813
+ // we could
814
+ localIsInPast = await isPastFrame({
815
+ olderAddr: localAddr,
816
+ newerAddr: remoteAddr,
817
+ space: mySpace,
818
+ });
819
+ }
820
+ catch (error) {
821
+ // couldn't get one of them, so localIsInPast remains false.
822
+ if (logalot) {
823
+ console.log(`${lc} expected error if we don't have remote. verbose logging error though: ${extractErrorMsg(error)} (I: 47ea08d0b418cf4aa8a502a7bcb80826)`);
824
+ }
825
+ }
826
+ if (localIsInPast) {
795
827
  // Fast-Forward: We update to remote's tip.
796
828
  console.log(`${lc} [TEST DEBUG] TJP ${tjp}: Local is in past - requesting delta`);
797
- deltaReqAddrs.push(remoteAddr);
829
+ deltaRequestAddrInfos.push({
830
+ addr: remoteAddr,
831
+ tjpAddr: tjp,
832
+ latestAddrAlreadyHave: localAddr,
833
+ });
798
834
  }
799
835
  else {
800
836
  // DIVERGENCE: Both have changes the other doesn't know about.
@@ -814,7 +850,7 @@ export class SyncSagaCoordinator {
814
850
  });
815
851
  }
816
852
  else if (conflictStrategy === 'optimistic') {
817
- // Optimistic: We want to resolving this.
853
+ // Optimistic: We want resolve this.
818
854
  // We need to send our history to the Sender so they can Merge.
819
855
  // Fetch Full History for Local Timeline
820
856
  // Note: We might optimize this to only send "recent" history if we had a KV?
@@ -825,11 +861,11 @@ export class SyncSagaCoordinator {
825
861
  // We have localAddr.
826
862
  const resLocalTip = await getFromSpace({ space: mySpace, addr: localAddr });
827
863
  if (!resLocalTip.success || resLocalTip.ibGibs?.length !== 1) {
828
- throw new Error(`couldn't get local tip (${localAddr}) from space (${mySpace.ib}) (E: ff06ff849fa8e8dba32ce09807411226)`);
864
+ throw new Error(`couldn't get local tip (${localAddr}) from space (${mySpace.ib}) (E: 83cb88a767e22bbda99c6788bec50526)`);
829
865
  }
830
866
  const localTip = resLocalTip.ibGibs[0];
831
867
  if (!localTip) {
832
- throw new Error(`${lc} Failed to load local tip for conflict resolution. (E: 8f9b2c3d4e5f6g7h)`);
868
+ throw new Error(`${lc} Failed to load local tip for conflict resolution. (E: c39448ad6b3a72af78339ad877a56826)`);
833
869
  }
834
870
  const timelineAddrs = [...(localTip.rel8ns?.past ?? []), localAddr];
835
871
  conflicts.push({
@@ -842,7 +878,7 @@ export class SyncSagaCoordinator {
842
878
  });
843
879
  }
844
880
  else {
845
- throw new Error(`${lc} Unsupported conflict strategy: ${conflictStrategy} (E: 2a9b3c4d5e6f7g8h9i0j)`);
881
+ throw new Error(`${lc} Unsupported conflict strategy: ${conflictStrategy}. Only these currently implemented: ${SYNC_CONFLICT_STRATEGY_VALID_VALUES} (E: 8f12384180f8a718a983a749fe0adf26)`);
846
882
  }
847
883
  }
848
884
  }
@@ -856,51 +892,17 @@ export class SyncSagaCoordinator {
856
892
  }
857
893
  throw new Error(`the saga has terminal conflicts. conflicts: ${JSON.stringify(conflicts)} (E: f2edbe93cc07a63b38bfc013d2213b26)`);
858
894
  }
859
- // 3. Build Knowledge Vector (Full History for known timelines)
860
- // [NEW] Smart Diff
861
- // We iterate over all relevant addresses (deltas we are requesting OR push offers we might have newer versions of).
862
- // Since we are "reacting" to Init, we primarily want to tell the Sender what we DO have for the things they talked about.
863
- /**
864
- * we will put this in {@link SyncSagaMessageAckData_V1.knowledgeVector}
865
- */
866
- const knowledgeVector = {};
867
- // [Smart Diff] Populate knowledge from timelines identified by Sender
868
- for (const tjp of remoteTjps) {
869
- const localAddr = localKV[tjp];
870
- if (localAddr) {
871
- const res = await getFromSpace({ addr: localAddr, space: mySpace });
872
- if (res.success && res.ibGibs?.[0]) {
873
- const ibGib = res.ibGibs[0];
874
- const realTjp = ibGib.rel8ns?.tjp?.[0] || getIbGibAddr({ ibGib }); // Should match `tjp` if normalized
875
- if (!knowledgeVector[realTjp]) {
876
- const past = ibGib.rel8ns?.past || [];
877
- knowledgeVector[realTjp] = [getIbGibAddr({ ibGib }), ...past];
878
- }
879
- }
880
- }
881
- }
882
- // Also populate from `knowledgeVector` in Init if we want bidirectional?
883
- // No, `Init` doesn't have `knowledgeVector` in `SyncSagaMessageInitData` yet (it has `SyncInitData` generic props).
884
- // Let's assume standard flow:
885
- // 1. Sender says "I have X"
886
- // 2. Receiver says "I don't have X. But if I did have Y (ancestor), I'd tell you."
887
- // Problem: Receiver doesn't know X is related to Y without X.
888
- // SOLUTION:
889
- // The *Sender* must include TJP mappings or we rely on `knowledgeVector` in `Init`?
890
- // `SyncSagaMessageInitData_V1` extends `SyncInitData`.
891
- // `SyncInitData` has `knowledgeVector`.
892
- // If Sender populates `knowledgeVector` in `Init`, Receiver can use keys (TJPs) to look up its own state!
893
- // Let's implement Sender populating `Init.knowledgeVector`.
894
- // But `SyncSagaCoordinator.startSaga` creates Init.
895
895
  // 3. Create Ack Frame
896
+ if (!sagaIbGib.data) {
897
+ throw new Error(`(UNEXPECTED) sagaIbGib.data falsy? (E: 24203af4600fb226ae6c1afbde442826)`);
898
+ }
896
899
  const sagaId = sagaIbGib.data.uuid;
897
900
  // Create Payload Stone
898
901
  const ackData = {
899
902
  sagaId,
900
903
  stage: SyncStage.ack,
901
- deltaReqAddrs,
902
- pushOfferAddrs,
903
- knowledgeVector,
904
+ deltaRequestAddrInfos,
905
+ pushOfferInfos,
904
906
  };
905
907
  if (conflicts?.length > 0) {
906
908
  ackData.conflicts = conflicts;
@@ -927,13 +929,68 @@ export class SyncSagaCoordinator {
927
929
  * offers. an ack frame's payloads, if any, are those push offers
928
930
  */
929
931
  // let payloadIbGibsDomain: IbGib_V1[] | undefined = await getPushOffers
930
- if (pushOfferAddrs.length > 0) {
931
- }
932
- return {
933
- frame: ackFrame,
934
- // conflictInfos,
935
- // payloadIbGibsDomain,
936
- };
932
+ let payloadIbGibsDomain;
933
+ if (pushOfferInfos.length > 0) {
934
+ const searchSecondSpaceAddrs = [];
935
+ payloadIbGibsDomain = [];
936
+ const domainAddrs = pushOfferInfos.flatMap(x => x.addrs);
937
+ const resGet = await getFromSpace({ addrs: domainAddrs, space: mySpace, });
938
+ const resGetRawData = resGet.rawResultIbGib?.data;
939
+ if (!resGetRawData) {
940
+ throw new Error(`(UNEXPECTED) resGet.rawResultIbGib.data falsy? (E: 1a2cc8cb99a1ffa60837e45a8229b826)`);
941
+ }
942
+ const addrsNotFound = resGetRawData.addrsNotFound ?? [];
943
+ const addrsErrored = resGetRawData.addrsErrored ?? [];
944
+ if (resGet.ibGibs && resGet.ibGibs.length === domainAddrs.length) {
945
+ // found all of them
946
+ resGet.ibGibs.forEach(x => { payloadIbGibsDomain.push(x); });
947
+ }
948
+ else if (resGet.ibGibs && resGet.ibGibs.length > 0) {
949
+ // found some of them
950
+ resGet.ibGibs.forEach(x => { payloadIbGibsDomain.push(x); });
951
+ const foundPlusNotFoundCount = payloadIbGibsDomain.length +
952
+ addrsNotFound.length +
953
+ addrsErrored.length;
954
+ if (foundPlusNotFoundCount === domainAddrs.length) {
955
+ // we can still conceivably get the remaining addrs
956
+ addrsNotFound.forEach(x => searchSecondSpaceAddrs.push(x));
957
+ addrsErrored.forEach(x => searchSecondSpaceAddrs.push(x));
958
+ }
959
+ else if (addrsNotFound.length === 0 && addrsErrored.length === 0) {
960
+ throw new Error(`(UNEXPECTED) found some but not all addrs but addrsNotFound and addrsErrored both empty? (E: ef1b2cf5bab8de2298ec507abe04e826)`);
961
+ }
962
+ else {
963
+ throw new Error(`(UNEXPECTED) found some but not all addrs but addrsNotFound and addrsErrored don't contain the addrs not found? (E: ae9e015109f8c3c3a813da584cd98826)`);
964
+ }
965
+ }
966
+ else {
967
+ // found none of them(?)
968
+ console.warn(`${lc} we were expecting all domainAddrs in mySpace (${mySpace.ib}) but we couldn't get all of them. addrsNotFound: ${addrsNotFound ?? []}. addrsErrored: ${addrsErrored ?? []}. Trying temp space (${myTempSpace.ib}). (W: f61908e264f8dddd2e3fb9084463d826)`);
969
+ domainAddrs.forEach(x => searchSecondSpaceAddrs.push(x));
970
+ }
971
+ if (searchSecondSpaceAddrs.length > 0) {
972
+ if (logalot) {
973
+ console.log(`${lc} couldn't get all addrs in mySpace (${mySpace.ib}). searchSecondSpaceAddrs: ${searchSecondSpaceAddrs} (I: 233fd954dbd84e51bca02fa8eed5f826)`);
974
+ }
975
+ const resGet2 = await getFromSpace({ addrs: searchSecondSpaceAddrs, space: myTempSpace, });
976
+ if (resGet2.success && resGet2.ibGibs && resGet2.ibGibs.length === searchSecondSpaceAddrs.length) {
977
+ // got them all the second try
978
+ resGet2.ibGibs.forEach(x => payloadIbGibsDomain.push(x));
979
+ }
980
+ else {
981
+ resGet2.ibGibs?.forEach(x => payloadIbGibsDomain.push(x));
982
+ const addrsFailed = domainAddrs.filter(x => !payloadIbGibsDomain.map(pid => getIbGibAddr({ ibGib: pid })).includes(x));
983
+ throw new Error(`couldn't get some or all of addrs from either mySpace (${mySpace.ib}) or myTempSpace (${myTempSpace.ib}). addrsFailed: ${addrsFailed} (E: 1394d412c4ffa4dd085f269b43338826)`);
984
+ }
985
+ }
986
+ // we have now populated payloadIbGibsDomain
987
+ }
988
+ throw new Error(`not implemented (E: ed3f98abb0988c5ae8038bb8d741fb26)`);
989
+ // return {
990
+ // frame: ackFrame,
991
+ // // conflictInfos,
992
+ // payloadIbGibsDomain,
993
+ // };
937
994
  }
938
995
  catch (error) {
939
996
  console.error(`${lc} ${extractErrorMsg(error)}`);
@@ -985,7 +1042,7 @@ export class SyncSagaCoordinator {
985
1042
  console.warn(`${lc} Received terminal conflicts from Ack: ${JSON.stringify(terminalConflicts)}`);
986
1043
  // Terminal failure. Sender should probably Commit(Fail) or just Abort.
987
1044
  // For now, throw to trigger abort.
988
- throw new Error(`${lc} Peer reported terminal conflicts. (E: a1b2c3d4e5f6g7h8i9j0k)`);
1045
+ throw new Error(`${lc} Peer reported terminal conflicts. (E: 23a0096ee05a2ccfa89334e8f156b426)`);
989
1046
  }
990
1047
  const optimisticConflicts = conflicts.filter(c => !c.terminal);
991
1048
  const mergeDeltaReqs = []; // Additional requests for merging
@@ -1007,7 +1064,7 @@ export class SyncSagaCoordinator {
1007
1064
  // Or can we send a 'Delta Request' frame?
1008
1065
  // Standard Saga: Init(Push) -> Ack(Pull Reqs) -> Delta(Push Data).
1009
1066
  // If Sender needs data, we might need a "Reverse Delta" or "Pull" phase?
1010
- // Or we just proceed to Delta (sending what Receiver wants),
1067
+ // Or we just proceed to Delta (sending what Receiver wants),
1011
1068
  // AND we piggyback our own requests?
1012
1069
  // OR: We treat the Conflict Resolution as a sub-saga or side-effect?
1013
1070
  // SIMPLIFICATION for V1:
@@ -1031,7 +1088,7 @@ export class SyncSagaCoordinator {
1031
1088
  const resSenderTip = await getFromSpace({ space: destSpace, addr: senderTip });
1032
1089
  const senderTipIbGib = resSenderTip.ibGibs?.[0];
1033
1090
  if (!senderTipIbGib) {
1034
- throw new Error(`${lc} Sender missing its own tip? ${senderTip} (E: 9c8d7e6f5g4h3i2j1k0l)`);
1091
+ throw new Error(`${lc} Sender missing its own tip? ${senderTip} (E: 832f3804645878869ee3c13714366726)`);
1035
1092
  }
1036
1093
  // Basic Diff: Find what Receiver has that we don't.
1037
1094
  // Actually, we need to traverse OUR past to find commonality.
@@ -1108,46 +1165,46 @@ export class SyncSagaCoordinator {
1108
1165
  console.log(`${lc} [CONFLICT DEBUG] No optimistic conflicts to process`);
1109
1166
  }
1110
1167
  // 2. Prepare Delta Payload (What Receiver Requesting + Our Conflict Logic)
1111
- const deltaReqAddrs = ackData.deltaReqAddrs || [];
1112
- const pushOfferAddrs = ackData.pushOfferAddrs || [];
1168
+ const deltaReqAddrs = ackData.deltaRequestAddrInfos || [];
1169
+ const pushOfferAddrs = ackData.pushOfferInfos || [];
1113
1170
  // 1. Process Push Offers (Pull Requests) (Naive: Accept all if missing)
1114
1171
  const pullReqAddrs = [];
1115
1172
  for (const addr of pushOfferAddrs) {
1116
- const existing = srcGraph[addr] || (await getFromSpace({ addr, space: destSpace })).ibGibs?.[0];
1117
- if (!existing) {
1118
- pullReqAddrs.push(addr);
1119
- }
1173
+ // const existing = srcGraph[addr] || (await getFromSpace({ addr, space: destSpace })).ibGibs?.[0];
1174
+ // if (!existing) {
1175
+ // pullReqAddrs.push(addr);
1176
+ // }
1120
1177
  }
1121
1178
  // 2. Process Delta Requests (Push Payload)
1122
1179
  // [NEW] Smart Diff: Use knowledgeVector to skip dependencies
1180
+ // const useThisFunction = getDeltaDependencyGraph({ ibGibAddr: '', latestCommonFrameAddr: '', space: })
1123
1181
  const skipAddrs = new Set();
1124
1182
  if (ackData.knowledgeVector) {
1125
1183
  Object.values(ackData.knowledgeVector).forEach(addrs => {
1126
- addrs.forEach(a => skipAddrs.add(a));
1184
+ // addrs.forEach(a => skipAddrs.add(a));
1127
1185
  });
1128
1186
  }
1129
1187
  const payloadIbGibs = [];
1130
1188
  // Gather all tips to sync first
1131
1189
  const tipsToSync = [];
1132
1190
  for (const addr of deltaReqAddrs) {
1133
- let ibGib = srcGraph[addr];
1134
- if (!ibGib) {
1135
- const res = await getFromSpace({ addr, space: destSpace });
1136
- if (res.ibGibs && res.ibGibs.length > 0) {
1137
- ibGib = res.ibGibs[0];
1138
- }
1139
- }
1140
- if (ibGib) {
1141
- tipsToSync.push(ibGib);
1142
- }
1143
- else {
1144
- throw new Error(`${lc} Requested addr not found: ${addr} (E: d41d59cff4a887f6414c3e92eabd8e26)`);
1145
- }
1191
+ // let ibGib = srcGraph[addr];
1192
+ // if (!ibGib) {
1193
+ // const res = await getFromSpace({ addr, space: destSpace });
1194
+ // if (res.ibGibs && res.ibGibs.length > 0) {
1195
+ // ibGib = res.ibGibs[0];
1196
+ // }
1197
+ // }
1198
+ // if (ibGib) {
1199
+ // tipsToSync.push(ibGib);
1200
+ // } else {
1201
+ // throw new Error(`${lc} Requested addr not found: ${addr} (E: d41d59cff4a887f6414c3e92eabd8e26)`);
1202
+ // }
1146
1203
  }
1147
1204
  // Calculate Dependency Graph for ALL tips, effectively utilizing common history
1148
1205
  // Pass skipAddrs to `getDependencyGraph` or gather manually.
1149
1206
  // `getDependencyGraph` takes a single ibGib.
1150
- // We can optimize by doing it for each tip and unioning the result?
1207
+ // We can optimize by doing it for each tip and unioning the result?
1151
1208
  // Or `graph-helper` could support `ibGibs: []`. It currently takes `ibGib`.
1152
1209
  // We will loop.
1153
1210
  const allDepsSet = new Set();
@@ -1219,7 +1276,8 @@ export class SyncSagaCoordinator {
1219
1276
  payloadIbGibsControl.push(identity);
1220
1277
  }
1221
1278
  // return { frame: deltaFrame, payloadIbGibsControl, payloadIbGibsDomain: payloadIbGibs };
1222
- return { frame: deltaFrame, payloadIbGibsDomain: payloadIbGibs };
1279
+ // return { frame: deltaFrame, payloadIbGibsDomain: payloadIbGibs };
1280
+ throw new Error(`not implemented (E: 62e1e2a408e8bfa2982b2f87e8843826)`);
1223
1281
  }
1224
1282
  catch (error) {
1225
1283
  console.error(`${lc} ${extractErrorMsg(error)}`);
@@ -1255,7 +1313,7 @@ export class SyncSagaCoordinator {
1255
1313
  throw new Error(`${lc} Invalid delta frame: deltaData.stage !== SyncStage.delta (E: 0c28c8d8f08a4421b8344e6727271421)`);
1256
1314
  }
1257
1315
  if (logalot) {
1258
- console.log(`${lc} deltaData: ${pretty(deltaData)} (I: 8d7e6f5g4h3i2j1k0l9m)`);
1316
+ console.log(`${lc} deltaData: ${pretty(deltaData)} (I: a76008681df458cfbcdc4848f825a826)`);
1259
1317
  }
1260
1318
  console.log(`${lc} [CONFLICT DEBUG] deltaData.payloadAddrs count: ${deltaData.payloadAddrs?.length || 0}`);
1261
1319
  const payloadAddrs = deltaData.payloadAddrs || [];
@@ -1264,8 +1322,8 @@ export class SyncSagaCoordinator {
1264
1322
  // 1. Process Received Payload (Ingest)
1265
1323
  const receivedPayloadIbGibs = [];
1266
1324
  if (payloadAddrs.length > 0) {
1267
- // We use `payloadAddrs` as the manifest.
1268
- // The ACTUAL collection of ibGibs should be available via `getFromSpace`
1325
+ // We use `payloadAddrs` as the manifest.
1326
+ // The ACTUAL collection of ibGibs should be available via `getFromSpace`
1269
1327
  // assuming the "Transport" layer put them there implicitly?
1270
1328
  // OR, if we are local-only, we just get them.
1271
1329
  // The `handleDeltaFrame` contract assumes data is reachable in `space`.
@@ -1290,7 +1348,7 @@ export class SyncSagaCoordinator {
1290
1348
  // Get the requested ibGib
1291
1349
  let ibGib = srcGraph[addr];
1292
1350
  if (!ibGib) {
1293
- const res = await getFromSpace({ addr, space: destSpace }); // Query from destSpace
1351
+ const res = await getFromSpace({ addr, space: destSpace }); // Query from destSpace
1294
1352
  if (res.ibGibs && res.ibGibs.length > 0) {
1295
1353
  ibGib = res.ibGibs[0];
1296
1354
  }
@@ -1376,7 +1434,7 @@ export class SyncSagaCoordinator {
1376
1434
  console.log(`${lc} [CONFLICT DEBUG] ReceiverTip found in tempSpace: ${!!resRecTip.ibGibs?.[0]}`);
1377
1435
  if (resRecTip.success && resRecTip.ibGibs?.[0]) {
1378
1436
  // We have the tip!
1379
- // Do we have the full history?
1437
+ // Do we have the full history?
1380
1438
  // `mergeDivergentTimelines` in `conflict-optimistic` will attempt to fetch history.
1381
1439
  // If we just ingested the missing pieces, `getFromSpace` inside `merge` should succeed.
1382
1440
  // Perform Merge!
@@ -1420,9 +1478,9 @@ export class SyncSagaCoordinator {
1420
1478
  payloadAddrs: outgoingPayload.map(p => getIbGibAddr({ ibGib: p })),
1421
1479
  requests: hasMyRequests ? myRequests : undefined,
1422
1480
  proposeCommit: !hasMyRequests // If we are sending data but have no requests, we VALIDATE PROPOSAL?
1423
- // Wait. If we send data, we are NOT committing yet.
1481
+ // Wait. If we send data, we are NOT committing yet.
1424
1482
  // We are sending data. The OTHER side must ingest it.
1425
- // So proposeCommit = true?
1483
+ // So proposeCommit = true?
1426
1484
  // "Here is the data. I'm done. If you are good, let's commit."
1427
1485
  // Yes.
1428
1486
  };
@@ -1448,7 +1506,8 @@ export class SyncSagaCoordinator {
1448
1506
  payloadIbGibsControl.push(identity);
1449
1507
  }
1450
1508
  // return { frame: deltaFrame, payloadIbGibsControl, payloadIbGibsDomain: outgoingPayload };
1451
- return { frame: deltaFrame, payloadIbGibsDomain: outgoingPayload };
1509
+ // return { frame: deltaFrame, payloadIbGibsDomain: outgoingPayload };
1510
+ throw new Error(`not implemented (E: 2b38a8afb6d84efcee5ab51673387826)`);
1452
1511
  }
1453
1512
  else {
1454
1513
  // We have nothing to send.
@@ -1477,7 +1536,8 @@ export class SyncSagaCoordinator {
1477
1536
  commitCtrlPayloads.push(identity);
1478
1537
  }
1479
1538
  // return { frame: commitFrame, payloadIbGibsControl: commitCtrlPayloads };
1480
- return { frame: commitFrame, };
1539
+ // return { frame: commitFrame, };
1540
+ throw new Error(`not implemented (E: dda1ddc63fdcadff06653298e0d04826)`);
1481
1541
  }
1482
1542
  else {
1483
1543
  // peer did NOT propose commit (maybe they just sent data/requests and didn't ready flag).
@@ -1531,7 +1591,8 @@ export class SyncSagaCoordinator {
1531
1591
  commitCtrlPayloads2.push(identity);
1532
1592
  }
1533
1593
  // return { frame: commitFrame, payloadIbGibsControl: commitCtrlPayloads2 };
1534
- return { frame: commitFrame, };
1594
+ // return { frame: commitFrame, };
1595
+ throw new Error(`not implemented (E: 27514878585889e531ef21f1abbef826)`);
1535
1596
  }
1536
1597
  // Build control payloads for delta propose
1537
1598
  const deltaCtrlPayloads = [deltaFrame, deltaStone];
@@ -1539,7 +1600,8 @@ export class SyncSagaCoordinator {
1539
1600
  deltaCtrlPayloads.push(identity);
1540
1601
  }
1541
1602
  // return { frame: deltaFrame, payloadIbGibsControl: deltaCtrlPayloads };
1542
- return { frame: deltaFrame, };
1603
+ // return { frame: deltaFrame, };
1604
+ throw new Error(`not implemented (E: ff35584696b6fcb3ad6dd7c5cade2f26)`);
1543
1605
  }
1544
1606
  }
1545
1607
  }
@@ -1559,7 +1621,8 @@ export class SyncSagaCoordinator {
1559
1621
  if (logalot) {
1560
1622
  console.log(`${lc} Peer committed. Finalizing saga locally. Saga Complete.`);
1561
1623
  }
1562
- return null;
1624
+ // return { responseWasNull: true };
1625
+ throw new Error(`not implemented (E: 4d7f878bcc45ad3dd9c4b8573f3aa826)`);
1563
1626
  }
1564
1627
  // #endregion Handlers
1565
1628
  async createSyncMsgStone({ data, localSpace, metaspace, }) {
@@ -1633,7 +1696,7 @@ export class SyncSagaCoordinator {
1633
1696
  if (sessionIdentity) {
1634
1697
  rel8nInfos.push({ rel8nName: 'identity', ibGibs: [sessionIdentity], });
1635
1698
  }
1636
- // remove the existing sync msg stones' addrs
1699
+ // remove the existing sync msg stones' addrs
1637
1700
  if (!prevSagaIbGib.rel8ns) {
1638
1701
  throw new Error(`(UNEXPECTED) prevSagaIbGib.rel8ns falsy? (E: 81375841aff85b1e48ea42ca218e6826)`);
1639
1702
  }