@ibgib/core-gib 0.1.42 → 0.1.43

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.
@@ -148,7 +148,7 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
148
148
  });
149
149
  const r1_alpha_source_tipAddr = r1_alpha_sourceKV[alpha_tjpAddr];
150
150
  if (!r1_alpha_source_tipAddr) {
151
- ifWeMight(sir, 'r1_alpha_source_tipAddr is falsy?', async () => {
151
+ ifWe(sir, 'r1_alpha_source_tipAddr is falsy?', async () => {
152
152
  iReckon(sir, true).asTo('fail').isGonnaBeFalse();
153
153
  });
154
154
  return; /* <<<< returns early */
@@ -161,17 +161,17 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
161
161
  });
162
162
  const r1_alpha_dest_tipAddr = r1_alpha_destKV[alpha_tjpAddr];
163
163
  if (!r1_alpha_dest_tipAddr) {
164
- ifWeMight(sir, 'r1_alpha_dest_tipAddr is falsy?', async () => {
164
+ ifWe(sir, 'r1_alpha_dest_tipAddr is falsy?', async () => {
165
165
  iReckon(sir, true).asTo('fail').isGonnaBeFalse();
166
166
  });
167
167
  return; /* <<<< returns early */
168
168
  }
169
169
 
170
- await ifWeMight(sir, 'r1 tip addrs match', async () => {
170
+ await ifWe(sir, 'r1 tip addrs match', async () => {
171
171
  iReckon(sir, r1_alpha_source_tipAddr).asTo('R1 source/dest have same tip').isGonnaBe(r1_alpha_dest_tipAddr);
172
172
  });
173
173
 
174
- await ifWeMight(sir, 'r1 text synced correctly', async () => {
174
+ await ifWe(sir, 'r1 text synced correctly', async () => {
175
175
  if (!r1_alpha_dest_tipAddr) {
176
176
  throw new Error(`r1_dest_tipAddr is null/undefined (E: 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d)`);
177
177
  }
@@ -181,7 +181,7 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
181
181
  iReckon(sir, destTipIbGib.data!.text).asTo('Dest has initial text').isGonnaBe(INITIAL_TEXT);
182
182
  });
183
183
 
184
- await ifWeMight(sir, 'r1 dep graphs synced', async () => {
184
+ await ifWe(sir, 'r1 dep graphs synced', async () => {
185
185
  const [r1_alpha_source_tip] = await getIbGibsFromCache_fallbackToSpaces({
186
186
  addrs: [r1_alpha_source_tipAddr],
187
187
  space: sourceSpace,
@@ -260,7 +260,7 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
260
260
  // #endregion r2 dest edits
261
261
 
262
262
  await respecfully(sir, `r2 verify pre`, async () => {
263
- await ifWeMight(sir, 'texts as expected', async () => {
263
+ await ifWe(sir, 'texts as expected', async () => {
264
264
  // before the sync, each side only has their edit. after the sync,
265
265
  // both sides should have both prepended and appended text
266
266
  iReckon(sir, r2_alpha_v1_source_appendedText.ibGib.data?.text.includes(INITIAL_TEXT)).asTo('alpha source has initial text').isGonnaBeTrue();
@@ -296,14 +296,14 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
296
296
  const kv_dest = await senderCoordinator.getKnowledgeMap({ space: destSpace, metaspace, domainIbGibs: [r1_alpha_v0_source.ibGib] });
297
297
  const r2_alpha_source_tipAddr = kv_source[alpha_tjpAddr];
298
298
  if (!r2_alpha_source_tipAddr) {
299
- await ifWeMight(sir, 'r2_alpha_source_tipAddr falsy?', async () => {
299
+ await ifWe(sir, 'r2_alpha_source_tipAddr falsy?', async () => {
300
300
  iReckon(sir, true).asTo('fails').isGonnaBe(false);
301
301
  });
302
302
  return; /* <<<< returns early */
303
303
  }
304
304
  const r2_alpha_dest_tipAddr = kv_dest[alpha_tjpAddr];
305
305
  if (!r2_alpha_dest_tipAddr) {
306
- await ifWeMight(sir, 'r2_alpha_dest_tipAddr falsy?', async () => {
306
+ await ifWe(sir, 'r2_alpha_dest_tipAddr falsy?', async () => {
307
307
  iReckon(sir, true).asTo('fails').isGonnaBe(false);
308
308
  });
309
309
  return; /* <<<< returns early */
@@ -317,11 +317,11 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
317
317
  space: sourceSpace,
318
318
  });
319
319
 
320
- await ifWeMight(sir, 'r2 tip addrs match', async () => {
320
+ await ifWe(sir, 'r2 tip addrs match', async () => {
321
321
  iReckon(sir, r2_alpha_source_tipAddr).asTo('alpha').isGonnaBe(r2_alpha_dest_tipAddr);
322
322
  });
323
323
 
324
- await ifWeMight(sir, 'r2 text merged correctly', async () => {
324
+ await ifWe(sir, 'r2 text merged correctly', async () => {
325
325
  // before the sync, each side only has their edit. after the sync,
326
326
  // both sides should have both prepended and appended text
327
327
  iReckon(sir, r2_alpha_v1_source_appendedText.ibGib.data?.text.includes(INITIAL_TEXT)).asTo('alpha source has initial text').isGonnaBeTrue();
@@ -340,7 +340,7 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
340
340
  iReckon(sir, text).asTo('R2 has both prepend and append').isGonnaBe(DEST_PREPEND + INITIAL_TEXT + SOURCE_APPEND);
341
341
  });
342
342
 
343
- await ifWeMight(sir, 'r2 dep graphs synced', async () => {
343
+ await ifWe(sir, 'r2 dep graphs synced', async () => {
344
344
  // alpha's full dep graph should exist on dest
345
345
  const depGraph_alpha_source = await getDependencyGraph({
346
346
  ibGib: r2_alpha_source_tip,
@@ -414,7 +414,7 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
414
414
  // // #endregion r3 dest edits
415
415
 
416
416
  // await respecfully(sir, `r3 verify pre`, async () => {
417
- // await ifWeMight(sir, 'dest has alpha after R2 graft', async () => {
417
+ // await ifWe(sir, 'dest has alpha after R2 graft', async () => {
418
418
  // const kv = await receiverCoordinator.getKnowledgeMap({ space: destSpace, metaspace, domainIbGibs: [r3_v0_graft_fromDest] });
419
419
  // iReckon(sir, !!kv[alpha_tjpAddr]).asTo('dest has tip').isGonnaBeTrue();
420
420
  // });
@@ -445,11 +445,11 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
445
445
  // const r3_tip_s = kv_s[alpha_tjpAddr];
446
446
  // const r3_tip_d = kv_d[alpha_tjpAddr];
447
447
 
448
- // await ifWeMight(sir, 'r3 tip addrs match', async () => {
448
+ // await ifWe(sir, 'r3 tip addrs match', async () => {
449
449
  // iReckon(sir, r3_tip_s).asTo('R3 tips match').isGonnaBe(r3_tip_d);
450
450
  // });
451
451
 
452
- // await ifWeMight(sir, 'r3 both paragraph edits merged', async () => {
452
+ // await ifWe(sir, 'r3 both paragraph edits merged', async () => {
453
453
  // const res = await getFromSpace({ space: sourceSpace, addr: r3_tip_s! });
454
454
  // const tip = res.ibGibs![0] as IbGib_V1<TestData>;
455
455
  // const mergedText = tip.data!.text!;
@@ -468,7 +468,7 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
468
468
  // .isGonnaBeTrue();
469
469
  // });
470
470
 
471
- // await ifWeMight(sir, 'r3 dep graphs synced', async () => {
471
+ // await ifWe(sir, 'r3 dep graphs synced', async () => {
472
472
  // const [d] = await getIbGibsFromCache_fallbackToSpaces({ addrs: [r3_tip_s!], space: destSpace });
473
473
  // iReckon(sir, d).asTo('exists dest').isGonnaBeTruthy();
474
474
  // });
@@ -502,7 +502,7 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
502
502
  // // #endregion r4 dest edits
503
503
 
504
504
  // await respecfully(sir, `r4 verify pre`, async () => {
505
- // await ifWeMight(sir, 'dest has alpha after R3 graft', async () => {
505
+ // await ifWe(sir, 'dest has alpha after R3 graft', async () => {
506
506
  // // TODO: Verify pre-sync state
507
507
  // });
508
508
  // });
@@ -512,16 +512,16 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
512
512
  // // TODO: Add sync operation
513
513
 
514
514
  // await respecfully(sir, `r4 verify post`, async () => {
515
- // await ifWeMight(sir, 'r4 tip addrs match', async () => {
515
+ // await ifWe(sir, 'r4 tip addrs match', async () => {
516
516
  // // TODO: Verify tips match
517
517
  // });
518
518
 
519
- // await ifWeMight(sir, 'r4 LCS merged both word changes', async () => {
519
+ // await ifWe(sir, 'r4 LCS merged both word changes', async () => {
520
520
  // // TODO: Verify text has both source and dest word changes
521
521
  // // TODO: Verify LCS algorithm preserved both edits correctly
522
522
  // });
523
523
 
524
- // await ifWeMight(sir, 'r4 dep graphs synced', async () => {
524
+ // await ifWe(sir, 'r4 dep graphs synced', async () => {
525
525
  // // TODO: Verify dep graphs
526
526
  // });
527
527
  // });
@@ -556,7 +556,7 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
556
556
  // // #endregion r5 dest edits
557
557
 
558
558
  // await respecfully(sir, `r5 verify pre`, async () => {
559
- // await ifWeMight(sir, 'dest has alpha after R4 graft', async () => {
559
+ // await ifWe(sir, 'dest has alpha after R4 graft', async () => {
560
560
  // // TODO: Verify pre-sync state
561
561
  // });
562
562
  // });
@@ -566,24 +566,24 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
566
566
  // // TODO: Add sync operation
567
567
 
568
568
  // await respecfully(sir, `r5 verify post`, async () => {
569
- // await ifWeMight(sir, 'r5 tip addrs match', async () => {
569
+ // await ifWe(sir, 'r5 tip addrs match', async () => {
570
570
  // // TODO: Verify tips match
571
571
  // });
572
572
 
573
- // await ifWeMight(sir, 'r5 text field merged', async () => {
573
+ // await ifWe(sir, 'r5 text field merged', async () => {
574
574
  // // TODO: Verify text field has both source and dest changes
575
575
  // });
576
576
 
577
- // await ifWeMight(sir, 'r5 description field merged', async () => {
577
+ // await ifWe(sir, 'r5 description field merged', async () => {
578
578
  // // TODO: Verify description field has both source and dest changes
579
579
  // });
580
580
 
581
- // await ifWeMight(sir, 'r5 both fields independently LCS-merged', async () => {
581
+ // await ifWe(sir, 'r5 both fields independently LCS-merged', async () => {
582
582
  // // TODO: Verify each field was merged independently
583
583
  // // TODO: Ensure one field's merge didn't affect the other
584
584
  // });
585
585
 
586
- // await ifWeMight(sir, 'r5 dep graphs synced', async () => {
586
+ // await ifWe(sir, 'r5 dep graphs synced', async () => {
587
587
  // // TODO: Verify dep graphs
588
588
  // });
589
589
  // });
@@ -0,0 +1,316 @@
1
+ /**
2
+ * @module sync-innerspace-dest-ahead.respec
3
+ *
4
+ * Verifies Sync Scenario where the receiver is ahead, with identity enabled.
5
+ */
6
+
7
+ import {
8
+ respecfully, lastOfAll, ifWe, iReckon,
9
+ ifWeMight
10
+ } from '@ibgib/helper-gib/dist/respec-gib/respec-gib.mjs';
11
+ const maam = `[${import.meta.url}]`, sir = maam;
12
+ import { clone, delay, extractErrorMsg, pretty } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
13
+ import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
14
+ import { IbGibAddr } from '@ibgib/ts-gib/dist/types.mjs';
15
+
16
+ import { SyncSagaCoordinator } from './sync-saga-coordinator.mjs';
17
+ import { putInSpace, getFromSpace, registerNewIbGib } from '../witness/space/space-helper.mjs';
18
+ import { Metaspace_Innerspace } from '../witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.mjs';
19
+ import { InnerSpace_V1 } from '../witness/space/inner-space/inner-space-v1.mjs';
20
+ import { createTimelineRootTestHelper, getTestKeystoneServiceHelper } from '../test-helpers.mjs';
21
+ import { mut8Timeline } from '../timeline/timeline-api.mjs';
22
+ import { DEFAULT_INNER_SPACE_DATA_V1 } from '../witness/space/inner-space/inner-space-types.mjs';
23
+ import { toDto } from '../common/other/ibgib-helper.mjs';
24
+ import { SyncPeerInnerspace_V1 } from './sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs';
25
+ import { SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1 } from './sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mjs';
26
+ import { GetIbGibResult } from '../common/other/other-types.mjs';
27
+ import { IbGibSpaceAny } from '../witness/space/space-base-v1.mjs';
28
+ import { getDependencyGraph } from '../common/other/graph-helper.mjs';
29
+
30
+ const logalot = false;
31
+ const lc = `[sync-innerspace-dest-ahead.respec]`;
32
+
33
+ await respecfully(sir, `Sync InnerSpaces (Dest Ahead)`, async () => {
34
+
35
+ let metaspace: Metaspace_Innerspace;
36
+ let sourceSpace: InnerSpace_V1;
37
+ let destSpace: InnerSpace_V1;
38
+
39
+ interface TestData {
40
+ type: string;
41
+ label?: string;
42
+ uuid?: string;
43
+ n?: number;
44
+ }
45
+
46
+ await respecfully(sir, `Dest Ahead (Remote Newer)`, async () => {
47
+ // 1. Setup Spaces
48
+ metaspace = new Metaspace_Innerspace(undefined);
49
+ await metaspace.initialize({
50
+ getFnAlert: () => async ({ title, msg }) => { },
51
+ getFnPrompt: () => async ({ title, msg }) => { return ''; },
52
+ getFnPromptPassword: () => async (title, msg) => { return null; },
53
+ });
54
+ while (!metaspace.initialized) { await delay(10); }
55
+
56
+ const defaultLocalUserSpace = await metaspace.getLocalUserSpace({ lock: false });
57
+ await defaultLocalUserSpace!.initialized;
58
+
59
+ sourceSpace = new InnerSpace_V1({
60
+ ...DEFAULT_INNER_SPACE_DATA_V1,
61
+ name: 'source',
62
+ uuid: 'source_uuid',
63
+ description: 'source test space',
64
+ });
65
+ await sourceSpace.initialized;
66
+
67
+ destSpace = new InnerSpace_V1({
68
+ ...DEFAULT_INNER_SPACE_DATA_V1,
69
+ name: 'dest',
70
+ uuid: 'dest_uuid',
71
+ description: 'dest test space',
72
+ });
73
+ await destSpace.initialized;
74
+
75
+ // 2. Seed Data
76
+ // Root -> V1 (Shared) -> V2 (Dest has New)
77
+ // Source only has V1.
78
+
79
+ const v0 = await createTimelineRootTestHelper<TestData>({
80
+ ib: 'timeline_root_ff',
81
+ data: { type: 'root', label: 'Root' },
82
+ space: sourceSpace,
83
+ });
84
+ const addrV0 = getIbGibAddr({ ibGib: v0 });
85
+ console.log(pretty(v0));
86
+
87
+ // V1 (Both have it, but we create in source and copy to dest)
88
+ const v1 = await mut8Timeline<TestData>({
89
+ timeline: v0,
90
+ mut8Opts: { dataToAddOrPatch: { type: 'comment', label: 'V1' } },
91
+ metaspace,
92
+ space: sourceSpace,
93
+ });
94
+ const addrV1 = getIbGibAddr({ ibGib: v1 });
95
+ console.log(pretty(v1));
96
+
97
+
98
+ // Transfer Root & V1 to Dest
99
+ const initialDepGraph = await getDependencyGraph({ ibGibs: [v0, v1], space: sourceSpace });
100
+ await putInSpace({ space: destSpace, ibGibs: Object.values(initialDepGraph) }); // Naive seeding
101
+ await registerNewIbGib({ space: destSpace, ibGib: v0 });
102
+ await registerNewIbGib({ space: destSpace, ibGib: v1 });
103
+
104
+ // V2 (Created in Dest ONLY)
105
+ const v2 = await mut8Timeline<TestData>({
106
+ timeline: v1, // v1 is in memory, linked to source, but we want to Mutate IN DEST SPACE
107
+ mut8Opts: { dataToAddOrPatch: { type: 'comment', label: 'V2' } },
108
+ metaspace,
109
+ space: destSpace, // Mutate in Dest
110
+ });
111
+ const addrV2 = getIbGibAddr({ ibGib: v2 });
112
+ console.log(pretty(v2));
113
+
114
+ const fnAddrExistsInSpace = async (addr: IbGibAddr, space: IbGibSpaceAny) => {
115
+ const resGet = await getFromSpace({ addr, space });
116
+ return resGet.success && resGet.ibGibs && resGet.ibGibs.length === 1;
117
+ }
118
+
119
+ await ifWeMight(sir, 'verify setup', async () => {
120
+ // Ensure V2 is ONLY in Dest (it is, per `space: destSpace`)
121
+ // Ensure Source does NOT have V2
122
+ iReckon(sir, await fnAddrExistsInSpace(addrV0, sourceSpace)).asTo('source has V0').isGonnaBeTrue();
123
+ iReckon(sir, await fnAddrExistsInSpace(addrV1, sourceSpace)).asTo('source has V1').isGonnaBeTrue();
124
+ iReckon(sir, await fnAddrExistsInSpace(addrV2, sourceSpace)).asTo('source has V2').isGonnaBeFalse();
125
+ iReckon(sir, await fnAddrExistsInSpace(addrV0, destSpace)).asTo('dest has V0').isGonnaBeTrue();
126
+ iReckon(sir, await fnAddrExistsInSpace(addrV1, destSpace)).asTo('dest has V1').isGonnaBeTrue();
127
+ iReckon(sir, await fnAddrExistsInSpace(addrV2, destSpace)).asTo('dest has V2').isGonnaBeTrue();
128
+ });
129
+
130
+ // 3. Setup Sync
131
+ const mockKeystone = await getTestKeystoneServiceHelper();
132
+ const senderCoordinator = new SyncSagaCoordinator(mockKeystone);
133
+ const receiverCoordinator = new SyncSagaCoordinator(mockKeystone);
134
+
135
+ const peer = new SyncPeerInnerspace_V1(clone(SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1));
136
+ await peer.initialized;
137
+ await peer.initializeSender({
138
+ senderSpace: sourceSpace, // "Client"
139
+ receiverSpace: destSpace, // "Server"
140
+ receiverCoordinator,
141
+ receiverMetaspace: metaspace,
142
+ });
143
+
144
+ // 4. Run Sync (Source Pushes V1)
145
+ console.log(`${lc} Running Sync...`);
146
+ const { done, sagaId, updates$ } = await senderCoordinator.sync({
147
+ peer: peer,
148
+ localSpace: sourceSpace,
149
+ metaspace: metaspace,
150
+ domainIbGibs: [v1], // Source tries to push V1
151
+ useSessionIdentity: true,
152
+ });
153
+ await done;
154
+
155
+ // 5. Verify Sync (v2 should be in both source and dest now)
156
+ console.log(`${lc} Verifying Sync...`);
157
+
158
+ await ifWeMight(sir, `verify v2 now also in source`, async () => {
159
+ // Verify Tip (V2)
160
+
161
+ iReckon(sir, await fnAddrExistsInSpace(addrV0, sourceSpace)).asTo('source has V0').isGonnaBeTrue();
162
+ iReckon(sir, await fnAddrExistsInSpace(addrV1, sourceSpace)).asTo('source has V1').isGonnaBeTrue();
163
+ iReckon(sir, await fnAddrExistsInSpace(addrV2, sourceSpace)).asTo('source has V2').isGonnaBeTrue();
164
+ iReckon(sir, await fnAddrExistsInSpace(addrV0, destSpace)).asTo('dest has V0').isGonnaBeTrue();
165
+ iReckon(sir, await fnAddrExistsInSpace(addrV1, destSpace)).asTo('dest has V1').isGonnaBeTrue();
166
+ iReckon(sir, await fnAddrExistsInSpace(addrV2, destSpace)).asTo('dest has V2').isGonnaBeTrue();
167
+
168
+ });
169
+
170
+ await ifWeMight(sir, `dependency graphs the same`, async () => {
171
+
172
+ const sourceDepGraph = await getDependencyGraph({
173
+ ibGibAddr: addrV2,
174
+ space: sourceSpace,
175
+ });
176
+ const destDepGraph = await getDependencyGraph({
177
+ ibGibAddr: addrV2,
178
+ space: destSpace,
179
+ });
180
+
181
+ const sourceDepGraphAddrs = Object.keys(sourceDepGraph);
182
+ const destDepGraphAddrs = Object.keys(destDepGraph);
183
+
184
+ iReckon(sir, sourceDepGraphAddrs.length === destDepGraphAddrs.length).asTo('dep graphs same size').isGonnaBeTrue();
185
+
186
+ sourceDepGraphAddrs.forEach(sourceDepAddr => {
187
+ iReckon(sir, destDepGraphAddrs.includes(sourceDepAddr)).asTo(`${sourceDepAddr} is both graphs`).isGonnaBeTrue();
188
+ });
189
+ });
190
+
191
+ // ========================================================================
192
+ // IDENTITY-RELATED ASSERTIONS (TDD - Expose Implementation Gaps)
193
+ // ========================================================================
194
+
195
+ // Need to capture session identity and saga context from sync result
196
+ // For now, we'll retrieve from spaces after sync completes
197
+ let sessionKeystoneAddr: IbGibAddr | undefined;
198
+
199
+ await ifWeMight(sir, 'IDENTITY: session keystone exists in sender space', async () => {
200
+ // Session keystone should be in sender's durable space
201
+ // Since we can't enumerate space easily, we verify indirectly:
202
+ // The fact that sync completed means keystone was findable
203
+
204
+ // TODO: Capture sessionKeystoneAddr from sync() return value
205
+ // For now, placeholder passes
206
+ iReckon(sir, true)
207
+ .asTo('sync completed (keystone must exist)')
208
+ .isGonnaBeTrue();
209
+ });
210
+
211
+ await ifWeMight(sir, 'IDENTITY: session keystone exists in receiver space', async () => {
212
+ // Session keystone should be transferred to receiver's durable space
213
+ iReckon(sir, sessionKeystoneAddr)
214
+ .asTo('session keystone address was captured')
215
+ .isGonnaBeTruthy();
216
+
217
+ if (sessionKeystoneAddr) {
218
+ const destResult = await getFromSpace({ addr: sessionKeystoneAddr, space: destSpace });
219
+ iReckon(sir, destResult.success)
220
+ .asTo('receiver has session keystone')
221
+ .isGonnaBeTrue();
222
+ }
223
+ });
224
+
225
+ await ifWeMight(sir, 'IDENTITY: saga frames are signed', async () => {
226
+ // TODO: Get saga frames and check each has a proof
227
+ // This will FAIL when we actually check - that's the point (TDD RED)
228
+
229
+ iReckon(sir, false)
230
+ .asTo('saga frames have proofs (NOT IMPLEMENTED - should fail)')
231
+ .isGonnaBeTrue();
232
+ });
233
+
234
+ await ifWeMight(sir, 'IDENTITY: frame signatures are valid', async () => {
235
+ // TODO: For each saga frame, validate proof against session keystone
236
+ // const isValid = await validateProofWithKeystone({
237
+ // proof: frame.proof,
238
+ // keystone: sessionKeystone,
239
+ // targetFrame: frame
240
+ // });
241
+ // iReckon(sir, isValid).asTo('proof is valid').isGonnaBeTrue();
242
+
243
+ // Placeholder for now
244
+ iReckon(sir, true)
245
+ .asTo('proof validation not yet implemented')
246
+ .isGonnaBeTrue();
247
+ });
248
+
249
+ await ifWeMight(sir, 'IDENTITY: session keystone challenges are depleted', async () => {
250
+ // TODO: Session keystone should evolve after signing frames
251
+ // This will FAIL because keystone evolution not implemented yet
252
+
253
+ iReckon(sir, false)
254
+ .asTo('challenges depleted (NOT IMPLEMENTED - should fail)')
255
+ .isGonnaBeTrue();
256
+ });
257
+
258
+ await ifWeMight(sir, 'IDENTITY: frame timestamps are present and fresh', async () => {
259
+ // TODO: Check each frame has timestamp in proof claim
260
+ // const claim = JSON.parse(frame.proof.claim.scope);
261
+ // iReckon(sir, claim.timestamp).asTo('has timestamp').isGonnaBeTruthy();
262
+ // const age = Date.now() - claim.timestamp;
263
+ // iReckon(sir, age < 60000).asTo('timestamp is fresh (<60s)').isGonnaBeTrue();
264
+
265
+ // Placeholder
266
+ iReckon(sir, true)
267
+ .asTo('timestamp validation not yet implemented')
268
+ .isGonnaBeTrue();
269
+ });
270
+
271
+ await ifWeMight(sir, 'IDENTITY: keystone has no hard links to domain ibgibs', async () => {
272
+ if (sessionKeystoneAddr) {
273
+ const keystoneResult = await getFromSpace({
274
+ addr: sessionKeystoneAddr,
275
+ space: sourceSpace
276
+ });
277
+
278
+ if (keystoneResult.success && keystoneResult.ibGibs && keystoneResult.ibGibs.length > 0) {
279
+ const keystone = keystoneResult.ibGibs[0];
280
+ const rel8ns = keystone.rel8ns || {};
281
+ const allRel8nAddrs = Object.values(rel8ns)
282
+ .flat()
283
+ .filter(addr => typeof addr === 'string');
284
+
285
+ const domainAddrs = [addrV0, addrV1, addrV2];
286
+
287
+ for (const domainAddr of domainAddrs) {
288
+ iReckon(sir, allRel8nAddrs.includes(domainAddr))
289
+ .asTo(`keystone does not hard link to ${domainAddr}`)
290
+ .isGonnaBeFalse();
291
+ }
292
+ }
293
+ }
294
+ });
295
+
296
+ await ifWeMight(sir, 'IDENTITY: saga frames have no hard links to domain ibgibs', async () => {
297
+ // Saga frames should NOT have hard links to domain ibgibs
298
+ // This currently PASSES but will expose issues if hard links exist
299
+
300
+ iReckon(sir, true)
301
+ .asTo('hard link validation (placeholder)')
302
+ .isGonnaBeTrue();
303
+
304
+ // TODO: Get saga frames and check their rel8ns
305
+ // for (const frame of sagaFrames) {
306
+ // const rel8nAddrs = Object.values(frame.rel8ns || {}).flat();
307
+ // for (const domainAddr of [addrV0, addrV1, addrV2]) {
308
+ // iReckon(sir, rel8nAddrs.includes(domainAddr)).asTo get('no hard link').isGonnaBeFalse();
309
+ // }
310
+ // }
311
+ });
312
+
313
+
314
+ });
315
+
316
+ });
@@ -197,7 +197,7 @@ export class SyncSagaCoordinator {
197
197
 
198
198
  // BOOTSTRAP IDENTITY (Session Keystone)
199
199
  const sessionIdentity = useSessionIdentity
200
- ? await this.getSessionIdentity({ sagaId, metaspace, tempSpace })
200
+ ? await this.getSessionIdentity({ sagaId, metaspace, localSpace })
201
201
  : undefined;
202
202
  // if (logalot) { console.log(`${lc} sessionIdentity: ${sessionIdentity ? pretty(sessionIdentity) : 'undefined'} (I: abc01872800b3a66b819a05898bba826)`); }
203
203
 
@@ -328,11 +328,11 @@ export class SyncSagaCoordinator {
328
328
  private async getSessionIdentity({
329
329
  sagaId,
330
330
  metaspace,
331
- tempSpace,
331
+ localSpace,
332
332
  }: {
333
333
  sagaId: string,
334
334
  metaspace: MetaspaceService,
335
- tempSpace: IbGibSpaceAny,
335
+ localSpace: IbGibSpaceAny,
336
336
  }): Promise<KeystoneIbGib_V1> {
337
337
  const lc = `${this.lc}[${this.getSessionIdentity.name}]`;
338
338
  try {
@@ -349,7 +349,7 @@ export class SyncSagaCoordinator {
349
349
  masterSecret: sagaId,
350
350
  configs: [config],
351
351
  metaspace,
352
- space: tempSpace
352
+ space: localSpace // ✅ FIXED: Use durable space, not temp space
353
353
  });
354
354
 
355
355
  return sessionIdentity;