@ibgib/core-gib 0.1.60 → 0.1.61

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 (179) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/dist/common/other/graph-helper.d.mts.map +1 -1
  3. package/dist/common/other/graph-helper.mjs +7 -6
  4. package/dist/common/other/graph-helper.mjs.map +1 -1
  5. package/dist/keystone/keystone-config-builder.d.mts +1 -2
  6. package/dist/keystone/keystone-config-builder.d.mts.map +1 -1
  7. package/dist/keystone/keystone-config-builder.mjs +4 -19
  8. package/dist/keystone/keystone-config-builder.mjs.map +1 -1
  9. package/dist/keystone/keystone-constants.d.mts +2 -0
  10. package/dist/keystone/keystone-constants.d.mts.map +1 -1
  11. package/dist/keystone/keystone-constants.mjs +2 -0
  12. package/dist/keystone/keystone-constants.mjs.map +1 -1
  13. package/dist/keystone/keystone-helpers.d.mts +5 -15
  14. package/dist/keystone/keystone-helpers.d.mts.map +1 -1
  15. package/dist/keystone/keystone-helpers.mjs +59 -73
  16. package/dist/keystone/keystone-helpers.mjs.map +1 -1
  17. package/dist/keystone/keystone-policy-types.d.mts +6 -4
  18. package/dist/keystone/keystone-policy-types.d.mts.map +1 -1
  19. package/dist/keystone/keystone-service-v1.d.mts.map +1 -1
  20. package/dist/keystone/keystone-service-v1.mjs +4 -8
  21. package/dist/keystone/keystone-service-v1.mjs.map +1 -1
  22. package/dist/keystone/keystone-service-v1.respec.mjs +182 -33
  23. package/dist/keystone/keystone-service-v1.respec.mjs.map +1 -1
  24. package/dist/keystone/keystone-types.d.mts +4 -11
  25. package/dist/keystone/keystone-types.d.mts.map +1 -1
  26. package/dist/keystone/policy/keystone-profile-builder.d.mts +25 -0
  27. package/dist/keystone/policy/keystone-profile-builder.d.mts.map +1 -0
  28. package/dist/keystone/policy/keystone-profile-builder.mjs +117 -0
  29. package/dist/keystone/policy/keystone-profile-builder.mjs.map +1 -0
  30. package/dist/keystone/policy/profiles/profile-high.json +84 -0
  31. package/dist/keystone/policy/profiles/profile-low.json +84 -0
  32. package/dist/keystone/policy/profiles/profile-medium.json +84 -0
  33. package/dist/keystone/policy/profiles/profile-session.json +84 -0
  34. package/dist/keystone/policy/profiles/profile-test.json +84 -0
  35. package/dist/keystone/policy/schemas/connect-pool.high.schema.json +23 -0
  36. package/dist/keystone/policy/schemas/connect-pool.low.schema.json +23 -0
  37. package/dist/keystone/policy/schemas/connect-pool.medium.schema.json +23 -0
  38. package/dist/keystone/policy/schemas/keystone.high.schema.json +26 -0
  39. package/dist/keystone/policy/schemas/keystone.low.schema.json +26 -0
  40. package/dist/keystone/policy/schemas/keystone.medium.schema.json +26 -0
  41. package/dist/keystone/policy/schemas/manage-pool.high.schema.json +23 -0
  42. package/dist/keystone/policy/schemas/manage-pool.low.schema.json +23 -0
  43. package/dist/keystone/policy/schemas/manage-pool.medium.schema.json +23 -0
  44. package/dist/keystone/policy/schemas/revoke-pool.high.schema.json +23 -0
  45. package/dist/keystone/policy/schemas/revoke-pool.low.schema.json +23 -0
  46. package/dist/keystone/policy/schemas/revoke-pool.medium.schema.json +23 -0
  47. package/dist/keystone/policy/schemas/sign-pool.high.schema.json +23 -0
  48. package/dist/keystone/policy/schemas/sign-pool.low.schema.json +23 -0
  49. package/dist/keystone/policy/schemas/sign-pool.medium.schema.json +23 -0
  50. package/dist/keystone/policy/schemas/sync-pool.high.schema.json +23 -0
  51. package/dist/keystone/policy/schemas/sync-pool.low.schema.json +23 -0
  52. package/dist/keystone/policy/schemas/sync-pool.medium.schema.json +23 -0
  53. package/dist/sync/sync-conflict-adv-multitimelines.withid.respec.d.mts +8 -0
  54. package/dist/sync/sync-conflict-adv-multitimelines.withid.respec.d.mts.map +1 -0
  55. package/dist/sync/sync-conflict-adv-multitimelines.withid.respec.mjs +582 -0
  56. package/dist/sync/sync-conflict-adv-multitimelines.withid.respec.mjs.map +1 -0
  57. package/dist/sync/sync-conflict-basic-divergence.withid.respec.d.mts +7 -0
  58. package/dist/sync/sync-conflict-basic-divergence.withid.respec.d.mts.map +1 -0
  59. package/dist/sync/sync-conflict-basic-divergence.withid.respec.mjs +274 -0
  60. package/dist/sync/sync-conflict-basic-divergence.withid.respec.mjs.map +1 -0
  61. package/dist/sync/sync-conflict-basic-multitimelines.withid.respec.d.mts +8 -0
  62. package/dist/sync/sync-conflict-basic-multitimelines.withid.respec.d.mts.map +1 -0
  63. package/dist/sync/sync-conflict-basic-multitimelines.withid.respec.mjs +322 -0
  64. package/dist/sync/sync-conflict-basic-multitimelines.withid.respec.mjs.map +1 -0
  65. package/dist/sync/sync-conflict-text-merge.withid.respec.d.mts +7 -0
  66. package/dist/sync/sync-conflict-text-merge.withid.respec.d.mts.map +1 -0
  67. package/dist/sync/sync-conflict-text-merge.withid.respec.mjs +307 -0
  68. package/dist/sync/sync-conflict-text-merge.withid.respec.mjs.map +1 -0
  69. package/dist/sync/sync-innerspace-constants.withid.respec.d.mts +8 -0
  70. package/dist/sync/sync-innerspace-constants.withid.respec.d.mts.map +1 -0
  71. package/dist/sync/sync-innerspace-constants.withid.respec.mjs +233 -0
  72. package/dist/sync/sync-innerspace-constants.withid.respec.mjs.map +1 -0
  73. package/dist/sync/sync-innerspace-deep-updates.withid.respec.d.mts +7 -0
  74. package/dist/sync/sync-innerspace-deep-updates.withid.respec.d.mts.map +1 -0
  75. package/dist/sync/sync-innerspace-deep-updates.withid.respec.mjs +233 -0
  76. package/dist/sync/sync-innerspace-deep-updates.withid.respec.mjs.map +1 -0
  77. package/dist/sync/sync-innerspace-dest-ahead.withid.respec.d.mts +7 -0
  78. package/dist/sync/sync-innerspace-dest-ahead.withid.respec.d.mts.map +1 -0
  79. package/dist/sync/sync-innerspace-dest-ahead.withid.respec.mjs +225 -0
  80. package/dist/sync/sync-innerspace-dest-ahead.withid.respec.mjs.map +1 -0
  81. package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs.map +1 -1
  82. package/dist/sync/sync-innerspace-multiple-timelines.withid.respec.d.mts +7 -0
  83. package/dist/sync/sync-innerspace-multiple-timelines.withid.respec.d.mts.map +1 -0
  84. package/dist/sync/sync-innerspace-multiple-timelines.withid.respec.mjs +235 -0
  85. package/dist/sync/sync-innerspace-multiple-timelines.withid.respec.mjs.map +1 -0
  86. package/dist/sync/sync-innerspace-partial-update.withid.respec.d.mts +7 -0
  87. package/dist/sync/sync-innerspace-partial-update.withid.respec.d.mts.map +1 -0
  88. package/dist/sync/sync-innerspace-partial-update.withid.respec.mjs +211 -0
  89. package/dist/sync/sync-innerspace-partial-update.withid.respec.mjs.map +1 -0
  90. package/dist/sync/sync-innerspace.withid.respec.d.mts +8 -0
  91. package/dist/sync/sync-innerspace.withid.respec.d.mts.map +1 -0
  92. package/dist/sync/sync-innerspace.withid.respec.mjs +260 -0
  93. package/dist/sync/sync-innerspace.withid.respec.mjs.map +1 -0
  94. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.d.mts +1 -0
  95. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.d.mts.map +1 -1
  96. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.mjs +13 -4
  97. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.mjs.map +1 -1
  98. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.d.mts +1 -1
  99. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.d.mts.map +1 -1
  100. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mjs +5 -3
  101. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mjs.map +1 -1
  102. package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
  103. package/dist/sync/sync-saga-coordinator.mjs +165 -145
  104. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  105. package/dist/sync/sync-withid.pingpong.respec.mjs +8 -8
  106. package/dist/sync/sync-withid.pingpong.respec.mjs.map +1 -1
  107. package/dist/timeline/timeline-api.d.mts.map +1 -1
  108. package/dist/timeline/timeline-api.mjs +1 -14
  109. package/dist/timeline/timeline-api.mjs.map +1 -1
  110. package/dist/witness/space/reconciliation-space/reconciliation-space-base.d.mts.map +1 -1
  111. package/dist/witness/space/reconciliation-space/reconciliation-space-base.mjs +0 -40
  112. package/dist/witness/space/reconciliation-space/reconciliation-space-base.mjs.map +1 -1
  113. package/dist/witness/space/reconciliation-space/reconciliation-space-helper.d.mts.map +1 -1
  114. package/dist/witness/space/reconciliation-space/reconciliation-space-helper.mjs +6 -6
  115. package/dist/witness/space/reconciliation-space/reconciliation-space-helper.mjs.map +1 -1
  116. package/ibgib-foundations.md +2 -1
  117. package/package.json +1 -1
  118. package/src/common/other/graph-helper.mts +7 -6
  119. package/src/keystone/README.md +19 -15
  120. package/src/keystone/docs/CRYPTANALYSIS.md +185 -0
  121. package/src/keystone/docs/architecture.md +24 -1
  122. package/src/keystone/docs/profiles.md +124 -0
  123. package/src/keystone/keystone-config-builder.mts +3 -21
  124. package/src/keystone/keystone-constants.mts +2 -0
  125. package/src/keystone/keystone-helpers.mts +74 -77
  126. package/src/keystone/keystone-policy-types.mts +6 -4
  127. package/src/keystone/keystone-service-v1.mts +4 -9
  128. package/src/keystone/keystone-service-v1.respec.mts +214 -32
  129. package/src/keystone/keystone-types.mts +5 -9
  130. package/src/keystone/policy/IMPLEMENTATION.md +60 -0
  131. package/src/keystone/policy/README.md +94 -0
  132. package/src/keystone/policy/keystone-profile-builder.mts +131 -0
  133. package/src/keystone/policy/profiles/profile-high.json +84 -0
  134. package/src/keystone/policy/profiles/profile-low.json +84 -0
  135. package/src/keystone/policy/profiles/profile-medium.json +84 -0
  136. package/src/keystone/policy/profiles/profile-session.json +84 -0
  137. package/src/keystone/policy/profiles/profile-test.json +84 -0
  138. package/src/keystone/policy/schemas/connect-pool.high.schema.json +23 -0
  139. package/src/keystone/policy/schemas/connect-pool.low.schema.json +23 -0
  140. package/src/keystone/policy/schemas/connect-pool.medium.schema.json +23 -0
  141. package/src/keystone/policy/schemas/keystone.high.schema.json +26 -0
  142. package/src/keystone/policy/schemas/keystone.low.schema.json +26 -0
  143. package/src/keystone/policy/schemas/keystone.medium.schema.json +26 -0
  144. package/src/keystone/policy/schemas/manage-pool.high.schema.json +23 -0
  145. package/src/keystone/policy/schemas/manage-pool.low.schema.json +23 -0
  146. package/src/keystone/policy/schemas/manage-pool.medium.schema.json +23 -0
  147. package/src/keystone/policy/schemas/revoke-pool.high.schema.json +23 -0
  148. package/src/keystone/policy/schemas/revoke-pool.low.schema.json +23 -0
  149. package/src/keystone/policy/schemas/revoke-pool.medium.schema.json +23 -0
  150. package/src/keystone/policy/schemas/sign-pool.high.schema.json +23 -0
  151. package/src/keystone/policy/schemas/sign-pool.low.schema.json +23 -0
  152. package/src/keystone/policy/schemas/sign-pool.medium.schema.json +23 -0
  153. package/src/keystone/policy/schemas/sync-pool.high.schema.json +23 -0
  154. package/src/keystone/policy/schemas/sync-pool.low.schema.json +23 -0
  155. package/src/keystone/policy/schemas/sync-pool.medium.schema.json +23 -0
  156. package/src/sync/docs/security.md +54 -21
  157. package/src/sync/sync-conflict-adv-multitimelines.withid.respec.mts +706 -0
  158. package/src/sync/sync-conflict-basic-divergence.withid.respec.mts +321 -0
  159. package/src/sync/sync-conflict-basic-multitimelines.withid.respec.mts +374 -0
  160. package/src/sync/sync-conflict-text-merge.withid.respec.mts +347 -0
  161. package/src/sync/sync-innerspace-constants.withid.respec.mts +264 -0
  162. package/src/sync/sync-innerspace-deep-updates.withid.respec.mts +272 -0
  163. package/src/sync/sync-innerspace-dest-ahead.withid.respec.mts +266 -0
  164. package/src/sync/sync-innerspace-multiple-timelines.respec.mts +0 -1
  165. package/src/sync/sync-innerspace-multiple-timelines.withid.respec.mts +273 -0
  166. package/src/sync/sync-innerspace-partial-update.withid.respec.mts +249 -0
  167. package/src/sync/sync-innerspace.withid.respec.mts +265 -0
  168. package/src/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.mts +12 -4
  169. package/src/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mts +5 -3
  170. package/src/sync/sync-saga-coordinator.mts +159 -143
  171. package/src/sync/sync-withid.pingpong.respec.mts +8 -8
  172. package/src/timeline/timeline-api.mts +1 -15
  173. package/src/timeline/timeline-api.respec.mts +3 -3
  174. package/src/witness/space/reconciliation-space/reconciliation-space-base.mts +0 -46
  175. package/src/witness/space/reconciliation-space/reconciliation-space-helper.mts +6 -5
  176. package/tsconfig.json +6 -1
  177. package/src/keystone/keystone-policy.schema.json +0 -51
  178. package/src/witness/space/reconciliation-space/reconciliation-space-base.mts.OLD.md +0 -884
  179. package/src/witness/space/reconciliation-space/reconciliation-space-helper.mts.OLD.md +0 -125
