@ibgib/core-gib 0.1.23 → 0.1.26

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 (80) 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/common/other/ibgib-helper.d.mts +1 -1
  6. package/dist/common/other/ibgib-helper.d.mts.map +1 -1
  7. package/dist/common/other/ibgib-helper.mjs.map +1 -1
  8. package/dist/sync/graft-info/graft-info-helpers.mjs +2 -2
  9. package/dist/sync/graft-info/graft-info-helpers.mjs.map +1 -1
  10. package/dist/sync/sync-conflict.respec.mjs +10 -15
  11. package/dist/sync/sync-conflict.respec.mjs.map +1 -1
  12. package/dist/sync/sync-constants.d.mts +1 -0
  13. package/dist/sync/sync-constants.d.mts.map +1 -1
  14. package/dist/sync/sync-constants.mjs +1 -0
  15. package/dist/sync/sync-constants.mjs.map +1 -1
  16. package/dist/sync/sync-helpers.d.mts +5 -0
  17. package/dist/sync/sync-helpers.d.mts.map +1 -1
  18. package/dist/sync/sync-helpers.mjs +37 -1
  19. package/dist/sync/sync-helpers.mjs.map +1 -1
  20. package/dist/sync/sync-innerspace-constants.respec.mjs +10 -12
  21. package/dist/sync/sync-innerspace-constants.respec.mjs.map +1 -1
  22. package/dist/sync/sync-innerspace-deep-updates.respec.mjs +10 -12
  23. package/dist/sync/sync-innerspace-deep-updates.respec.mjs.map +1 -1
  24. package/dist/sync/sync-innerspace-dest-ahead.respec.mjs +10 -12
  25. package/dist/sync/sync-innerspace-dest-ahead.respec.mjs.map +1 -1
  26. package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs +9 -12
  27. package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs.map +1 -1
  28. package/dist/sync/sync-innerspace-partial-update.respec.mjs +9 -14
  29. package/dist/sync/sync-innerspace-partial-update.respec.mjs.map +1 -1
  30. package/dist/sync/sync-innerspace.respec.mjs +9 -12
  31. package/dist/sync/sync-innerspace.respec.mjs.map +1 -1
  32. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.d.mts +2 -0
  33. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.d.mts.map +1 -1
  34. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mjs +4 -0
  35. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mjs.map +1 -1
  36. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts +24 -13
  37. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts.map +1 -1
  38. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs +176 -76
  39. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs.map +1 -1
  40. package/dist/sync/sync-peer/sync-peer-types.d.mts +29 -6
  41. package/dist/sync/sync-peer/sync-peer-types.d.mts.map +1 -1
  42. package/dist/sync/sync-peer/sync-peer-v1.d.mts +38 -55
  43. package/dist/sync/sync-peer/sync-peer-v1.d.mts.map +1 -1
  44. package/dist/sync/sync-peer/sync-peer-v1.mjs +111 -244
  45. package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
  46. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts +32 -1
  47. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts.map +1 -1
  48. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs +96 -7
  49. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs.map +1 -1
  50. package/dist/sync/sync-saga-coordinator.d.mts +59 -13
  51. package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
  52. package/dist/sync/sync-saga-coordinator.mjs +446 -304
  53. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  54. package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts +51 -6
  55. package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts.map +1 -1
  56. package/dist/sync/sync-types.d.mts +35 -10
  57. package/dist/sync/sync-types.d.mts.map +1 -1
  58. package/dist/sync/sync-types.mjs +1 -2
  59. package/dist/sync/sync-types.mjs.map +1 -1
  60. package/package.json +1 -1
  61. package/src/common/other/graph-helper.mts +53 -0
  62. package/src/common/other/ibgib-helper.mts +1 -1
  63. package/src/sync/graft-info/graft-info-helpers.mts +3 -3
  64. package/src/sync/sync-conflict.respec.mts +10 -17
  65. package/src/sync/sync-constants.mts +1 -0
  66. package/src/sync/sync-helpers.mts +47 -7
  67. package/src/sync/sync-innerspace-constants.respec.mts +10 -12
  68. package/src/sync/sync-innerspace-deep-updates.respec.mts +10 -12
  69. package/src/sync/sync-innerspace-dest-ahead.respec.mts +10 -12
  70. package/src/sync/sync-innerspace-multiple-timelines.respec.mts +9 -12
  71. package/src/sync/sync-innerspace-partial-update.respec.mts +9 -14
  72. package/src/sync/sync-innerspace.respec.mts +9 -12
  73. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mts +7 -0
  74. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mts +200 -75
  75. package/src/sync/sync-peer/sync-peer-types.mts +35 -11
  76. package/src/sync/sync-peer/sync-peer-v1.mts +154 -257
  77. package/src/sync/sync-saga-context/sync-saga-context-helpers.mts +90 -13
  78. package/src/sync/sync-saga-coordinator.mts +536 -356
  79. package/src/sync/sync-saga-message/sync-saga-message-types.mts +56 -4
  80. 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)`);
@@ -143,6 +142,75 @@ export class SyncSagaCoordinator {
143
142
  done
144
143
  };
145
144
  }
145
+ /**
146
+ * This is what the receiving side of the sync calls to drive the FSM to the
147
+ * next stage.
148
+ *
149
+ * So whereas the sender executes a saga loop and drives the entire process,
150
+ * this is a reactive one-off that drives just the single step that the
151
+ * receiver does in that saga.
152
+ *
153
+ * @returns next context result if another round, else if commit returns
154
+ * null
155
+ */
156
+ async receiverContinueSync({ sagaContext, mySpace, myTempSpace, identity, identitySecret, metaspace, }) {
157
+ const lc = `${this.lc}[${this.receiverContinueSync.name}]`;
158
+ try {
159
+ if (logalot) {
160
+ console.log(`${lc} starting... (I: f64e08bf77d1425378601f380384ec26)`);
161
+ }
162
+ const contextResult = await this.handleResponseSagaContext({
163
+ sagaContext,
164
+ mySpace,
165
+ myTempSpace,
166
+ identity,
167
+ identitySecret,
168
+ metaspace,
169
+ });
170
+ if (!contextResult) {
171
+ if (logalot) {
172
+ console.log(`${lc} Handler returned null (Saga End). (I: 43da8bb6c846b1fe7766332643be0e26)`);
173
+ }
174
+ return null;
175
+ }
176
+ // #region error conditions throw
177
+ if (contextResult.errorMsg) {
178
+ throw new Error(`Couldn't handle response saga context. errorMsg: ${contextResult.errorMsg} (E: 7b41a183cf3cb58a5859c803800cf826)`);
179
+ }
180
+ else if (!contextResult.nextFrameInfo) {
181
+ throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo falsy? (E: 5740542f5eb8ccb41dfec188d87c1e26)`);
182
+ }
183
+ else if (contextResult.nextFrameInfo?.responseWasNull) {
184
+ throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo.responseWasNull? logic flow should not have gotten here. (E: ae06748d8c0c5e70c92322c8fb0cb426)`);
185
+ }
186
+ // #endregion error conditions throw
187
+ // create the return context
188
+ const { frame, payloadIbGibsDomain } = contextResult.nextFrameInfo;
189
+ const responseCtx = await createSyncSagaContext({
190
+ sagaFrame: frame,
191
+ localSpace: mySpace,
192
+ payloadIbGibsDomain,
193
+ // todo: we need to thoroughly go through the identity per each step after getting basic merging
194
+ sessionKeystones: identity ? [identity] : undefined, // ??
195
+ });
196
+ const immediateValidationErrors = await validateContextAndSagaFrame({
197
+ context: responseCtx,
198
+ });
199
+ if (immediateValidationErrors.length > 0) {
200
+ throw new Error(`(UNEXPECTED) just created sync saga context () and there were immediateValidationErrors? immediateValidationErrors: ${immediateValidationErrors} (E: c120e8e0aa98673d685267a8a36e5826)`);
201
+ }
202
+ return responseCtx;
203
+ }
204
+ catch (error) {
205
+ console.error(`${lc} ${extractErrorMsg(error)}`);
206
+ throw error;
207
+ }
208
+ finally {
209
+ if (logalot) {
210
+ console.log(`${lc} complete.`);
211
+ }
212
+ }
213
+ }
146
214
  async getSessionIdentity({ sagaId, metaspace, tempSpace, }) {
147
215
  const lc = `${this.lc}[${this.getSessionIdentity.name}]`;
148
216
  try {
@@ -189,45 +257,23 @@ export class SyncSagaCoordinator {
189
257
  * the NEXT request context.
190
258
  * When the Peer responds with data (in the response context), it is resolved and put into `tempSpace`.
191
259
  */
192
- async executeSagaLoop({ initialFrame, initialDomainGraph, peer, sessionIdentity, updates$, localSpace, tempSpace, metaspace }) {
260
+ async executeSagaLoop({ initFrame, initDomainGraph, peer, sessionIdentity, updates$, localSpace, tempSpace, metaspace }) {
193
261
  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)
262
+ /** The current frame we just generated (e.g., Init or Delta Request) */
263
+ let currentFrame = initFrame;
264
+ /** The **domain** payload we need to transmit (data we are sending) */
197
265
  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
266
  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)
267
+ // first, prepare for context transmission...
268
+ /**
269
+ * this is used later in pollForDomainPayloads **iif** payloads are
270
+ * received **in the response**, i.e., on the return trip. So if we
271
+ * request addrs, the response should have these addrs and their
272
+ * dependencies. The ibgibs corresponding to these addrs will be
273
+ * streamed and placed into this map.
274
+ */
230
275
  const domainPayloadsMap = new Map();
276
+ // #region set up peer observable for any domainPayloadsMap
231
277
  const sublc = `${lc}[peer.payloadIbGibsDomainReceived$]`;
232
278
  const subscription = await peer.payloadIbGibsDomainReceived$.subscribe(fnObs({
233
279
  next: async (ibgib) => {
@@ -256,38 +302,45 @@ export class SyncSagaCoordinator {
256
302
  await subscription.unsubscribe();
257
303
  },
258
304
  }));
259
- // Create the Request Context...
305
+ // #endregion set up peer observable for any domainPayloadsMap
306
+ // ...create/compose the Request Context itself...
260
307
  const requestCtx = await createSyncSagaContext({
261
308
  sagaFrame: currentFrame,
262
309
  sessionKeystones: sessionIdentity ? [sessionIdentity] : undefined,
263
310
  /**
264
311
  * init frame: empty
265
- *
312
+ * ack frame: possible push offers
313
+ * delta frame: requested ibgibs or commit offer
314
+ * commit frame: empty
266
315
  */
267
- payloadIbGibsDomain: nextDomainIbGibsAndDeps,
316
+ payloadIbGibsDomain: nextDomainIbGibs,
268
317
  localSpace,
269
318
  });
270
- // Log what we're sending
319
+ // #region Log what we're sending
271
320
  if (logalotControlDomain) {
272
- const domainAddrs = nextDomainIbGibsAndDeps.map(p => getIbGibAddr({ ibGib: p }));
273
- console.log(`${lc}${lcControlDomain} SENDER TRANSMIT -> peer.witness (I: b3c4d5e6f7a8b9c0)`);
321
+ const domainAddrs = nextDomainIbGibs.map(p => getIbGibAddr({ ibGib: p }));
322
+ console.log(`${lc}${lcControlDomain} SENDER TRANSMIT -> peer.witness (I: 5b0081803698770f0bf64992220b312)`);
274
323
  console.log(`${lc}${lcControlDomain} Context: ${getIbGibAddr({ ibGib: requestCtx })}`);
275
324
  console.log(`${lc}${lcControlDomain} Frame: ${getIbGibAddr({ ibGib: currentFrame })}`);
276
325
  console.log(`${lc}${lcControlDomain} DOMAIN Payloads (${domainAddrs.length}): ${domainAddrs.join(', ') || '(none)'}`);
277
326
  }
327
+ // #endregion Log what we're sending
278
328
  // update our saga listeners...
279
329
  // if (logalot) { console.log(`${lc} transmitting... requestCtx: ${pretty(requestCtx)} (I: 8cf20817c66899abdb1e76df50356826)`); }
280
- updates$.next(requestCtx); // spins off
281
- // ...And send the context
330
+ updates$.next(requestCtx); // spins off for saga UI updates
331
+ // ...And send the context.
332
+ peer.setOptionalOpts({ senderSpace: localSpace, senderTempSpace: tempSpace, });
282
333
  const responseCtx = await peer.witness(requestCtx);
283
- // C. Handle Response
334
+ // the send returned, but a peer can return a falsy responseCtx, if
335
+ // we just sent a commit to them and they're done. If so, there will
336
+ // necessarily be no payload to wait to receive
284
337
  if (!responseCtx) {
285
338
  if (currentFrame) {
286
339
  // Check for Commit (Peer silence expected)
287
340
  const msg = await getSyncSagaMessageFromFrame({ frameIbGib: currentFrame, space: localSpace });
288
341
  if (msg?.data?.stage === SyncStage.commit) {
289
342
  if (logalot) {
290
- console.log(`${lc} Sender sent Commit. Peer returned no response. Saga Complete.`);
343
+ console.log(`${lc} Sender sent Commit. Peer returned no response. Saga Complete. (I: 26f9ee073858ca78b8284753368b5226)`);
291
344
  }
292
345
  currentFrame = null;
293
346
  break;
@@ -300,19 +353,23 @@ export class SyncSagaCoordinator {
300
353
  throw new Error(`(UNEXPECTED) no response and currentFrame falsy? (E: 8d1085ea2f28cfc3f9c922649864a826)`);
301
354
  }
302
355
  }
303
- // ---------------------------------------------------------------------
304
- // 2d. HANDLE RESPONSE
305
- // ---------------------------------------------------------------------
306
- // at this point, we have received the response context ibgib, but
356
+ // at this point, we did indeed receive a response to analyze. BUT!
357
+ // we have only necessarily received the response context ibgib.
307
358
  // if there were payloads expected to be transferred, they may not
308
359
  // be done yet.
309
360
  if (!responseCtx.data) {
310
361
  throw new Error(`(UNEXPECTED) responseCtx.data falsy? (E: a969992bae53ab18a827ec58aec15826)`);
311
362
  }
312
- updates$.next(responseCtx); // spins off -- don't remove this comment!
363
+ updates$.next(responseCtx); // spins off for saga UI updating
364
+ // immediately validate context/saga frame (but not payloads because
365
+ // we may not have those yet)
366
+ const contextAndSagaFrameValidationErrors = await validateContextAndSagaFrame({ context: responseCtx });
367
+ if (contextAndSagaFrameValidationErrors.length > 0) {
368
+ throw new Error(`contextAndSagaFrameValidationErrors: ${contextAndSagaFrameValidationErrors} (E: 6eebe8e7fa437c00a8cde3ada3c66826)`);
369
+ }
313
370
  // Extract expected domain addresses from response context
314
371
  const responsePayloadAddrsDomain = responseCtx.data[SYNC_SAGA_PAYLOAD_ADDRS_DOMAIN] || [];
315
- // Poll for them if needed
372
+ // Poll for them if needed. see above jsdocs for domainPayloadsMap
316
373
  if (responsePayloadAddrsDomain.length > 0) {
317
374
  responseCtx.payloadIbGibsDomain = await this.pollForDomainPayloads({
318
375
  expectedAddrs: responsePayloadAddrsDomain,
@@ -321,49 +378,62 @@ export class SyncSagaCoordinator {
321
378
  tempSpace,
322
379
  });
323
380
  }
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
381
+ // #region Log what we received back
328
382
  if (!responseCtx.sagaFrame) {
329
383
  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
384
  }
331
385
  if (logalotControlDomain) {
332
386
  const responseControlAddrs = responseCtx.data?.['@payloadAddrsControl'] || [];
333
- console.log(`${lc}${lcControlDomain} SENDER RECEIVED <- peer.witness (I: c4d5e6f7a8b9c0d1)`);
387
+ console.log(`${lc}${lcControlDomain} SENDER RECEIVED <- peer.witness (I: 3dc76a9744d89a4fc3e2f076c2be4826)`);
334
388
  console.log(`${lc}${lcControlDomain} Response Context: ${getIbGibAddr({ ibGib: responseCtx })}`);
335
389
  console.log(`${lc}${lcControlDomain} Response Saga Frame: ${getIbGibAddr({ ibGib: responseCtx.sagaFrame })}`);
336
390
  console.log(`${lc}${lcControlDomain} CONTROL Payloads (${responseControlAddrs.length}): ${responseControlAddrs.join(', ') || '(none)'}`);
337
391
  console.log(`${lc}${lcControlDomain} DOMAIN Payloads (${responsePayloadAddrsDomain.length}): ${responsePayloadAddrsDomain.join(', ') || '(none)'}`);
338
392
  }
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({
393
+ // #endregion Log what we received back
394
+ // at this point, we have received the context AND **all** of the
395
+ // domain payloads (if applicable), so we are ready to do the next
396
+ // iteration in the saga loop
397
+ // this is the part that drives the FSM forward, i.e., when we
398
+ // evolve the sync saga ibgib itself to the next frame if we aren't
399
+ // finished/errored out.
400
+ const contextResult = await this.handleResponseSagaContext({
346
401
  sagaContext: responseCtx,
402
+ initDomainGraph,
347
403
  mySpace: localSpace,
348
404
  myTempSpace: tempSpace,
349
405
  metaspace,
350
406
  });
351
- if (!handleResult) {
407
+ if (!contextResult) {
352
408
  if (logalot) {
353
- console.log(`${lc} Handler returned null (Saga End).`);
409
+ console.log(`${lc} Handler returned null (Saga End). (I: faae22abc818ba9b28ac6d2881cd7826)`);
354
410
  }
355
411
  break;
356
412
  }
357
- currentFrame = handleResult.frame;
358
- // Collect next DOMAIN payloads for the NEXT request
359
- nextDomainIbGibs = [...(handleResult.payloadIbGibsDomain || [])];
360
- // Log handler output for next iteration
413
+ // #region error conditions throw
414
+ if (contextResult.errorMsg) {
415
+ throw new Error(`Couldn't handle response saga context. errorMsg: ${contextResult.errorMsg} (E: c948e81d513b2a0eb8b8afa878edc626)`);
416
+ }
417
+ else if (!contextResult.nextFrameInfo) {
418
+ throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo falsy? (E: c287a82e823e662a77923278e2418826)`);
419
+ }
420
+ else if (contextResult.nextFrameInfo?.responseWasNull) {
421
+ throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo.responseWasNull? logic flow should not have gotten here. (E: 104a32381db816b7183435e805b3d626)`);
422
+ }
423
+ // #endregion error conditions throw
424
+ // we have another frame to process and send out, with possibly
425
+ // payload domain ibgibs as well
426
+ const { frame, payloadIbGibsDomain, } = contextResult.nextFrameInfo;
427
+ currentFrame = frame;
428
+ nextDomainIbGibs = [...(payloadIbGibsDomain || [])];
429
+ // #region Log handler output for next iteration
361
430
  if (logalotControlDomain) {
362
431
  const handlerDomainAddrs = nextDomainIbGibs.map(p => getIbGibAddr({ ibGib: p }));
363
- console.log(`${lc}${lcControlDomain} HANDLER RESULT -> next iteration (I: d5e6f7a8b9c0d1e2)`);
432
+ console.log(`${lc}${lcControlDomain} HANDLER RESULT -> next iteration (I: 6b0d88c4c28857ccd812381515bd7826)`);
364
433
  console.log(`${lc}${lcControlDomain} Next Frame: ${getIbGibAddr({ ibGib: currentFrame })}`);
365
434
  console.log(`${lc}${lcControlDomain} DOMAIN for next (${handlerDomainAddrs.length}): ${handlerDomainAddrs.join(', ') || '(none)'}`);
366
435
  }
436
+ // #endregion Log handler output for next iteration
367
437
  }
368
438
  }
369
439
  /**
@@ -423,7 +493,7 @@ export class SyncSagaCoordinator {
423
493
  }
424
494
  const res = await getLatestAddrs({ space, tjpAddrs: tjps });
425
495
  if (!res.data || !res.data.latestAddrsMap) {
426
- throw new Error(`${lc} Failed to get latest addrs. (E: 7a8b9c0d)`);
496
+ throw new Error(`${lc} Failed to get latest addrs. (E: 7d395940c0e1419165c5196c39c6c826)`);
427
497
  }
428
498
  // if (false) { console.log(`${lc}[TEST DEBUG] res.data.latestAddrsMap: ${JSON.stringify(res.data.latestAddrsMap)} (I: a8e128bdf80898ac2e6d8021a5bff726)`); }
429
499
  return res.data.latestAddrsMap;
@@ -477,7 +547,7 @@ export class SyncSagaCoordinator {
477
547
  }
478
548
  // Analyze Timelines & Stones
479
549
  const analysis = await this.analyzeDomainIbGibs({ domainIbGibs, space: localSpace });
480
- // if (logalot) { console.log(`${lc} analysis: ${pretty(analysis)}(I: cd00e2be5eccc8976879c888ff2dfb26)`); }
550
+ // if (logalot) { console.log(`${lc} analysis: ${pretty(analysis)}(I: cd00e2be5eccc8976879c888ff2dfb26)`); }
481
551
  const { timelinesMap: srcTimelinesMap, fullGraph, stones: srcStones, } = analysis;
482
552
  // we need to store the fullGraph in our tempSpace for later...
483
553
  await putInSpace({ ibGibs: Object.values(fullGraph), space: tempSpace });
@@ -516,7 +586,7 @@ export class SyncSagaCoordinator {
516
586
  localSpace,
517
587
  });
518
588
  // if (logalot) { console.log(`${lc} sagaFrame (init): ${pretty(sagaFrame)} (I: b3d6a8be69248f18713cc3073cb08626)`); }
519
- return { sagaFrame, initialDomainGraph: fullGraph };
589
+ return { initFrame: sagaFrame, initDomainGraph: fullGraph };
520
590
  }
521
591
  catch (error) {
522
592
  console.error(`${lc} ${extractErrorMsg(error)}`);
@@ -588,6 +658,7 @@ export class SyncSagaCoordinator {
588
658
  }
589
659
  /**
590
660
  * This is the heart of the "ping pong" transaction, where we send a context
661
+ *
591
662
  * and receive a context. IOW, this drives the FSM of the sync saga ibgib as
592
663
  * a whole.
593
664
  *
@@ -606,8 +677,8 @@ export class SyncSagaCoordinator {
606
677
  *
607
678
  * This is a one-off on the receiver.
608
679
  */
609
- async handleSagaContext({ sagaContext, mySpace, myTempSpace, identity, identitySecret, metaspace, }) {
610
- const lc = `${this.lc}[${this.handleSagaContext.name}]`;
680
+ async handleResponseSagaContext({ sagaContext, initDomainGraph, mySpace, myTempSpace, identity, identitySecret, metaspace, }) {
681
+ const lc = `${this.lc}[${this.handleResponseSagaContext.name}]`;
611
682
  try {
612
683
  if (logalot) {
613
684
  console.log(`${lc} starting... (I: 5deec8a1f7a6d263c88cd458ad990826)`);
@@ -628,9 +699,10 @@ export class SyncSagaCoordinator {
628
699
  * don't like this name, need to refactor
629
700
  */
630
701
  const srcGraph = toFlatGraph({ ibGibs: sagaContext.payloadIbGibsDomain }) ?? {};
702
+ let nextFrameInfo;
631
703
  switch (stage) {
632
704
  case SyncStage.init:
633
- return await this.handleInitFrame({
705
+ nextFrameInfo = await this.handleInitFrame({
634
706
  sagaIbGib,
635
707
  messageData: messageData,
636
708
  metaspace,
@@ -639,19 +711,36 @@ export class SyncSagaCoordinator {
639
711
  identity,
640
712
  identitySecret
641
713
  });
714
+ break;
642
715
  case SyncStage.ack:
643
- return await this.handleAckFrame({ sagaIbGib, srcGraph, metaspace, destSpace: mySpace, tempSpace: myTempSpace, identity });
716
+ if (!initDomainGraph) {
717
+ throw new Error(`(UNEXPECTED) initDomainGraph falsy on the sender? (E: a3d758ad954829aba88663188eafc826)`);
718
+ }
719
+ nextFrameInfo = await this.handleAckFrame({
720
+ sagaIbGib,
721
+ srcGraph,
722
+ initDomainGraph,
723
+ metaspace,
724
+ destSpace: mySpace,
725
+ tempSpace: myTempSpace,
726
+ identity,
727
+ });
728
+ break;
644
729
  case SyncStage.delta:
645
- return await this.handleDeltaFrame({ sagaIbGib, srcGraph, metaspace, destSpace: mySpace, tempSpace: myTempSpace, identity, });
730
+ nextFrameInfo = await this.handleDeltaFrame({ sagaIbGib, srcGraph, metaspace, destSpace: mySpace, tempSpace: myTempSpace, identity, });
731
+ break;
646
732
  case SyncStage.commit:
647
- return await this.handleCommitFrame({ sagaIbGib, metaspace, destSpace: mySpace, tempSpace: myTempSpace, identity, });
733
+ nextFrameInfo = await this.handleCommitFrame({ sagaIbGib, metaspace, destSpace: mySpace, tempSpace: myTempSpace, identity, });
734
+ break;
648
735
  default:
649
736
  throw new Error(`${lc} (UNEXPECTED) Unknown sync stage: ${stage} (E: 9c2b4c8a6d34469f8263544710183355)`);
650
737
  }
738
+ return { errorMsg: undefined, nextFrameInfo, };
651
739
  }
652
740
  catch (error) {
653
- console.error(`${lc} ${extractErrorMsg(error)}`);
654
- throw error;
741
+ const errorMsg = `${lc} ${extractErrorMsg(error)}`;
742
+ console.error(errorMsg);
743
+ return { errorMsg };
655
744
  }
656
745
  finally {
657
746
  if (logalot) {
@@ -680,14 +769,11 @@ export class SyncSagaCoordinator {
680
769
  if (logalot) {
681
770
  console.log(`${lc} starting... (I: 9d88dcad0408c029e898a4bcf3b08426)`);
682
771
  }
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
- }
772
+ console.log(`${lc} [TEST DEBUG] Receiver mySpace: ${mySpace.ib}`);
687
773
  // Extract Init Data
688
774
  const initData = messageData; // Using renamed variable for clarity
689
775
  if (initData.stage !== SyncStage.init) {
690
- throw new Error(`${lc} Invalid init frame: initData.stage !== SyncStage.init (E: 8a2b3c4d5e6f7g8h)`);
776
+ throw new Error(`${lc} Invalid init frame: initData.stage !== SyncStage.init (E: c91be82970e4decc58f56bf8fc1ffc26)`);
691
777
  }
692
778
  // if (logalot) { console.log(`${lc} initData: ${pretty(initData)} (I: 46b0f8441b96ad7a388f1ce3239dd826)`); }
693
779
  if (!initData || !initData.knowledgeVector) {
@@ -697,8 +783,8 @@ export class SyncSagaCoordinator {
697
783
  const conflictStrategy = sagaIbGib.data.conflictStrategy || SyncConflictStrategy.abort;
698
784
  // 2. Gap Analysis
699
785
  const conflicts = [];
700
- const deltaReqAddrs = [];
701
- const pushOfferAddrs = [];
786
+ const deltaRequestAddrInfos = [];
787
+ const pushOfferInfos = [];
702
788
  // First do the consant stones (Non-TJPs)
703
789
  const stones = initData.stones || [];
704
790
  if (stones.length > 0) {
@@ -717,14 +803,14 @@ export class SyncSagaCoordinator {
717
803
  console.log(`${lc} stones missing (requesting): ${addrsNotFound.length}`);
718
804
  }
719
805
  addrsNotFound.forEach(addr => {
720
- if (!deltaReqAddrs.includes(addr)) {
721
- deltaReqAddrs.push(addr);
806
+ if (!deltaRequestAddrInfos.some(x => x.addr === addr)) {
807
+ deltaRequestAddrInfos.push({ addr }); // no tjpAddr
722
808
  }
723
809
  });
724
810
  }
725
811
  }
726
812
  /**
727
- * "remote" local to receiver's context is the sender
813
+ * "remote" is sender in this case
728
814
  */
729
815
  const remoteKV = initData.knowledgeVector;
730
816
  if (logalot) {
@@ -736,7 +822,7 @@ export class SyncSagaCoordinator {
736
822
  console.log(`${lc} remoteTjps: ${pretty(remoteTjps)} (I: 86ea4c53db0dc184c8b253386c402126)`);
737
823
  }
738
824
  // 1. Get Local Latest Addrs for all TJPs
739
- let localKV = {};
825
+ let localLatestAddrsMap = {};
740
826
  if (remoteTjps.length > 0) {
741
827
  // Batch get latest addrs for the TJPs
742
828
  const resGetLatestAddrs = await getLatestAddrs({
@@ -749,52 +835,88 @@ export class SyncSagaCoordinator {
749
835
  if (!resGetLatestAddrs.data.latestAddrsMap) {
750
836
  throw new Error(`(UNEXPECTED) resGetLatestAddrs.data.latestAddrsMap falsy? (E: 16bc386dd51d0ff53a49620b1e641826)`);
751
837
  }
752
- localKV = resGetLatestAddrs.data.latestAddrsMap;
753
- console.log(`${lc} [TEST DEBUG] localKV: ${JSON.stringify(localKV)}`);
838
+ localLatestAddrsMap = resGetLatestAddrs.data.latestAddrsMap;
839
+ console.log(`${lc} [TEST DEBUG] localKV: ${JSON.stringify(localLatestAddrsMap)}`);
754
840
  if (logalot) {
755
- console.log(`${lc} localKV: ${pretty(localKV)} (I: 980975642cbccd8018cf0cd808d30826)`);
841
+ console.log(`${lc} localKV: ${pretty(localLatestAddrsMap)} (I: 980975642cbccd8018cf0cd808d30826)`);
756
842
  }
757
843
  }
758
844
  // 2. Gap Analysis
759
845
  for (const tjp of remoteTjps) {
760
846
  const remoteAddr = remoteKV[tjp];
761
- const localAddr = localKV[tjp];
847
+ const localAddr = localLatestAddrsMap[tjp];
762
848
  if (!localAddr) {
763
849
  // We (Receiver) don't have this timeline at all. Request it.
764
850
  console.log(`${lc} [TEST DEBUG] Missing local timeline for TJP: ${tjp}. Requesting remoteAddr: ${remoteAddr}`);
765
- deltaReqAddrs.push(remoteAddr);
851
+ deltaRequestAddrInfos.push({
852
+ addr: remoteAddr,
853
+ tjpAddr: tjp,
854
+ // we don't have this timeline at all
855
+ // latestAddrAlreadyHave: undefined
856
+ });
766
857
  continue;
767
858
  }
859
+ // we do have this timeline...
768
860
  if (localAddr === remoteAddr) {
769
- // Synced
861
+ // ...already synced
770
862
  console.log(`${lc} [TEST DEBUG] TJP ${tjp}: Synced (localAddr === remoteAddr)`);
771
863
  continue;
772
864
  }
773
865
  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({
866
+ // we have this timeline but it's not synced...
867
+ // We're executing on receiver. Check if Remote (Sender) is in
868
+ // our past, and if so, we are ahead and need to push the delta
869
+ // to remote
870
+ const remoteIsInPast = await isPastFrame({
777
871
  olderAddr: remoteAddr,
778
872
  newerAddr: localAddr,
779
873
  space: mySpace,
780
874
  });
781
- if (isRemoteInPast) {
782
- console.log(`${lc} [TEST DEBUG] TJP ${tjp}: Remote is in past - offering push`);
783
- pushOfferAddrs.push(localAddr);
875
+ if (remoteIsInPast) {
876
+ // we're ahead, so push the delta of what the sender doesn't
877
+ // have (we have full knowledge)
878
+ console.log(`${lc} [TEST DEBUG] TJP ${tjp}: Remote (sender) is in past - offering push`);
879
+ const deltaGraph = await getDeltaDependencyGraph({
880
+ ibGibAddr: localAddr,
881
+ live: false, // always live: false right?
882
+ latestCommonFrameAddr: remoteAddr,
883
+ space: mySpace,
884
+ });
885
+ pushOfferInfos.push({ tjpAddr: tjp, addrs: Object.keys(deltaGraph), });
784
886
  }
785
887
  else {
786
- // Remote is not in our past.
787
- // Either Remote is ahead (Fast-Backward) OR Diverged.
888
+ // Remote tip is not in our past. So, either Remote is
889
+ // ahead (we're in THEIR past, i.e., Fast-Backward) OR
890
+ // Diverged/conflict (we've both made edits).
788
891
  // 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) {
892
+ /**
893
+ * we could first check for existence of remoteAddr in
894
+ * mySpace, but this is quick and easy. If it throws, we
895
+ * don't have it so it can't be in the past.
896
+ */
897
+ let localIsInPast = false;
898
+ try {
899
+ // we could
900
+ localIsInPast = await isPastFrame({
901
+ olderAddr: localAddr,
902
+ newerAddr: remoteAddr,
903
+ space: mySpace,
904
+ });
905
+ }
906
+ catch (error) {
907
+ // couldn't get one of them, so localIsInPast remains false.
908
+ if (logalot) {
909
+ console.log(`${lc} expected error if we don't have remote. verbose logging error though: ${extractErrorMsg(error)} (I: 47ea08d0b418cf4aa8a502a7bcb80826)`);
910
+ }
911
+ }
912
+ if (localIsInPast) {
795
913
  // Fast-Forward: We update to remote's tip.
796
914
  console.log(`${lc} [TEST DEBUG] TJP ${tjp}: Local is in past - requesting delta`);
797
- deltaReqAddrs.push(remoteAddr);
915
+ deltaRequestAddrInfos.push({
916
+ addr: remoteAddr,
917
+ tjpAddr: tjp,
918
+ latestAddrAlreadyHave: localAddr,
919
+ });
798
920
  }
799
921
  else {
800
922
  // DIVERGENCE: Both have changes the other doesn't know about.
@@ -814,7 +936,7 @@ export class SyncSagaCoordinator {
814
936
  });
815
937
  }
816
938
  else if (conflictStrategy === 'optimistic') {
817
- // Optimistic: We want to resolving this.
939
+ // Optimistic: We want resolve this.
818
940
  // We need to send our history to the Sender so they can Merge.
819
941
  // Fetch Full History for Local Timeline
820
942
  // Note: We might optimize this to only send "recent" history if we had a KV?
@@ -825,11 +947,11 @@ export class SyncSagaCoordinator {
825
947
  // We have localAddr.
826
948
  const resLocalTip = await getFromSpace({ space: mySpace, addr: localAddr });
827
949
  if (!resLocalTip.success || resLocalTip.ibGibs?.length !== 1) {
828
- throw new Error(`couldn't get local tip (${localAddr}) from space (${mySpace.ib}) (E: ff06ff849fa8e8dba32ce09807411226)`);
950
+ throw new Error(`couldn't get local tip (${localAddr}) from space (${mySpace.ib}) (E: 83cb88a767e22bbda99c6788bec50526)`);
829
951
  }
830
952
  const localTip = resLocalTip.ibGibs[0];
831
953
  if (!localTip) {
832
- throw new Error(`${lc} Failed to load local tip for conflict resolution. (E: 8f9b2c3d4e5f6g7h)`);
954
+ throw new Error(`${lc} Failed to load local tip for conflict resolution. (E: c39448ad6b3a72af78339ad877a56826)`);
833
955
  }
834
956
  const timelineAddrs = [...(localTip.rel8ns?.past ?? []), localAddr];
835
957
  conflicts.push({
@@ -842,7 +964,7 @@ export class SyncSagaCoordinator {
842
964
  });
843
965
  }
844
966
  else {
845
- throw new Error(`${lc} Unsupported conflict strategy: ${conflictStrategy} (E: 2a9b3c4d5e6f7g8h9i0j)`);
967
+ throw new Error(`${lc} Unsupported conflict strategy: ${conflictStrategy}. Only these currently implemented: ${SYNC_CONFLICT_STRATEGY_VALID_VALUES} (E: 8f12384180f8a718a983a749fe0adf26)`);
846
968
  }
847
969
  }
848
970
  }
@@ -856,51 +978,17 @@ export class SyncSagaCoordinator {
856
978
  }
857
979
  throw new Error(`the saga has terminal conflicts. conflicts: ${JSON.stringify(conflicts)} (E: f2edbe93cc07a63b38bfc013d2213b26)`);
858
980
  }
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
981
  // 3. Create Ack Frame
982
+ if (!sagaIbGib.data) {
983
+ throw new Error(`(UNEXPECTED) sagaIbGib.data falsy? (E: 24203af4600fb226ae6c1afbde442826)`);
984
+ }
896
985
  const sagaId = sagaIbGib.data.uuid;
897
986
  // Create Payload Stone
898
987
  const ackData = {
899
988
  sagaId,
900
989
  stage: SyncStage.ack,
901
- deltaReqAddrs,
902
- pushOfferAddrs,
903
- knowledgeVector,
990
+ deltaRequestAddrInfos,
991
+ pushOfferInfos,
904
992
  };
905
993
  if (conflicts?.length > 0) {
906
994
  ackData.conflicts = conflicts;
@@ -926,13 +1014,65 @@ export class SyncSagaCoordinator {
926
1014
  * we want to push ibgibs to the remote/sender if we have push
927
1015
  * offers. an ack frame's payloads, if any, are those push offers
928
1016
  */
929
- // let payloadIbGibsDomain: IbGib_V1[] | undefined = await getPushOffers
930
- if (pushOfferAddrs.length > 0) {
1017
+ let payloadIbGibsDomain;
1018
+ if (pushOfferInfos.length > 0) {
1019
+ const searchSecondSpaceAddrs = [];
1020
+ payloadIbGibsDomain = [];
1021
+ const domainAddrs = pushOfferInfos.flatMap(x => x.addrs);
1022
+ const resGet = await getFromSpace({ addrs: domainAddrs, space: mySpace, });
1023
+ const resGetRawData = resGet.rawResultIbGib?.data;
1024
+ if (!resGetRawData) {
1025
+ throw new Error(`(UNEXPECTED) resGet.rawResultIbGib.data falsy? (E: 1a2cc8cb99a1ffa60837e45a8229b826)`);
1026
+ }
1027
+ const addrsNotFound = resGetRawData.addrsNotFound ?? [];
1028
+ const addrsErrored = resGetRawData.addrsErrored ?? [];
1029
+ if (resGet.ibGibs && resGet.ibGibs.length === domainAddrs.length) {
1030
+ // found all of them
1031
+ resGet.ibGibs.forEach(x => { payloadIbGibsDomain.push(x); });
1032
+ }
1033
+ else if (resGet.ibGibs && resGet.ibGibs.length > 0) {
1034
+ // found some of them
1035
+ resGet.ibGibs.forEach(x => { payloadIbGibsDomain.push(x); });
1036
+ const foundPlusNotFoundCount = payloadIbGibsDomain.length +
1037
+ addrsNotFound.length +
1038
+ addrsErrored.length;
1039
+ if (foundPlusNotFoundCount === domainAddrs.length) {
1040
+ // we can still conceivably get the remaining addrs
1041
+ addrsNotFound.forEach(x => searchSecondSpaceAddrs.push(x));
1042
+ addrsErrored.forEach(x => searchSecondSpaceAddrs.push(x));
1043
+ }
1044
+ else if (addrsNotFound.length === 0 && addrsErrored.length === 0) {
1045
+ throw new Error(`(UNEXPECTED) found some but not all addrs but addrsNotFound and addrsErrored both empty? (E: ef1b2cf5bab8de2298ec507abe04e826)`);
1046
+ }
1047
+ else {
1048
+ throw new Error(`(UNEXPECTED) found some but not all addrs but addrsNotFound and addrsErrored don't contain the addrs not found? (E: ae9e015109f8c3c3a813da584cd98826)`);
1049
+ }
1050
+ }
1051
+ else {
1052
+ // found none of them(?)
1053
+ 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)`);
1054
+ domainAddrs.forEach(x => searchSecondSpaceAddrs.push(x));
1055
+ }
1056
+ if (searchSecondSpaceAddrs.length > 0) {
1057
+ if (logalot) {
1058
+ console.log(`${lc} couldn't get all addrs in mySpace (${mySpace.ib}). searchSecondSpaceAddrs: ${searchSecondSpaceAddrs} (I: 233fd954dbd84e51bca02fa8eed5f826)`);
1059
+ }
1060
+ const resGet2 = await getFromSpace({ addrs: searchSecondSpaceAddrs, space: myTempSpace, });
1061
+ if (resGet2.success && resGet2.ibGibs && resGet2.ibGibs.length === searchSecondSpaceAddrs.length) {
1062
+ // got them all the second try
1063
+ resGet2.ibGibs.forEach(x => payloadIbGibsDomain.push(x));
1064
+ }
1065
+ else {
1066
+ resGet2.ibGibs?.forEach(x => payloadIbGibsDomain.push(x));
1067
+ const addrsFailed = domainAddrs.filter(x => !payloadIbGibsDomain.map(pid => getIbGibAddr({ ibGib: pid })).includes(x));
1068
+ throw new Error(`couldn't get some or all of addrs from either mySpace (${mySpace.ib}) or myTempSpace (${myTempSpace.ib}). addrsFailed: ${addrsFailed} (E: 1394d412c4ffa4dd085f269b43338826)`);
1069
+ }
1070
+ }
1071
+ // we have now populated payloadIbGibsDomain
931
1072
  }
932
1073
  return {
933
1074
  frame: ackFrame,
934
- // conflictInfos,
935
- // payloadIbGibsDomain,
1075
+ payloadIbGibsDomain,
936
1076
  };
937
1077
  }
938
1078
  catch (error) {
@@ -957,7 +1097,7 @@ export class SyncSagaCoordinator {
957
1097
  *
958
1098
  * Returns a `Delta` frame.
959
1099
  */
960
- async handleAckFrame({ sagaIbGib, srcGraph, destSpace, tempSpace, metaspace, identity, }) {
1100
+ async handleAckFrame({ sagaIbGib, srcGraph, initDomainGraph, destSpace, tempSpace, metaspace, identity, }) {
961
1101
  const lc = `${this.lc}[${this.handleAckFrame.name}]`;
962
1102
  try {
963
1103
  if (logalot) {
@@ -985,12 +1125,12 @@ export class SyncSagaCoordinator {
985
1125
  console.warn(`${lc} Received terminal conflicts from Ack: ${JSON.stringify(terminalConflicts)}`);
986
1126
  // Terminal failure. Sender should probably Commit(Fail) or just Abort.
987
1127
  // For now, throw to trigger abort.
988
- throw new Error(`${lc} Peer reported terminal conflicts. (E: a1b2c3d4e5f6g7h8i9j0k)`);
1128
+ throw new Error(`${lc} Peer reported terminal conflicts. (E: 23a0096ee05a2ccfa89334e8f156b426)`);
989
1129
  }
990
- const optimisticConflicts = conflicts.filter(c => !c.terminal);
1130
+ // at this point, if we have conflicts, they are non-terminal
991
1131
  const mergeDeltaReqs = []; // Additional requests for merging
992
- if (optimisticConflicts.length > 0) {
993
- console.log(`${lc} [CONFLICT DEBUG] Processing ${optimisticConflicts.length} optimistic conflicts`);
1132
+ if (conflicts.length > 0) {
1133
+ console.log(`${lc} [CONFLICT DEBUG] Processing ${conflicts.length} non-terminal conflicts`);
994
1134
  // We need to resolve these.
995
1135
  // Strategy:
996
1136
  // 1. Analyze Divergence (Sender vs Receiver)
@@ -1007,7 +1147,7 @@ export class SyncSagaCoordinator {
1007
1147
  // Or can we send a 'Delta Request' frame?
1008
1148
  // Standard Saga: Init(Push) -> Ack(Pull Reqs) -> Delta(Push Data).
1009
1149
  // If Sender needs data, we might need a "Reverse Delta" or "Pull" phase?
1010
- // Or we just proceed to Delta (sending what Receiver wants),
1150
+ // Or we just proceed to Delta (sending what Receiver wants),
1011
1151
  // AND we piggyback our own requests?
1012
1152
  // OR: We treat the Conflict Resolution as a sub-saga or side-effect?
1013
1153
  // SIMPLIFICATION for V1:
@@ -1016,138 +1156,134 @@ export class SyncSagaCoordinator {
1016
1156
  // `peer.pull(addr)`?
1017
1157
  // Yes! The Coordinator has the `peer`.
1018
1158
  // Let's analyze and pull immediately.
1019
- for (const conflict of optimisticConflicts) {
1020
- const { timelineAddrs, localAddr: receiverTip, remoteAddr: senderTip } = conflict;
1021
- // Sender History
1022
- // We need our own history for this timeline.
1023
- // We know the 'senderTip' (remoteAddr in Ack).
1024
- // Sender should verify it has this tip.
1025
- // Compute Diffs
1026
- // We need to find `receiverOnly` addrs.
1027
- // Receiver sent us `timelineAddrs` (Full History).
1028
- const receiverHistorySet = new Set(timelineAddrs);
1029
- // We need our execution context's history for this senderTip.
1030
- // We can fetch valid 'past' from space.
1031
- const resSenderTip = await getFromSpace({ space: destSpace, addr: senderTip });
1032
- const senderTipIbGib = resSenderTip.ibGibs?.[0];
1033
- if (!senderTipIbGib) {
1034
- throw new Error(`${lc} Sender missing its own tip? ${senderTip} (E: 9c8d7e6f5g4h3i2j1k0l)`);
1035
- }
1036
- // Basic Diff: Find what Receiver has that we don't.
1037
- // Actually, we need to traverse OUR past to find commonality.
1038
- const senderHistory = [senderTip, ...(senderTipIbGib.rel8ns?.past || [])];
1039
- const receiverOnlyAddrs = timelineAddrs.filter(addr => !senderHistory.includes(addr));
1040
- if (receiverOnlyAddrs.length > 0) {
1041
- console.log(`${lc} [CONFLICT DEBUG] Found ${receiverOnlyAddrs.length} receiver-only frames - need to pull for merge`);
1042
- console.log(`${lc} [CONFLICT DEBUG] Receiver-only addrs:`, receiverOnlyAddrs);
1043
- // PULL these frames from Peer into Local Space
1044
- // (Validation: We trust peer for now / verification happens on put)
1045
- for (const addr of receiverOnlyAddrs) {
1046
- console.error(`${lc} [CONFLICT DEBUG] NOT IMPLEMENTED (E: e6bf1a9d2758c469bb2f97514062d826)`);
1047
- }
1048
- // Compute DELTA dependencies for each receiver-only frame
1049
- // Find LCA to determine what dependencies we already have
1050
- const lcaAddr = timelineAddrs.find(addr => senderHistory.includes(addr));
1051
- console.log(`${lc} [CONFLICT DEBUG] LCA: ${lcaAddr || 'NONE'}`);
1052
- const skipAddrsSet = new Set();
1053
- if (lcaAddr) {
1054
- try {
1055
- const lcaRes = await getFromSpace({ addr: lcaAddr, space: destSpace });
1056
- const lcaIbGib = lcaRes.ibGibs?.[0];
1057
- if (lcaIbGib) {
1058
- const lcaDeps = await getDependencyGraph({ ibGib: lcaIbGib, space: destSpace });
1059
- if (lcaDeps)
1060
- Object.keys(lcaDeps).forEach(a => skipAddrsSet.add(a));
1061
- console.log(`${lc} [CONFLICT DEBUG] LCA deps to skip: ${skipAddrsSet.size}`);
1062
- }
1063
- }
1064
- catch (e) {
1065
- console.warn(`${lc} Error getting LCA deps: ${extractErrorMsg(e)}`);
1066
- }
1067
- }
1068
- // For each receiver-only frame, get its DELTA dependency graph (minus LCA deps)
1069
- for (const addr of receiverOnlyAddrs) {
1070
- // Add the frame itself first
1071
- if (!mergeDeltaReqs.includes(addr)) {
1072
- mergeDeltaReqs.push(addr);
1073
- }
1074
- // Get the frame's delta dependencies (skip LCA's deps)
1075
- try {
1076
- const frameRes = await getFromSpace({ addr, space: destSpace });
1077
- const frameIbGib = frameRes.ibGibs?.[0];
1078
- if (frameIbGib) {
1079
- // Get dependency graph, skipping all LCA dependencies
1080
- const frameDeltaDeps = await getDependencyGraph({
1081
- ibGib: frameIbGib,
1082
- space: destSpace,
1083
- skipAddrs: Array.from(skipAddrsSet), // Skip entire LCA dep graph
1084
- });
1085
- if (frameDeltaDeps) {
1086
- // Add all delta dependencies (Object.keys gives us the addresses)
1087
- Object.keys(frameDeltaDeps).forEach(depAddr => {
1088
- if (!mergeDeltaReqs.includes(depAddr) && !skipAddrsSet.has(depAddr)) {
1089
- mergeDeltaReqs.push(depAddr);
1090
- }
1091
- });
1092
- }
1093
- }
1094
- }
1095
- catch (depError) {
1096
- console.warn(`${lc} [CONFLICT DEBUG] Error getting delta deps for ${addr}: ${extractErrorMsg(depError)}`);
1097
- }
1098
- }
1099
- console.log(`${lc} [CONFLICT DEBUG] Total merge requests (frames + delta deps): ${mergeDeltaReqs.length}`);
1100
- }
1101
- else {
1102
- console.log(`${lc} [CONFLICT DEBUG] No receiver-only frames found for this conflict`);
1103
- }
1159
+ for (const conflict of conflicts) {
1160
+ // todo: integrate conflict strategies into this point...this whole block needs to be redone, but I want to check the fast-forward/backward simpler case tests first
1161
+ throw new Error(`conflicts not (re)implemented yet (E: 3b7d0819f83842a6de3ae988819bc826)`);
1162
+ // const { timelineAddrs, localAddr: receiverTip, remoteAddr: senderTip } = conflict;
1163
+ // // Sender History
1164
+ // // We need our own history for this timeline.
1165
+ // // We know the 'senderTip' (remoteAddr in Ack).
1166
+ // // Sender should verify it has this tip.
1167
+ // // Compute Diffs
1168
+ // // We need to find `receiverOnly` addrs.
1169
+ // // Receiver sent us `timelineAddrs` (Full History).
1170
+ // const receiverHistorySet = new Set(timelineAddrs);
1171
+ // // We need our execution context's history for this senderTip.
1172
+ // // We can fetch valid 'past' from space.
1173
+ // const resSenderTip = await getFromSpace({ space: destSpace, addr: senderTip });
1174
+ // const senderTipIbGib = resSenderTip.ibGibs?.[0];
1175
+ // if (!senderTipIbGib) { throw new Error(`${lc} Sender missing its own tip? ${senderTip} (E: 832f3804645878869ee3c13714366726)`); }
1176
+ // // Basic Diff: Find what Receiver has that we don't.
1177
+ // // Actually, we need to traverse OUR past to find commonality.
1178
+ // const senderHistory = [senderTip, ...(senderTipIbGib.rel8ns?.past || [])];
1179
+ // const receiverOnlyAddrs = timelineAddrs.filter(addr => !senderHistory.includes(addr));
1180
+ // if (receiverOnlyAddrs.length > 0) {
1181
+ // console.log(`${lc} [CONFLICT DEBUG] Found ${receiverOnlyAddrs.length} receiver-only frames - need to pull for merge`);
1182
+ // console.log(`${lc} [CONFLICT DEBUG] Receiver-only addrs:`, receiverOnlyAddrs);
1183
+ // // PULL these frames from Peer into Local Space
1184
+ // // (Validation: We trust peer for now / verification happens on put)
1185
+ // for (const addr of receiverOnlyAddrs) {
1186
+ // console.error(`${lc} [CONFLICT DEBUG] NOT IMPLEMENTED (E: e6bf1a9d2758c469bb2f97514062d826)`);
1187
+ // }
1188
+ // // Compute DELTA dependencies for each receiver-only frame
1189
+ // // Find LCA to determine what dependencies we already have
1190
+ // const lcaAddr = timelineAddrs.find(addr => senderHistory.includes(addr));
1191
+ // console.log(`${lc} [CONFLICT DEBUG] LCA: ${lcaAddr || 'NONE'}`);
1192
+ // const skipAddrsSet = new Set<string>();
1193
+ // if (lcaAddr) {
1194
+ // try {
1195
+ // const lcaRes = await getFromSpace({ addr: lcaAddr, space: destSpace });
1196
+ // const lcaIbGib = lcaRes.ibGibs?.[0];
1197
+ // if (lcaIbGib) {
1198
+ // const lcaDeps = await getDependencyGraph({ ibGib: lcaIbGib, space: destSpace });
1199
+ // if (lcaDeps) Object.keys(lcaDeps).forEach(a => skipAddrsSet.add(a));
1200
+ // console.log(`${lc} [CONFLICT DEBUG] LCA deps to skip: ${skipAddrsSet.size}`);
1201
+ // }
1202
+ // } catch (e) {
1203
+ // console.warn(`${lc} Error getting LCA deps: ${extractErrorMsg(e)}`);
1204
+ // }
1205
+ // }
1206
+ // // For each receiver-only frame, get its DELTA dependency graph (minus LCA deps)
1207
+ // for (const addr of receiverOnlyAddrs) {
1208
+ // // Add the frame itself first
1209
+ // if (!mergeDeltaReqs.includes(addr)) {
1210
+ // mergeDeltaReqs.push(addr);
1211
+ // }
1212
+ // // Get the frame's delta dependencies (skip LCA's deps)
1213
+ // try {
1214
+ // const frameRes = await getFromSpace({ addr, space: destSpace });
1215
+ // const frameIbGib = frameRes.ibGibs?.[0];
1216
+ // if (frameIbGib) {
1217
+ // // Get dependency graph, skipping all LCA dependencies
1218
+ // const frameDeltaDeps = await getDependencyGraph({
1219
+ // ibGib: frameIbGib,
1220
+ // space: destSpace,
1221
+ // skipAddrs: Array.from(skipAddrsSet), // Skip entire LCA dep graph
1222
+ // });
1223
+ // if (frameDeltaDeps) {
1224
+ // // Add all delta dependencies (Object.keys gives us the addresses)
1225
+ // Object.keys(frameDeltaDeps).forEach(depAddr => {
1226
+ // if (!mergeDeltaReqs.includes(depAddr) && !skipAddrsSet.has(depAddr)) {
1227
+ // mergeDeltaReqs.push(depAddr);
1228
+ // }
1229
+ // });
1230
+ // }
1231
+ // }
1232
+ // } catch (depError) {
1233
+ // console.warn(`${lc} [CONFLICT DEBUG] Error getting delta deps for ${addr}: ${extractErrorMsg(depError)}`);
1234
+ // }
1235
+ // }
1236
+ // console.log(`${lc} [CONFLICT DEBUG] Total merge requests (frames + delta deps): ${mergeDeltaReqs.length}`);
1237
+ // } else {
1238
+ // console.log(`${lc} [CONFLICT DEBUG] No receiver-only frames found for this conflict`);
1239
+ // }
1104
1240
  }
1105
- console.log(`${lc} [CONFLICT DEBUG] Finished processing ${optimisticConflicts.length} conflicts. mergeDeltaReqs: ${mergeDeltaReqs.length}`);
1241
+ console.log(`${lc} [CONFLICT DEBUG] Finished processing ${conflicts.length} conflicts. mergeDeltaReqs: ${mergeDeltaReqs.length}`);
1106
1242
  }
1107
1243
  else {
1108
1244
  console.log(`${lc} [CONFLICT DEBUG] No optimistic conflicts to process`);
1109
1245
  }
1110
1246
  // 2. Prepare Delta Payload (What Receiver Requesting + Our Conflict Logic)
1111
- const deltaReqAddrs = ackData.deltaReqAddrs || [];
1112
- const pushOfferAddrs = ackData.pushOfferAddrs || [];
1247
+ const deltaReqAddrs = ackData.deltaRequestAddrInfos || [];
1248
+ const pushOfferAddrs = ackData.pushOfferInfos || [];
1113
1249
  // 1. Process Push Offers (Pull Requests) (Naive: Accept all if missing)
1114
1250
  const pullReqAddrs = [];
1115
1251
  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
- }
1252
+ // const existing = srcGraph[addr] || (await getFromSpace({ addr, space: destSpace })).ibGibs?.[0];
1253
+ // if (!existing) {
1254
+ // pullReqAddrs.push(addr);
1255
+ // }
1120
1256
  }
1121
1257
  // 2. Process Delta Requests (Push Payload)
1122
1258
  // [NEW] Smart Diff: Use knowledgeVector to skip dependencies
1259
+ // const useThisFunction = getDeltaDependencyGraph({ ibGibAddr: '', latestCommonFrameAddr: '', space: })
1123
1260
  const skipAddrs = new Set();
1124
1261
  if (ackData.knowledgeVector) {
1125
1262
  Object.values(ackData.knowledgeVector).forEach(addrs => {
1126
- addrs.forEach(a => skipAddrs.add(a));
1263
+ // addrs.forEach(a => skipAddrs.add(a));
1127
1264
  });
1128
1265
  }
1129
1266
  const payloadIbGibs = [];
1130
1267
  // Gather all tips to sync first
1131
1268
  const tipsToSync = [];
1132
1269
  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
- }
1270
+ // let ibGib = srcGraph[addr];
1271
+ // if (!ibGib) {
1272
+ // const res = await getFromSpace({ addr, space: destSpace });
1273
+ // if (res.ibGibs && res.ibGibs.length > 0) {
1274
+ // ibGib = res.ibGibs[0];
1275
+ // }
1276
+ // }
1277
+ // if (ibGib) {
1278
+ // tipsToSync.push(ibGib);
1279
+ // } else {
1280
+ // throw new Error(`${lc} Requested addr not found: ${addr} (E: d41d59cff4a887f6414c3e92eabd8e26)`);
1281
+ // }
1146
1282
  }
1147
1283
  // Calculate Dependency Graph for ALL tips, effectively utilizing common history
1148
1284
  // Pass skipAddrs to `getDependencyGraph` or gather manually.
1149
1285
  // `getDependencyGraph` takes a single ibGib.
1150
- // We can optimize by doing it for each tip and unioning the result?
1286
+ // We can optimize by doing it for each tip and unioning the result?
1151
1287
  // Or `graph-helper` could support `ibGibs: []`. It currently takes `ibGib`.
1152
1288
  // We will loop.
1153
1289
  const allDepsSet = new Set();
@@ -1219,7 +1355,8 @@ export class SyncSagaCoordinator {
1219
1355
  payloadIbGibsControl.push(identity);
1220
1356
  }
1221
1357
  // return { frame: deltaFrame, payloadIbGibsControl, payloadIbGibsDomain: payloadIbGibs };
1222
- return { frame: deltaFrame, payloadIbGibsDomain: payloadIbGibs };
1358
+ // return { frame: deltaFrame, payloadIbGibsDomain: payloadIbGibs };
1359
+ throw new Error(`not implemented (E: 62e1e2a408e8bfa2982b2f87e8843826)`);
1223
1360
  }
1224
1361
  catch (error) {
1225
1362
  console.error(`${lc} ${extractErrorMsg(error)}`);
@@ -1255,7 +1392,7 @@ export class SyncSagaCoordinator {
1255
1392
  throw new Error(`${lc} Invalid delta frame: deltaData.stage !== SyncStage.delta (E: 0c28c8d8f08a4421b8344e6727271421)`);
1256
1393
  }
1257
1394
  if (logalot) {
1258
- console.log(`${lc} deltaData: ${pretty(deltaData)} (I: 8d7e6f5g4h3i2j1k0l9m)`);
1395
+ console.log(`${lc} deltaData: ${pretty(deltaData)} (I: a76008681df458cfbcdc4848f825a826)`);
1259
1396
  }
1260
1397
  console.log(`${lc} [CONFLICT DEBUG] deltaData.payloadAddrs count: ${deltaData.payloadAddrs?.length || 0}`);
1261
1398
  const payloadAddrs = deltaData.payloadAddrs || [];
@@ -1264,8 +1401,8 @@ export class SyncSagaCoordinator {
1264
1401
  // 1. Process Received Payload (Ingest)
1265
1402
  const receivedPayloadIbGibs = [];
1266
1403
  if (payloadAddrs.length > 0) {
1267
- // We use `payloadAddrs` as the manifest.
1268
- // The ACTUAL collection of ibGibs should be available via `getFromSpace`
1404
+ // We use `payloadAddrs` as the manifest.
1405
+ // The ACTUAL collection of ibGibs should be available via `getFromSpace`
1269
1406
  // assuming the "Transport" layer put them there implicitly?
1270
1407
  // OR, if we are local-only, we just get them.
1271
1408
  // The `handleDeltaFrame` contract assumes data is reachable in `space`.
@@ -1290,7 +1427,7 @@ export class SyncSagaCoordinator {
1290
1427
  // Get the requested ibGib
1291
1428
  let ibGib = srcGraph[addr];
1292
1429
  if (!ibGib) {
1293
- const res = await getFromSpace({ addr, space: destSpace }); // Query from destSpace
1430
+ const res = await getFromSpace({ addr, space: destSpace }); // Query from destSpace
1294
1431
  if (res.ibGibs && res.ibGibs.length > 0) {
1295
1432
  ibGib = res.ibGibs[0];
1296
1433
  }
@@ -1376,7 +1513,7 @@ export class SyncSagaCoordinator {
1376
1513
  console.log(`${lc} [CONFLICT DEBUG] ReceiverTip found in tempSpace: ${!!resRecTip.ibGibs?.[0]}`);
1377
1514
  if (resRecTip.success && resRecTip.ibGibs?.[0]) {
1378
1515
  // We have the tip!
1379
- // Do we have the full history?
1516
+ // Do we have the full history?
1380
1517
  // `mergeDivergentTimelines` in `conflict-optimistic` will attempt to fetch history.
1381
1518
  // If we just ingested the missing pieces, `getFromSpace` inside `merge` should succeed.
1382
1519
  // Perform Merge!
@@ -1420,9 +1557,9 @@ export class SyncSagaCoordinator {
1420
1557
  payloadAddrs: outgoingPayload.map(p => getIbGibAddr({ ibGib: p })),
1421
1558
  requests: hasMyRequests ? myRequests : undefined,
1422
1559
  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.
1560
+ // Wait. If we send data, we are NOT committing yet.
1424
1561
  // We are sending data. The OTHER side must ingest it.
1425
- // So proposeCommit = true?
1562
+ // So proposeCommit = true?
1426
1563
  // "Here is the data. I'm done. If you are good, let's commit."
1427
1564
  // Yes.
1428
1565
  };
@@ -1448,7 +1585,8 @@ export class SyncSagaCoordinator {
1448
1585
  payloadIbGibsControl.push(identity);
1449
1586
  }
1450
1587
  // return { frame: deltaFrame, payloadIbGibsControl, payloadIbGibsDomain: outgoingPayload };
1451
- return { frame: deltaFrame, payloadIbGibsDomain: outgoingPayload };
1588
+ // return { frame: deltaFrame, payloadIbGibsDomain: outgoingPayload };
1589
+ throw new Error(`not implemented (E: 2b38a8afb6d84efcee5ab51673387826)`);
1452
1590
  }
1453
1591
  else {
1454
1592
  // We have nothing to send.
@@ -1477,7 +1615,8 @@ export class SyncSagaCoordinator {
1477
1615
  commitCtrlPayloads.push(identity);
1478
1616
  }
1479
1617
  // return { frame: commitFrame, payloadIbGibsControl: commitCtrlPayloads };
1480
- return { frame: commitFrame, };
1618
+ // return { frame: commitFrame, };
1619
+ throw new Error(`not implemented (E: dda1ddc63fdcadff06653298e0d04826)`);
1481
1620
  }
1482
1621
  else {
1483
1622
  // peer did NOT propose commit (maybe they just sent data/requests and didn't ready flag).
@@ -1531,7 +1670,8 @@ export class SyncSagaCoordinator {
1531
1670
  commitCtrlPayloads2.push(identity);
1532
1671
  }
1533
1672
  // return { frame: commitFrame, payloadIbGibsControl: commitCtrlPayloads2 };
1534
- return { frame: commitFrame, };
1673
+ // return { frame: commitFrame, };
1674
+ throw new Error(`not implemented (E: 27514878585889e531ef21f1abbef826)`);
1535
1675
  }
1536
1676
  // Build control payloads for delta propose
1537
1677
  const deltaCtrlPayloads = [deltaFrame, deltaStone];
@@ -1539,7 +1679,8 @@ export class SyncSagaCoordinator {
1539
1679
  deltaCtrlPayloads.push(identity);
1540
1680
  }
1541
1681
  // return { frame: deltaFrame, payloadIbGibsControl: deltaCtrlPayloads };
1542
- return { frame: deltaFrame, };
1682
+ // return { frame: deltaFrame, };
1683
+ throw new Error(`not implemented (E: ff35584696b6fcb3ad6dd7c5cade2f26)`);
1543
1684
  }
1544
1685
  }
1545
1686
  }
@@ -1559,7 +1700,8 @@ export class SyncSagaCoordinator {
1559
1700
  if (logalot) {
1560
1701
  console.log(`${lc} Peer committed. Finalizing saga locally. Saga Complete.`);
1561
1702
  }
1562
- return null;
1703
+ // return { responseWasNull: true };
1704
+ throw new Error(`not implemented (E: 4d7f878bcc45ad3dd9c4b8573f3aa826)`);
1563
1705
  }
1564
1706
  // #endregion Handlers
1565
1707
  async createSyncMsgStone({ data, localSpace, metaspace, }) {
@@ -1633,7 +1775,7 @@ export class SyncSagaCoordinator {
1633
1775
  if (sessionIdentity) {
1634
1776
  rel8nInfos.push({ rel8nName: 'identity', ibGibs: [sessionIdentity], });
1635
1777
  }
1636
- // remove the existing sync msg stones' addrs
1778
+ // remove the existing sync msg stones' addrs
1637
1779
  if (!prevSagaIbGib.rel8ns) {
1638
1780
  throw new Error(`(UNEXPECTED) prevSagaIbGib.rel8ns falsy? (E: 81375841aff85b1e48ea42ca218e6826)`);
1639
1781
  }