@@ -0,0 +1,706 @@
1
+ /**
2
+ * @module sync-conflict-adv-multitimelines.withid.respec
3
+ *
4
+ * Verifies Conflict Resolution strategies in SyncSagaCoordinator under identity.
5
+ * Reproduces divergence scenarios and asserts resolution behavior.
6
+ */
7
+
8
+ import {
9
+ respecfully, lastOfAll, ifWe, iReckon,
10
+ ifWeMight
11
+ } from '@ibgib/helper-gib/dist/respec-gib/respec-gib.mjs';
12
+ const maam = `[${import.meta.url}]`, sir = maam;
13
+ import { clone, delay, extractErrorMsg, pretty } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
14
+ import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
15
+ import { IbGibData_V1, IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
16
+
17
+ import { GLOBAL_LOG_A_LOT } from '../core-constants.mjs';
18
+ import { TestTransformer, } from '../test-helpers.mjs';
19
+ import { TestMut8Info, } from '../test-types.mjs';
20
+ import { SyncSagaCoordinator } from './sync-saga-coordinator.mjs';
21
+ import { getFromSpace } from '../witness/space/space-helper.mjs';
22
+ import { Metaspace_Innerspace } from '../witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.mjs';
23
+ import { InnerSpace_V1 } from '../witness/space/inner-space/inner-space-v1.mjs';
24
+ import { SyncPeerInnerspace_V1 } from './sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs';
25
+ import { DEFAULT_INNER_SPACE_DATA_V1 } from '../witness/space/inner-space/inner-space-types.mjs';
26
+ import { getIbGibsFromCache_fallbackToSpaces, getTjpAddr, } from '../common/other/ibgib-helper.mjs';
27
+ import { SyncSagaInfo } from './sync-types.mjs';
28
+ import { getDependencyGraph, graphsAreEquivalent } from '../common/other/graph-helper.mjs';
29
+ import { SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1 } from './sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mjs';
30
+ import { SyncConflictStrategy } from './sync-constants.mjs';
31
+ import { getHistory } from '../timeline/timeline-api.mjs';
32
+
33
+ import { KeystoneService_V1 } from '../keystone/keystone-service-v1.mjs';
34
+ import {
35
+ KEYSTONE_VERB_SYNC, POOL_ID_SYNC,
36
+ } from '../keystone/keystone-constants.mjs';
37
+ import { createStandardPoolConfig } from '../keystone/keystone-config-builder.mjs';
38
+ import { KeystoneReplenishStrategy, KeystoneIbGib_V1 } from '../keystone/keystone-types.mjs';
39
+
40
+ const logalot = GLOBAL_LOG_A_LOT;
41
+ const lc = sir;
42
+
43
+ const SENDER_SECRET = 'test-sender-secret-conflict-adv-multitimelines-withid';
44
+
45
+ const SENDER_IDENTITY_SYNC_POOL_CONFIG = createStandardPoolConfig({
46
+ id: POOL_ID_SYNC,
47
+ salt: 'senderidentitysyncsaltconflictadvmultitimelineswithid',
48
+ verbs: [KEYSTONE_VERB_SYNC],
49
+ size: 200,
50
+ sequential: 1,
51
+ random: 1,
52
+ targetBinding: 2,
53
+ replenishStrategy: KeystoneReplenishStrategy.topUp,
54
+ });
55
+
56
+ interface TestData extends IbGibData_V1 {
57
+ commonField?: string;
58
+ fieldA?: string;
59
+ fieldB?: string;
60
+ fieldC?: string;
61
+ fieldD?: string;
62
+ fieldE?: string;
63
+ fieldF?: string;
64
+ fieldG?: string;
65
+ betaFieldA?: string;
66
+ betaFieldB?: string;
67
+ betaFieldC?: string;
68
+ betaFieldD?: string;
69
+ gammaField?: string;
70
+ }
71
+
72
+ const TEST_REL8N_NAME = 'testrel8n';
73
+
74
+ await respecfully(sir, `Multi-round/timeline permutations with Identity`, async () => {
75
+
76
+ // #region Init/Setup
77
+
78
+ const metaspace = new Metaspace_Innerspace(undefined);
79
+ await metaspace.initialize({
80
+ getFnAlert: () => async ({ title, msg }) => { console.log(`[Alert] ${title}: ${msg}`); },
81
+ getFnPrompt: () => async ({ title, msg }) => { console.log(`[Prompt] ${title}: ${msg}`); return ''; },
82
+ getFnPromptPassword: () => async (title, msg) => { console.log(`[PromptPwd] ${title}: ${msg}`); return null; },
83
+ });
84
+ while (!metaspace.initialized) { await delay(10); }
85
+
86
+ const defaultLocalUserSpace = await metaspace.getLocalUserSpace({ lock: false });
87
+ await defaultLocalUserSpace!.initialized;
88
+
89
+ const sourceSpace = new InnerSpace_V1({
90
+ ...DEFAULT_INNER_SPACE_DATA_V1,
91
+ name: 'source',
92
+ uuid: 'source_uuid',
93
+ description: 'source test space',
94
+ });
95
+ await sourceSpace.initialized;
96
+
97
+ const destSpace = new InnerSpace_V1({
98
+ ...DEFAULT_INNER_SPACE_DATA_V1,
99
+ name: 'dest',
100
+ uuid: 'dest_uuid',
101
+ description: 'dest test space',
102
+ });
103
+ await destSpace.initialized;
104
+
105
+ const testTransformer = new TestTransformer(metaspace, sourceSpace, destSpace);
106
+
107
+ if (logalot) { console.log(`${lc} Setting up Coordinators...`); }
108
+ const senderCoordinator = new SyncSagaCoordinator();
109
+ const receiverCoordinator = new SyncSagaCoordinator();
110
+
111
+ // Setup Identities
112
+ const keystoneSvc = new KeystoneService_V1();
113
+ const r1_senderIdentity_v0_source = await keystoneSvc.genesis({
114
+ masterSecret: SENDER_SECRET,
115
+ configs: [SENDER_IDENTITY_SYNC_POOL_CONFIG],
116
+ metaspace,
117
+ space: sourceSpace,
118
+ });
119
+
120
+ // Register identity in both spaces
121
+ await metaspace.put({ ibGib: r1_senderIdentity_v0_source, space: destSpace });
122
+ await metaspace.registerNewIbGib({ ibGib: r1_senderIdentity_v0_source, space: destSpace });
123
+
124
+ let senderIdentityLatestSource = r1_senderIdentity_v0_source;
125
+
126
+ async function newTestPeer(): Promise<SyncPeerInnerspace_V1> {
127
+ const peer = new SyncPeerInnerspace_V1(clone(SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1));
128
+ await peer.initialized;
129
+ await peer.initializeOpts({
130
+ localMetaspace: metaspace,
131
+ localSpace: sourceSpace,
132
+ receiverSpace: destSpace,
133
+ receiverCoordinator: receiverCoordinator,
134
+ receiverMetaspace: metaspace,
135
+ });
136
+ return peer;
137
+ }
138
+
139
+ // #endregion Init/Setup
140
+
141
+ // #region Round 1: Seed common history
142
+
143
+ const _r1 = testTransformer.newRound({
144
+ name: 'r1_seedCommonHistory',
145
+ description: 'Create alpha v0 and v1 on source, sync to dest so both v0 and v1 are established as synced.',
146
+ });
147
+
148
+ if (logalot) { console.log(`${lc} Creating common History...`); }
149
+ const r1_alpha_v0_source = await testTransformer.create({
150
+ atom: 'alpha',
151
+ in: 'source',
152
+ name: 'r1_alpha_v0_source',
153
+ });
154
+ const alpha_tjpAddr = getTjpAddr({ ibGib: r1_alpha_v0_source.ibGib, defaultIfNone: 'incomingAddr' })!;
155
+
156
+ // Create v1 (common) - will be synced to dest
157
+ const r1_alpha_v1_source_common = await testTransformer.mut8({
158
+ stepInfo: r1_alpha_v0_source,
159
+ strField: 'commonField',
160
+ name: 'r1_alpha_v1_source_common'
161
+ });
162
+
163
+ await respecfully(sir, `r1 verify pre`, async () => {
164
+ await ifWe(sir, 'dest should NOT have alpha', async () => {
165
+ const resGet = await getFromSpace({
166
+ space: destSpace,
167
+ addr: alpha_tjpAddr,
168
+ });
169
+ iReckon(sir, resGet.success).asTo('getFromSpace should return false for missing timeline').isGonnaBeFalse();
170
+ iReckon(sir, resGet.ibGibs?.length ?? 0).asTo('Dest should NOT have alpha timeline yet').isGonnaBe(0);
171
+ });
172
+ });
173
+
174
+ const peerR1 = await newTestPeer();
175
+ const r1_syncSaga = await senderCoordinator.sync({
176
+ peer: peerR1,
177
+ localSpace: sourceSpace,
178
+ metaspace,
179
+ domainIbGibs: [r1_alpha_v1_source_common.ibGib],
180
+ conflictStrategy: SyncConflictStrategy.optimisticWithLCS,
181
+ senderIdentity: senderIdentityLatestSource,
182
+ fnSenderSecret: async () => SENDER_SECRET,
183
+ });
184
+
185
+ await r1_syncSaga.done;
186
+ if (logalot) { console.log(`${lc} r1_syncSaga Complete.`); }
187
+
188
+ await respecfully(sir, `r1 verify post`, async () => {
189
+ await ifWe(sir, 'dest should have alpha', async () => {
190
+ const [alpha_dest] = await getIbGibsFromCache_fallbackToSpaces({
191
+ addrs: [r1_alpha_v0_source.addr],
192
+ space: destSpace,
193
+ });
194
+ iReckon(sir, alpha_dest).asTo('alpha exists in dest').isGonnaBeTruthy();
195
+ if (alpha_dest) {
196
+ const depGraph_alpha_source = await getDependencyGraph({ ibGib: r1_alpha_v0_source.ibGib, space: sourceSpace });
197
+ const depGraph_alpha_dest = await getDependencyGraph({ ibGib: alpha_dest, space: destSpace });
198
+ const alphaDepsAreEqual = graphsAreEquivalent({
199
+ graphA: depGraph_alpha_source, graphB: depGraph_alpha_dest
200
+ });
201
+ iReckon(sir, alphaDepsAreEqual).asTo('alpha got synced and graphs are equal').isGonnaBe(true);
202
+ }
203
+ });
204
+
205
+ await ifWe(sir, 'sessionIdentity evolved for Round 1', async () => {
206
+ const latestS = peerR1.currentSessionIdentity;
207
+ iReckon(sir, latestS).asTo('session identity exists').isGonnaBeTruthy();
208
+ if (latestS) {
209
+ iReckon(sir, latestS.data?.n).asTo('session identity data.n').isGonnaBe(2);
210
+ }
211
+ });
212
+ });
213
+
214
+ // Get alpha_v1_common from destSpace for Round 2
215
+ const resGetDest = await getFromSpace({ space: destSpace, addr: r1_alpha_v1_source_common.addr });
216
+ if (!resGetDest.success || !resGetDest.ibGibs || resGetDest.ibGibs.length === 0) {
217
+ throw new Error(`Failed to retrieve alpha from destSpace after sync. (E: r1_fail)`);
218
+ }
219
+ const alpha_v1_common_onDest = resGetDest.ibGibs[0];
220
+
221
+ // Fetch evolved user identity from space
222
+ const latestSenderIdentityAddrR1 = await metaspace.getLatestAddr({
223
+ addr: getIbGibAddr({ ibGib: r1_senderIdentity_v0_source }),
224
+ space: sourceSpace,
225
+ });
226
+ if (!latestSenderIdentityAddrR1) {
227
+ throw new Error("Could not find latest sender identity after R1");
228
+ }
229
+ const resGetSenderIR1 = await getFromSpace({ space: sourceSpace, addr: latestSenderIdentityAddrR1 });
230
+ senderIdentityLatestSource = resGetSenderIR1.ibGibs![0] as KeystoneIbGib_V1;
231
+
232
+ // Copy/register evolved user identity to dest space
233
+ await metaspace.put({ ibGib: senderIdentityLatestSource, space: destSpace });
234
+ await metaspace.registerNewIbGib({ ibGib: senderIdentityLatestSource, space: destSpace });
235
+
236
+ // #endregion Round 1: Seed common history
237
+
238
+ // #region Round 2: Create Divergence (v2source vs v2dest)
239
+
240
+ const _r2 = testTransformer.newRound({
241
+ name: 'r2_divergent_edits',
242
+ description: 'Create conflicts on alpha, add beta relation on source, separate edit on dest'
243
+ });
244
+
245
+ // #region r2 source edits
246
+ if (logalot) { console.log(`${lc} Creating Divergence...`); }
247
+
248
+ // Source: Create beta, mutate alpha fieldA, add beta relation
249
+ const r2_beta_v0_source = await testTransformer.create({
250
+ atom: 'beta',
251
+ in: 'source',
252
+ data: { fieldA: 'beta field A created on source' },
253
+ name: 'r2_beta_v0_source'
254
+ });
255
+ const r2_alpha_v2_source_arbitraryMut8 = await testTransformer.mut8({
256
+ ibGib: r1_alpha_v1_source_common.ibGib,
257
+ in: 'source',
258
+ strField: 'fieldA',
259
+ name: 'r2_alpha_v2_source_arbitraryMut8',
260
+ comments_snake_plus_CamelCase: 'editedOnSource',
261
+ });
262
+ const r2_alpha_v3_source_rel8dBeta = await testTransformer.rel8({
263
+ stepInfo: r2_alpha_v2_source_arbitraryMut8,
264
+ in: 'source',
265
+ targetIbGibs: [r2_beta_v0_source.ibGib],
266
+ rel8nName: TEST_REL8N_NAME,
267
+ name: 'r2_alpha_v3_source_rel8dBeta'
268
+ });
269
+ // #endregion r2 source edits
270
+
271
+ // #region r2 dest edits
272
+ // Dest: Mutate alpha fieldB
273
+ const r2_alpha_v2_dest_mut8FieldB = await testTransformer.mut8({
274
+ ibGib: alpha_v1_common_onDest,
275
+ in: 'dest',
276
+ strField: 'fieldB',
277
+ name: 'r2_alpha_v2_dest_mut8FieldB',
278
+ comments_snake_plus_CamelCase: 'editedOnDest',
279
+ });
280
+ if (logalot) { console.log(`${lc} Divergence created.`); }
281
+ // #endregion r2 dest edits
282
+
283
+ await respecfully(sir, `r2 verify pre`, async () => {
284
+ await ifWe(sir, 'dest has alpha v1 common', async () => {
285
+ const destKV = await receiverCoordinator.getKnowledgeMap({
286
+ space: destSpace,
287
+ metaspace,
288
+ domainIbGibs: [alpha_v1_common_onDest]
289
+ });
290
+ const alpha_v1_common_tjpAddr_onDest = getTjpAddr({ ibGib: alpha_v1_common_onDest, defaultIfNone: 'incomingAddr' })!;
291
+ const destTip = destKV[alpha_v1_common_tjpAddr_onDest];
292
+ iReckon(sir, !!destTip).asTo(`Dest KV has timeline tip`).isGonnaBeTruthy();
293
+ });
294
+ });
295
+
296
+ const peerR2 = await newTestPeer();
297
+ const r2_syncSaga = await senderCoordinator.sync({
298
+ peer: peerR2,
299
+ localSpace: sourceSpace,
300
+ metaspace,
301
+ domainIbGibs: [r2_alpha_v3_source_rel8dBeta.ibGib],
302
+ conflictStrategy: SyncConflictStrategy.optimisticWithLCS,
303
+ senderIdentity: senderIdentityLatestSource,
304
+ fnSenderSecret: async () => SENDER_SECRET,
305
+ });
306
+ await r2_syncSaga.done;
307
+
308
+ await respecfully(sir, `r2 verify post`, async () => {
309
+ const alpha_sourceKV_afterSync = await senderCoordinator.getKnowledgeMap({
310
+ space: sourceSpace,
311
+ metaspace,
312
+ domainIbGibs: [r1_alpha_v0_source.ibGib]
313
+ });
314
+ const alpha_source_tipAddr = alpha_sourceKV_afterSync[alpha_tjpAddr];
315
+
316
+ const alpha_destKV_afterSync = await senderCoordinator.getKnowledgeMap({
317
+ space: destSpace,
318
+ metaspace,
319
+ domainIbGibs: [r1_alpha_v0_source.ibGib]
320
+ });
321
+ const alpha_dest_tipAddr = alpha_destKV_afterSync[alpha_tjpAddr];
322
+
323
+ await ifWe(sir, 'tip addrs match', async () => {
324
+ iReckon(sir, alpha_source_tipAddr).asTo('source/dest tip addrs').isGonnaBe(alpha_dest_tipAddr);
325
+ });
326
+
327
+ const resGet_alpha_source_tipAddr = await getFromSpace({ space: sourceSpace, addr: alpha_source_tipAddr! });
328
+ const gotten_alpha_source_tipIbGib = resGet_alpha_source_tipAddr.ibGibs![0] as IbGib_V1<TestData>;
329
+
330
+ await ifWe(sir, 'r2 basics of alpha merge', async () => {
331
+ iReckon(sir, alpha_source_tipAddr).not.isGonnaBe(r2_alpha_v3_source_rel8dBeta.addr);
332
+ iReckon(sir, alpha_source_tipAddr).not.isGonnaBe(r2_alpha_v2_dest_mut8FieldB.addr);
333
+
334
+ const r2_source_mut8Info = r2_alpha_v2_source_arbitraryMut8.infos[0] as TestMut8Info;
335
+ const r2_dest_mut8Info = r2_alpha_v2_dest_mut8FieldB.infos[0] as TestMut8Info;
336
+
337
+ iReckon(sir, gotten_alpha_source_tipIbGib.data![r2_source_mut8Info.key!]).isGonnaBe(r2_source_mut8Info.value!);
338
+ iReckon(sir, gotten_alpha_source_tipIbGib.data![r2_dest_mut8Info.key!]).isGonnaBe(r2_dest_mut8Info.value!);
339
+ });
340
+
341
+ await ifWe(sir, 'r2 beta and deps synced', async () => {
342
+ const [beta_dest] = await getIbGibsFromCache_fallbackToSpaces({
343
+ addrs: [r2_beta_v0_source.addr],
344
+ space: destSpace,
345
+ });
346
+ iReckon(sir, beta_dest).asTo('beta exists in dest').isGonnaBeTruthy();
347
+ });
348
+
349
+ await ifWe(sir, 'sessionIdentity evolved for Round 2', async () => {
350
+ const latestS = peerR2.currentSessionIdentity;
351
+ iReckon(sir, latestS).asTo('session identity exists').isGonnaBeTruthy();
352
+ if (latestS) {
353
+ iReckon(sir, latestS.data?.n).asTo('session identity data.n').isGonnaBe(3);
354
+ }
355
+ });
356
+ });
357
+
358
+ // Fetch evolved user identity from space
359
+ const latestSenderIdentityAddrR2 = await metaspace.getLatestAddr({
360
+ addr: getIbGibAddr({ ibGib: r1_senderIdentity_v0_source }),
361
+ space: sourceSpace,
362
+ });
363
+ if (!latestSenderIdentityAddrR2) {
364
+ throw new Error("Could not find latest sender identity after R2");
365
+ }
366
+ const resGetSenderIR2 = await getFromSpace({ space: sourceSpace, addr: latestSenderIdentityAddrR2 });
367
+ senderIdentityLatestSource = resGetSenderIR2.ibGibs![0] as KeystoneIbGib_V1;
368
+
369
+ // Copy/register evolved user identity to dest space
370
+ await metaspace.put({ ibGib: senderIdentityLatestSource, space: destSpace });
371
+ await metaspace.registerNewIbGib({ ibGib: senderIdentityLatestSource, space: destSpace });
372
+
373
+ // #endregion Round 2: Create Divergence
374
+
375
+ // #region Round 3: Multiple Timeline Conflicts
376
+
377
+ const _r3 = testTransformer.newRound({
378
+ name: 'r3_multiple_timeline_conflicts',
379
+ description: 'Both alpha AND beta have divergent edits on source vs dest - tests multiple simultaneous grafts'
380
+ });
381
+
382
+ // #region r3 source edits
383
+ const resGet_r3_alpha_source = await getFromSpace({ space: sourceSpace, addr: alpha_tjpAddr });
384
+ const r3_alpha_v3_graftPoint = resGet_r3_alpha_source.ibGibs![0];
385
+
386
+ const beta_tjpAddr = getTjpAddr({ ibGib: r2_beta_v0_source.ibGib, defaultIfNone: 'incomingAddr' })!;
387
+ const resGet_r3_beta_source = await getFromSpace({ space: sourceSpace, addr: beta_tjpAddr });
388
+ const r3_beta_v0_graftPoint = resGet_r3_beta_source.ibGibs![0];
389
+
390
+ // Mutate alpha fieldC on source
391
+ const r3_alpha_v4_source_mut8fieldC = await testTransformer.mut8({
392
+ ibGib: r3_alpha_v3_graftPoint,
393
+ in: 'source',
394
+ strField: 'fieldC',
395
+ name: 'r3_alpha_v4_source_mut8fieldC',
396
+ comments_snake_plus_CamelCase: 'postGraft',
397
+ });
398
+
399
+ // Mutate beta betaFieldA on source
400
+ const r3_beta_v1_source = await testTransformer.mut8({
401
+ ibGib: r3_beta_v0_graftPoint,
402
+ in: 'source',
403
+ strField: 'betaFieldA',
404
+ name: 'r3_beta_v1_source',
405
+ });
406
+ // #endregion r3 source edits
407
+
408
+ // #region r3 dest edits
409
+ const resGet_r3_alpha_dest = await getFromSpace({ space: destSpace, addr: alpha_tjpAddr });
410
+ const r3_alpha_v3_graftPoint_fromDest = resGet_r3_alpha_dest.ibGibs![0];
411
+
412
+ const resGet_r3_beta_dest = await getFromSpace({ space: destSpace, addr: beta_tjpAddr });
413
+ const r3_beta_v0_graftPoint_fromDest = resGet_r3_beta_dest.ibGibs![0];
414
+
415
+ // Mutate alpha fieldD on dest
416
+ const r3_alpha_v4_dest_mut8fieldD = await testTransformer.mut8({
417
+ ibGib: r3_alpha_v3_graftPoint_fromDest,
418
+ in: 'dest',
419
+ strField: 'fieldD',
420
+ name: 'r3_alpha_v4_dest_mut8fieldD',
421
+ comments_snake_plus_CamelCase: 'postGraft',
422
+ });
423
+
424
+ // Mutate beta betaFieldB on dest
425
+ const r3_beta_v1_dest = await testTransformer.mut8({
426
+ ibGib: r3_beta_v0_graftPoint_fromDest,
427
+ in: 'dest',
428
+ strField: 'betaFieldB',
429
+ name: 'r3_beta_v1_dest',
430
+ });
431
+ // #endregion r3 dest edits
432
+
433
+ await respecfully(sir, `r3 verify pre`, async () => {
434
+ await ifWe(sir, 'dest has both alpha and beta tips', async () => {
435
+ const destKV = await receiverCoordinator.getKnowledgeMap({
436
+ space: destSpace,
437
+ metaspace,
438
+ domainIbGibs: [r3_alpha_v3_graftPoint_fromDest, r3_beta_v0_graftPoint_fromDest]
439
+ });
440
+ iReckon(sir, !!destKV[alpha_tjpAddr]).isGonnaBeTruthy();
441
+ iReckon(sir, !!destKV[beta_tjpAddr]).isGonnaBeTruthy();
442
+ });
443
+ });
444
+
445
+ const peerR3 = await newTestPeer();
446
+ const r3_syncSaga = await senderCoordinator.sync({
447
+ peer: peerR3,
448
+ localSpace: sourceSpace,
449
+ metaspace,
450
+ domainIbGibs: [r3_alpha_v4_source_mut8fieldC.ibGib, r3_beta_v1_source.ibGib],
451
+ conflictStrategy: SyncConflictStrategy.optimisticWithLCS,
452
+ senderIdentity: senderIdentityLatestSource,
453
+ fnSenderSecret: async () => SENDER_SECRET,
454
+ });
455
+ await r3_syncSaga.done;
456
+
457
+ await respecfully(sir, `r3 verify post`, async () => {
458
+ const alpha_sourceKV_afterR3 = await senderCoordinator.getKnowledgeMap({ space: sourceSpace, metaspace, domainIbGibs: [r1_alpha_v0_source.ibGib] });
459
+ const r3_alpha_source_tipAddr = alpha_sourceKV_afterR3[alpha_tjpAddr];
460
+
461
+ const alpha_destKV_afterR3 = await senderCoordinator.getKnowledgeMap({ space: destSpace, metaspace, domainIbGibs: [r1_alpha_v0_source.ibGib] });
462
+ const r3_alpha_dest_tipAddr = alpha_destKV_afterR3[alpha_tjpAddr];
463
+
464
+ const beta_sourceKV_afterR3 = await senderCoordinator.getKnowledgeMap({ space: sourceSpace, metaspace, domainIbGibs: [r2_beta_v0_source.ibGib] });
465
+ const r3_beta_source_tipAddr = beta_sourceKV_afterR3[beta_tjpAddr];
466
+
467
+ const beta_destKV_afterR3 = await senderCoordinator.getKnowledgeMap({ space: destSpace, metaspace, domainIbGibs: [r2_beta_v0_source.ibGib] });
468
+ const r3_beta_dest_tipAddr = beta_destKV_afterR3[beta_tjpAddr];
469
+
470
+ await ifWe(sir, 'r3 tip addrs match (both timelines)', async () => {
471
+ iReckon(sir, r3_alpha_source_tipAddr).asTo('alpha tip').isGonnaBe(r3_alpha_dest_tipAddr);
472
+ iReckon(sir, r3_beta_source_tipAddr).asTo('beta tip').isGonnaBe(r3_beta_dest_tipAddr);
473
+ });
474
+
475
+ const resGet_r3_alpha_tip = await getFromSpace({ space: sourceSpace, addr: r3_alpha_source_tipAddr! });
476
+ const r3_alpha_tipIbGib = resGet_r3_alpha_tip.ibGibs![0] as IbGib_V1<TestData>;
477
+
478
+ const resGet_r3_beta_tip = await getFromSpace({ space: sourceSpace, addr: r3_beta_source_tipAddr! });
479
+ const r3_beta_tipIbGib = resGet_r3_beta_tip.ibGibs![0] as IbGib_V1<TestData>;
480
+
481
+ await ifWe(sir, 'r3 alpha merge has all four fields (commonField, fieldA, fieldB, fieldC, fieldD)', async () => {
482
+ const r3_alpha_v4_source_mut8Info = r3_alpha_v4_source_mut8fieldC.infos[0] as TestMut8Info;
483
+ const r3_alpha_v4_dest_mut8Info = r3_alpha_v4_dest_mut8fieldD.infos[0] as TestMut8Info;
484
+
485
+ iReckon(sir, r3_alpha_tipIbGib.data![r3_alpha_v4_source_mut8Info.key!]).isGonnaBe(r3_alpha_v4_source_mut8Info.value!);
486
+ iReckon(sir, r3_alpha_tipIbGib.data![r3_alpha_v4_dest_mut8Info.key!]).isGonnaBe(r3_alpha_v4_dest_mut8Info.value!);
487
+ });
488
+
489
+ await ifWe(sir, 'r3 beta merge has both fields (betaFieldA, betaFieldB)', async () => {
490
+ const r3_source_beta_mut8Info = r3_beta_v1_source.infos[0] as TestMut8Info;
491
+ const r3_dest_beta_mut8Info = r3_beta_v1_dest.infos[0] as TestMut8Info;
492
+
493
+ iReckon(sir, r3_beta_tipIbGib.data![r3_source_beta_mut8Info.key!]).isGonnaBe(r3_source_beta_mut8Info.value!);
494
+ iReckon(sir, r3_beta_tipIbGib.data![r3_dest_beta_mut8Info.key!]).isGonnaBe(r3_dest_beta_mut8Info.value!);
495
+ });
496
+
497
+ await ifWe(sir, 'sessionIdentity evolved for Round 3', async () => {
498
+ const latestS = peerR3.currentSessionIdentity;
499
+ iReckon(sir, latestS).asTo('session identity exists').isGonnaBeTruthy();
500
+ if (latestS) {
501
+ iReckon(sir, latestS.data?.n).asTo('session identity data.n').isGonnaBe(3);
502
+ }
503
+ });
504
+ });
505
+
506
+ // Fetch evolved user identity from space
507
+ const latestSenderIdentityAddrR3 = await metaspace.getLatestAddr({
508
+ addr: getIbGibAddr({ ibGib: r1_senderIdentity_v0_source }),
509
+ space: sourceSpace,
510
+ });
511
+ if (!latestSenderIdentityAddrR3) {
512
+ throw new Error("Could not find latest sender identity after R3");
513
+ }
514
+ const resGetSenderIR3 = await getFromSpace({ space: sourceSpace, addr: latestSenderIdentityAddrR3 });
515
+ senderIdentityLatestSource = resGetSenderIR3.ibGibs![0] as KeystoneIbGib_V1;
516
+
517
+ // Copy/register evolved user identity to dest space
518
+ await metaspace.put({ ibGib: senderIdentityLatestSource, space: destSpace });
519
+ await metaspace.registerNewIbGib({ ibGib: senderIdentityLatestSource, space: destSpace });
520
+
521
+ // #endregion Round 3: Multiple Timeline Conflicts
522
+
523
+ // #region Round 4: Chain Edits After Graft
524
+
525
+ const _r4 = testTransformer.newRound({
526
+ name: 'r4_chain_edits_after_graft',
527
+ description: 'Post-graft chain edits: mut8 → create gamma → rel8 gamma → mut8 again, tests continued editing on grafted timelines'
528
+ });
529
+
530
+ // #region r4 source edits
531
+ const resGet_r4_alpha_source = await getFromSpace({ space: sourceSpace, addr: alpha_tjpAddr });
532
+ const r4_alpha_v4_graftPoint = resGet_r4_alpha_source.ibGibs![0];
533
+
534
+ // Mutate alpha v5 (fieldE) from R3 graft point
535
+ const r4_alpha_v5_source = await testTransformer.mut8({
536
+ ibGib: r4_alpha_v4_graftPoint,
537
+ in: 'source',
538
+ strField: 'fieldE',
539
+ name: 'r4_alpha_v5_source',
540
+ comments_snake_plus_CamelCase: 'postGraft2',
541
+ });
542
+
543
+ // Create new gamma timeline
544
+ const r4_gamma_v0_source = await testTransformer.create({
545
+ atom: 'gamma',
546
+ in: 'source',
547
+ data: { gammaField: 'gamma created on source' },
548
+ name: 'r4_gamma_v0_source'
549
+ });
550
+
551
+ // Relate alpha to gamma (creates v6)
552
+ const r4_alpha_v6_source_rel8dGamma = await testTransformer.rel8({
553
+ stepInfo: r4_alpha_v5_source,
554
+ in: 'source',
555
+ targetIbGibs: [r4_gamma_v0_source.ibGib],
556
+ rel8nName: TEST_REL8N_NAME,
557
+ name: 'r4_alpha_v6_source_rel8dGamma'
558
+ });
559
+
560
+ // Mutate alpha again v7 (fieldF)
561
+ const r4_alpha_v7_source = await testTransformer.mut8({
562
+ ibGib: r4_alpha_v6_source_rel8dGamma.ibGib,
563
+ in: 'source',
564
+ strField: 'fieldF',
565
+ name: 'r4_alpha_v7_source',
566
+ comments_snake_plus_CamelCase: 'chainEnd',
567
+ });
568
+
569
+ // Retrieve beta R3 graft point from source
570
+ const resGet_r4_beta_source = await getFromSpace({ space: sourceSpace, addr: beta_tjpAddr });
571
+ const r4_beta_v1_graftPoint = resGet_r4_beta_source.ibGibs![0];
572
+
573
+ // Mutate beta v2 (betaFieldD) on source
574
+ const r4_beta_v2_source = await testTransformer.mut8({
575
+ ibGib: r4_beta_v1_graftPoint,
576
+ in: 'source',
577
+ strField: 'betaFieldD',
578
+ name: 'r4_beta_v2_source',
579
+ });
580
+ // #endregion r4 source edits
581
+
582
+ // #region r4 dest edits
583
+ // Retrieve alpha R3 graft point from dest
584
+ const resGet_r4_alpha_dest = await getFromSpace({ space: destSpace, addr: alpha_tjpAddr });
585
+ const r4_alpha_v4_graftPoint_fromDest = resGet_r4_alpha_dest.ibGibs![0];
586
+
587
+ // Mutate alpha v5 (fieldG) from R3 graft point
588
+ const r4_alpha_v5_dest = await testTransformer.mut8({
589
+ ibGib: r4_alpha_v4_graftPoint_fromDest,
590
+ in: 'dest',
591
+ strField: 'fieldG',
592
+ name: 'r4_alpha_v5_dest',
593
+ comments_snake_plus_CamelCase: 'postGraft2',
594
+ });
595
+
596
+ // Retrieve beta R3 graft point from dest
597
+ const resGet_r4_beta_dest = await getFromSpace({ space: destSpace, addr: beta_tjpAddr });
598
+ const r4_beta_v1_graftPoint_fromDest = resGet_r4_beta_dest.ibGibs![0];
599
+
600
+ // Mutate beta v2 (betaFieldC) on dest
601
+ const r4_beta_v2_dest = await testTransformer.mut8({
602
+ ibGib: r4_beta_v1_graftPoint_fromDest,
603
+ in: 'dest',
604
+ strField: 'betaFieldC',
605
+ name: 'r4_beta_v2_dest',
606
+ });
607
+ // #endregion r4 dest edits
608
+
609
+ await respecfully(sir, `r4 verify pre`, async () => {
610
+ await ifWe(sir, 'dest has alpha and beta post-R3 tips', async () => {
611
+ const destKV = await receiverCoordinator.getKnowledgeMap({
612
+ space: destSpace,
613
+ metaspace,
614
+ domainIbGibs: [r4_alpha_v4_graftPoint_fromDest, r4_beta_v1_graftPoint_fromDest]
615
+ });
616
+ iReckon(sir, !!destKV[alpha_tjpAddr]).isGonnaBeTruthy();
617
+ iReckon(sir, !!destKV[beta_tjpAddr]).isGonnaBeTruthy();
618
+ });
619
+ });
620
+
621
+ const peerR4 = await newTestPeer();
622
+ const r4_syncSaga = await senderCoordinator.sync({
623
+ peer: peerR4,
624
+ localSpace: sourceSpace,
625
+ metaspace,
626
+ domainIbGibs: [r4_alpha_v7_source.ibGib, r4_gamma_v0_source.ibGib, r4_beta_v2_source.ibGib],
627
+ conflictStrategy: SyncConflictStrategy.optimisticWithLCS,
628
+ senderIdentity: senderIdentityLatestSource,
629
+ fnSenderSecret: async () => SENDER_SECRET,
630
+ });
631
+ await r4_syncSaga.done;
632
+
633
+ await respecfully(sir, `r4 verify post`, async () => {
634
+ const gamma_tjpAddr = getTjpAddr({ ibGib: r4_gamma_v0_source.ibGib, defaultIfNone: 'incomingAddr' })!;
635
+
636
+ const r4_alpha_sourceKV = await senderCoordinator.getKnowledgeMap({ space: sourceSpace, metaspace, domainIbGibs: [r1_alpha_v0_source.ibGib] });
637
+ const r4_alpha_source_tipAddr = r4_alpha_sourceKV[alpha_tjpAddr];
638
+
639
+ const r4_alpha_destKV = await senderCoordinator.getKnowledgeMap({ space: destSpace, metaspace, domainIbGibs: [r1_alpha_v0_source.ibGib] });
640
+ const r4_alpha_dest_tipAddr = r4_alpha_destKV[alpha_tjpAddr];
641
+
642
+ const r4_beta_sourceKV = await senderCoordinator.getKnowledgeMap({ space: sourceSpace, metaspace, domainIbGibs: [r2_beta_v0_source.ibGib] });
643
+ const r4_beta_source_tipAddr = r4_beta_sourceKV[beta_tjpAddr];
644
+
645
+ const r4_beta_destKV = await senderCoordinator.getKnowledgeMap({ space: destSpace, metaspace, domainIbGibs: [r2_beta_v0_source.ibGib] });
646
+ const r4_beta_dest_tipAddr = r4_beta_destKV[beta_tjpAddr];
647
+
648
+ const r4_gamma_sourceKV = await senderCoordinator.getKnowledgeMap({ space: sourceSpace, metaspace, domainIbGibs: [r4_gamma_v0_source.ibGib] });
649
+ const r4_gamma_source_tipAddr = r4_gamma_sourceKV[gamma_tjpAddr];
650
+
651
+ const r4_gamma_destKV = await senderCoordinator.getKnowledgeMap({ space: destSpace, metaspace, domainIbGibs: [r4_gamma_v0_source.ibGib] });
652
+ const r4_gamma_dest_tipAddr = r4_gamma_destKV[gamma_tjpAddr];
653
+
654
+ await ifWe(sir, 'r4 tip addrs match (alpha, beta, gamma)', async () => {
655
+ iReckon(sir, r4_alpha_source_tipAddr).asTo('alpha tip').isGonnaBe(r4_alpha_dest_tipAddr);
656
+ iReckon(sir, r4_beta_source_tipAddr).asTo('beta tip').isGonnaBe(r4_beta_dest_tipAddr);
657
+ iReckon(sir, r4_gamma_source_tipAddr).asTo('gamma tip').isGonnaBe(r4_gamma_dest_tipAddr);
658
+ });
659
+
660
+ const resGet_r4_alpha_tip = await getFromSpace({ space: sourceSpace, addr: r4_alpha_source_tipAddr! });
661
+ const r4_alpha_tipIbGib = resGet_r4_alpha_tip.ibGibs![0] as IbGib_V1<TestData>;
662
+
663
+ const resGet_r4_beta_tip = await getFromSpace({ space: sourceSpace, addr: r4_beta_source_tipAddr! });
664
+ const r4_beta_tipIbGib = resGet_r4_beta_tip.ibGibs![0] as IbGib_V1<TestData>;
665
+
666
+ await ifWe(sir, 'r4 alpha has complete chain of edits and gamma relation', async () => {
667
+ const r4_source_alpha_v5_mut8Info = r4_alpha_v5_source.infos[0] as TestMut8Info;
668
+ const r4_source_alpha_v7_mut8Info = r4_alpha_v7_source.infos[0] as TestMut8Info;
669
+ const r4_dest_alpha_mut8Info = r4_alpha_v5_dest.infos[0] as TestMut8Info;
670
+
671
+ iReckon(sir, r4_alpha_tipIbGib.data![r4_source_alpha_v5_mut8Info.key!]).isGonnaBe(r4_source_alpha_v5_mut8Info.value!);
672
+ iReckon(sir, r4_alpha_tipIbGib.data![r4_source_alpha_v7_mut8Info.key!]).isGonnaBe(r4_source_alpha_v7_mut8Info.value!);
673
+ iReckon(sir, r4_alpha_tipIbGib.data![r4_dest_alpha_mut8Info.key!]).isGonnaBe(r4_dest_alpha_mut8Info.value!);
674
+
675
+ const gammaAddr = getIbGibAddr({ ibGib: r4_gamma_v0_source.ibGib });
676
+ const alphaRel8ns = r4_alpha_tipIbGib.rel8ns?.[TEST_REL8N_NAME] || [];
677
+ iReckon(sir, alphaRel8ns.includes(gammaAddr)).isGonnaBeTrue();
678
+ });
679
+
680
+ await ifWe(sir, 'r4 beta has all edits', async () => {
681
+ const r4_source_beta_mut8Info = r4_beta_v2_source.infos[0] as TestMut8Info;
682
+ const r4_dest_beta_mut8Info = r4_beta_v2_dest.infos[0] as TestMut8Info;
683
+
684
+ iReckon(sir, r4_beta_tipIbGib.data![r4_source_beta_mut8Info.key!]).isGonnaBe(r4_source_beta_mut8Info.value!);
685
+ iReckon(sir, r4_beta_tipIbGib.data![r4_dest_beta_mut8Info.key!]).isGonnaBe(r4_dest_beta_mut8Info.value!);
686
+ });
687
+
688
+ await ifWe(sir, 'r4 gamma synced with deps', async () => {
689
+ const [gamma_dest] = await getIbGibsFromCache_fallbackToSpaces({
690
+ addrs: [r4_gamma_v0_source.addr],
691
+ space: destSpace,
692
+ });
693
+ iReckon(sir, gamma_dest).asTo('gamma exists in dest').isGonnaBeTruthy();
694
+ });
695
+
696
+ await ifWe(sir, 'sessionIdentity evolved for Round 4', async () => {
697
+ const latestS = peerR4.currentSessionIdentity;
698
+ iReckon(sir, latestS).asTo('session identity exists').isGonnaBeTruthy();
699
+ if (latestS) {
700
+ iReckon(sir, latestS.data?.n).asTo('session identity data.n').isGonnaBe(3);
701
+ }
702
+ });
703
+ });
704
+
705
+ // #endregion Round 4: Chain Edits After Graft
706
+ });