@ibgib/core-gib 0.1.61 → 0.1.63

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 (100) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/keystone/keystone-constants.d.mts +0 -1
  3. package/dist/keystone/keystone-constants.d.mts.map +1 -1
  4. package/dist/keystone/keystone-constants.mjs +0 -1
  5. package/dist/keystone/keystone-constants.mjs.map +1 -1
  6. package/dist/keystone/keystone-helpers.d.mts +23 -1
  7. package/dist/keystone/keystone-helpers.d.mts.map +1 -1
  8. package/dist/keystone/keystone-helpers.mjs +98 -5
  9. package/dist/keystone/keystone-helpers.mjs.map +1 -1
  10. package/dist/keystone/keystone-service-v1.d.mts +39 -2
  11. package/dist/keystone/keystone-service-v1.d.mts.map +1 -1
  12. package/dist/keystone/keystone-service-v1.mjs +175 -3
  13. package/dist/keystone/keystone-service-v1.mjs.map +1 -1
  14. package/dist/keystone/keystone-service-v1.respec.mjs +397 -42
  15. package/dist/keystone/keystone-service-v1.respec.mjs.map +1 -1
  16. package/dist/keystone/keystone-types.d.mts +54 -0
  17. package/dist/keystone/keystone-types.d.mts.map +1 -1
  18. package/dist/keystone/policy/keystone-profile-builder.d.mts +1 -1
  19. package/dist/keystone/policy/keystone-profile-builder.d.mts.map +1 -1
  20. package/dist/keystone/policy/keystone-profile-builder.mjs +8 -0
  21. package/dist/keystone/policy/keystone-profile-builder.mjs.map +1 -1
  22. package/dist/keystone/policy/profiles/profile-domain.json +84 -0
  23. package/dist/keystone/policy/profiles/profile-sync.json +84 -0
  24. package/dist/keystone/strategy/hash-reveal-v1/hash-reveal-v1.d.mts +8 -0
  25. package/dist/keystone/strategy/hash-reveal-v1/hash-reveal-v1.d.mts.map +1 -1
  26. package/dist/keystone/strategy/hash-reveal-v1/hash-reveal-v1.mjs +15 -1
  27. package/dist/keystone/strategy/hash-reveal-v1/hash-reveal-v1.mjs.map +1 -1
  28. package/dist/sync/sync-conflict-adv-multitimelines.withid.respec.mjs +16 -4
  29. package/dist/sync/sync-conflict-adv-multitimelines.withid.respec.mjs.map +1 -1
  30. package/dist/sync/sync-conflict-basic-divergence.withid.respec.mjs +4 -1
  31. package/dist/sync/sync-conflict-basic-divergence.withid.respec.mjs.map +1 -1
  32. package/dist/sync/sync-conflict-basic-multitimelines.withid.respec.mjs +4 -1
  33. package/dist/sync/sync-conflict-basic-multitimelines.withid.respec.mjs.map +1 -1
  34. package/dist/sync/sync-conflict-text-merge.withid.respec.mjs +10 -4
  35. package/dist/sync/sync-conflict-text-merge.withid.respec.mjs.map +1 -1
  36. package/dist/sync/sync-innerspace-constants.withid.respec.mjs +12 -3
  37. package/dist/sync/sync-innerspace-constants.withid.respec.mjs.map +1 -1
  38. package/dist/sync/sync-innerspace-deep-updates.withid.respec.mjs +4 -1
  39. package/dist/sync/sync-innerspace-deep-updates.withid.respec.mjs.map +1 -1
  40. package/dist/sync/sync-innerspace-dest-ahead.withid.respec.mjs +4 -1
  41. package/dist/sync/sync-innerspace-dest-ahead.withid.respec.mjs.map +1 -1
  42. package/dist/sync/sync-innerspace-multiple-timelines.withid.respec.mjs +4 -1
  43. package/dist/sync/sync-innerspace-multiple-timelines.withid.respec.mjs.map +1 -1
  44. package/dist/sync/sync-innerspace-partial-update.withid.respec.mjs +4 -1
  45. package/dist/sync/sync-innerspace-partial-update.withid.respec.mjs.map +1 -1
  46. package/dist/sync/sync-innerspace.withid.respec.mjs +4 -1
  47. package/dist/sync/sync-innerspace.withid.respec.mjs.map +1 -1
  48. package/dist/sync/sync-peer/sync-peer-types.d.mts +4 -0
  49. package/dist/sync/sync-peer/sync-peer-types.d.mts.map +1 -1
  50. package/dist/sync/sync-peer/sync-peer-v1.d.mts.map +1 -1
  51. package/dist/sync/sync-peer/sync-peer-v1.mjs +4 -1
  52. package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
  53. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.d.mts.map +1 -1
  54. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mjs +90 -22
  55. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mjs.map +1 -1
  56. package/dist/sync/sync-saga-coordinator.d.mts +7 -10
  57. package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
  58. package/dist/sync/sync-saga-coordinator.mjs +14 -5
  59. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  60. package/dist/sync/sync-types.d.mts +5 -0
  61. package/dist/sync/sync-types.d.mts.map +1 -1
  62. package/dist/sync/sync-types.mjs.map +1 -1
  63. package/dist/sync/sync-withid.connect.respec.mjs +4 -1
  64. package/dist/sync/sync-withid.connect.respec.mjs.map +1 -1
  65. package/dist/sync/sync-withid.establish.respec.mjs +4 -1
  66. package/dist/sync/sync-withid.establish.respec.mjs.map +1 -1
  67. package/dist/sync/sync-withid.pingpong.respec.mjs +4 -1
  68. package/dist/sync/sync-withid.pingpong.respec.mjs.map +1 -1
  69. package/package.json +1 -1
  70. package/src/keystone/README.md +15 -2
  71. package/src/keystone/docs/architecture.md +21 -2
  72. package/src/keystone/docs/delegation.md +57 -0
  73. package/src/keystone/keystone-constants.mts +0 -1
  74. package/src/keystone/keystone-helpers.mts +131 -5
  75. package/src/keystone/keystone-service-v1.mts +223 -2
  76. package/src/keystone/keystone-service-v1.respec.mts +436 -40
  77. package/src/keystone/keystone-types.mts +55 -0
  78. package/src/keystone/policy/keystone-profile-builder.mts +9 -1
  79. package/src/keystone/policy/profiles/profile-domain.json +84 -0
  80. package/src/keystone/policy/profiles/profile-sync.json +84 -0
  81. package/src/keystone/strategy/hash-reveal-v1/hash-reveal-v1.mts +20 -1
  82. package/src/sync/sync-conflict-adv-multitimelines.withid.respec.mts +16 -4
  83. package/src/sync/sync-conflict-basic-divergence.withid.respec.mts +4 -1
  84. package/src/sync/sync-conflict-basic-multitimelines.withid.respec.mts +4 -1
  85. package/src/sync/sync-conflict-text-merge.withid.respec.mts +10 -4
  86. package/src/sync/sync-innerspace-constants.withid.respec.mts +12 -3
  87. package/src/sync/sync-innerspace-deep-updates.withid.respec.mts +4 -1
  88. package/src/sync/sync-innerspace-dest-ahead.withid.respec.mts +4 -1
  89. package/src/sync/sync-innerspace-multiple-timelines.withid.respec.mts +4 -1
  90. package/src/sync/sync-innerspace-partial-update.withid.respec.mts +4 -1
  91. package/src/sync/sync-innerspace.withid.respec.mts +4 -1
  92. package/src/sync/sync-peer/sync-peer-types.mts +4 -0
  93. package/src/sync/sync-peer/sync-peer-v1.mts +5 -1
  94. package/src/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mts +96 -22
  95. package/src/sync/sync-saga-coordinator.mts +17 -12
  96. package/src/sync/sync-types.mts +6 -0
  97. package/src/sync/sync-withid.connect.respec.mts +5 -2
  98. package/src/sync/sync-withid.establish.respec.mts +4 -1
  99. package/src/sync/sync-withid.pingpong.respec.mts +4 -1
  100. package/src/sync/unused-identity-backup.mts.md +0 -311
@@ -1,14 +1,16 @@
1
- import { respecfully, iReckon, firstOfAll, ifWeMight } from '@ibgib/helper-gib/dist/respec-gib/respec-gib.mjs';
1
+ import { respecfully, iReckon, ifWe, firstOfAll, firstOfEach } from '@ibgib/helper-gib/dist/respec-gib/respec-gib.mjs';
2
2
  const maam = `[${import.meta.url}]`, sir = maam;
3
3
  import { clone, hash, getUUID } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
4
4
  import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
5
5
  import { GLOBAL_LOG_A_LOT } from '../core-constants.mjs';
6
6
  import { KeystoneStrategyFactory } from './strategy/keystone-strategy-factory.mjs';
7
7
  import { createRevocationPoolConfig, createStandardPoolConfig } from './keystone-config-builder.mjs';
8
- import { POOL_ID_DEFAULT, POOL_ID_REVOKE, KEYSTONE_VERB_REVOKE, KEYSTONE_VERB_MANAGE } from './keystone-constants.mjs';
9
- import { KeystoneService_V1 } from './keystone-service-v1.mjs';
10
- import { selectChallengeIds, validateChallengePool } from './keystone-helpers.mjs';
8
+ import { POOL_ID_DEFAULT, POOL_ID_REVOKE, KEYSTONE_VERB_REVOKE, KEYSTONE_VERB_MANAGE, POOL_ID_MANAGE, KEYSTONE_VERB_SYNC } from './keystone-constants.mjs';
9
+ import { KeystoneService_V1, } from './keystone-service-v1.mjs';
10
+ import { selectChallengeIds, validateChallengePool, validateKeystoneIb, validateKeystoneTransition, validateGenesisKeystone } from './keystone-helpers.mjs';
11
11
  import { KeystoneProfileBuilder } from './policy/keystone-profile-builder.mjs';
12
+ import { getTjpAddr } from '../common/other/ibgib-helper.mjs';
13
+ import { deriveDelegateSecret } from './strategy/hash-reveal-v1/hash-reveal-v1.mjs';
12
14
  const logalot = GLOBAL_LOG_A_LOT;
13
15
  /**
14
16
  * A simple in-memory map acting as a Space.
@@ -28,18 +30,57 @@ class MockIbGibSpace {
28
30
  const data = this.store.get(addr);
29
31
  return data ? JSON.parse(JSON.stringify(data)) : null;
30
32
  }
33
+ async argy({ argData, ibGibs }) {
34
+ return {
35
+ ib: 'arg^gib',
36
+ gib: 'arg_gib',
37
+ data: argData,
38
+ ibGibs,
39
+ };
40
+ }
31
41
  async witness(arg) {
32
42
  const cmd = arg.data?.cmd;
43
+ const cmdModifiers = arg.data?.cmdModifiers || [];
33
44
  if (cmd === 'get') {
34
45
  const addrs = arg.data.ibGibAddrs || [];
35
- const ibGibs = [];
36
- for (const addr of addrs) {
37
- const x = await this.get({ addr });
38
- if (x) {
39
- ibGibs.push(x);
46
+ if (cmdModifiers.includes('latest') && cmdModifiers.includes('addrs')) {
47
+ const latestAddrsMap = {};
48
+ for (const queryAddr of addrs) {
49
+ const queryTjpGib = queryAddr.includes('.') ? queryAddr.split('.')[1] : queryAddr.split('^')[1];
50
+ let latestAddr = queryAddr;
51
+ let maxN = -1;
52
+ for (const [addr, ibGib] of this.store.entries()) {
53
+ const tjpGib = addr.includes('.') ? addr.split('.')[1] : addr.split('^')[1];
54
+ if (tjpGib === queryTjpGib) {
55
+ const n = ibGib.data?.n ?? 0;
56
+ if (n > maxN) {
57
+ maxN = n;
58
+ latestAddr = addr;
59
+ }
60
+ }
61
+ }
62
+ latestAddrsMap[queryAddr] = latestAddr;
40
63
  }
64
+ return {
65
+ data: {
66
+ success: true,
67
+ latestAddrsMap,
68
+ }
69
+ };
70
+ }
71
+ else {
72
+ const ibGibs = [];
73
+ for (const addr of addrs) {
74
+ const x = await this.get({ addr });
75
+ if (x) {
76
+ ibGibs.push(x);
77
+ }
78
+ }
79
+ return {
80
+ data: { success: true },
81
+ ibGibs,
82
+ };
41
83
  }
42
- return { ibGibs };
43
84
  }
44
85
  return undefined;
45
86
  }
@@ -70,6 +111,14 @@ class MockMetaspaceService {
70
111
  const target = args.space || this.space;
71
112
  return target.put(args);
72
113
  }
114
+ async get(args) {
115
+ const target = args.space || this.space;
116
+ const x = await target.get({ addr: args.addr });
117
+ return {
118
+ success: !!x,
119
+ ibGibs: x ? [x] : [],
120
+ };
121
+ }
73
122
  /**
74
123
  * Tracks the latest version of an ibGib timeline.
75
124
  */
@@ -111,20 +160,20 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
111
160
  });
112
161
  });
113
162
  await respecfully(sir, 'Derivation Logic', async () => {
114
- await ifWeMight(sir, 'derivePoolSecret with same inputs returns same output', async () => {
163
+ await ifWe(sir, 'derivePoolSecret with same inputs returns same output', async () => {
115
164
  const strategy = KeystoneStrategyFactory.create({ config });
116
165
  const secretA = await strategy.derivePoolSecret({ masterSecret });
117
166
  const secretB = await strategy.derivePoolSecret({ masterSecret });
118
167
  iReckon(sir, secretA).asTo('secret consistency').willEqual(secretB);
119
168
  iReckon(sir, secretA).asTo('secret length').isGonnaBeTruthy();
120
169
  });
121
- await ifWeMight(sir, 'derivePoolSecret with different master secret returns different output', async () => {
170
+ await ifWe(sir, 'derivePoolSecret with different master secret returns different output', async () => {
122
171
  const strategy = KeystoneStrategyFactory.create({ config });
123
172
  const secretA = await strategy.derivePoolSecret({ masterSecret });
124
173
  const secretB = await strategy.derivePoolSecret({ masterSecret: masterSecret + "_diff" });
125
174
  iReckon(sir, secretA).asTo('secrets differ').not.willEqual(secretB);
126
175
  });
127
- await ifWeMight(sir, 'derivePoolSecret with different salt returns different output', async () => {
176
+ await ifWe(sir, 'derivePoolSecret with different salt returns different output', async () => {
128
177
  // Modify salt in a copy of config
129
178
  const configB = { ...config, salt: "OtherPool" };
130
179
  const strategyA = KeystoneStrategyFactory.create({ config });
@@ -133,9 +182,17 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
133
182
  const secretB = await strategyB.derivePoolSecret({ masterSecret });
134
183
  iReckon(sir, secretA).asTo('salt affects secret').not.willEqual(secretB);
135
184
  });
185
+ await ifWe(sir, 'deriveDelegateSecret derives a consistent secret using KDF', async () => {
186
+ const secretA = await deriveDelegateSecret({ masterSecret });
187
+ const secretB = await deriveDelegateSecret({ masterSecret });
188
+ iReckon(sir, secretA).asTo('consistency').willEqual(secretB);
189
+ iReckon(sir, secretA).asTo('truthy').isGonnaBeTruthy();
190
+ const secretC = await deriveDelegateSecret({ masterSecret: masterSecret + '_other' });
191
+ iReckon(sir, secretA).asTo('differ').not.willEqual(secretC);
192
+ });
136
193
  });
137
194
  await respecfully(sir, 'Challenge/Solution Logic', async () => {
138
- await ifWeMight(sir, 'generateSolution -> generateChallenge -> validateSolution loop works', async () => {
195
+ await ifWe(sir, 'generateSolution -> generateChallenge -> validateSolution loop works', async () => {
139
196
  const strategy = KeystoneStrategyFactory.create({ config });
140
197
  const poolSecret = await strategy.derivePoolSecret({ masterSecret });
141
198
  const challengeId = "a3ff7843552870fc28bef2b"; // arbitrary random challengeId
@@ -150,7 +207,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
150
207
  const isValid = await strategy.validateSolution({ solution, challenge });
151
208
  iReckon(sir, isValid).asTo('valid pair should pass').isGonnaBeTrue();
152
209
  });
153
- await ifWeMight(sir, 'validateSolution fails for mismatched values', async () => {
210
+ await ifWe(sir, 'validateSolution fails for mismatched values', async () => {
154
211
  const strategy = KeystoneStrategyFactory.create({ config });
155
212
  const poolSecret = await strategy.derivePoolSecret({ masterSecret });
156
213
  const challengeId = "8c994f3ed598f150e25513"; // arbitrary random challengeId
@@ -162,7 +219,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
162
219
  const isValid = await strategy.validateSolution({ solution: badSolution, challenge });
163
220
  iReckon(sir, isValid).asTo('tampered solution should fail').isGonnaBeFalse();
164
221
  });
165
- await ifWeMight(sir, 'validateSolution fails for mismatched challenge hashes', async () => {
222
+ await ifWe(sir, 'validateSolution fails for mismatched challenge hashes', async () => {
166
223
  const strategy = KeystoneStrategyFactory.create({ config });
167
224
  const poolSecret = await strategy.derivePoolSecret({ masterSecret });
168
225
  // Generate pair A
@@ -193,7 +250,7 @@ await respecfully(sir, 'Suite B: Service Lifecycle', async () => {
193
250
  mockMetaspace = new MockMetaspaceService(mockSpace);
194
251
  });
195
252
  await respecfully(sir, 'Genesis', async () => {
196
- await ifWeMight(sir, 'creates a valid genesis frame and persists it', async () => {
253
+ await ifWe(sir, 'creates a valid genesis frame and persists it', async () => {
197
254
  const salt = (await getUUID()).substring(0, 16);
198
255
  const config = createStandardPoolConfig({
199
256
  id: POOL_ID_DEFAULT,
@@ -219,7 +276,7 @@ await respecfully(sir, 'Suite B: Service Lifecycle', async () => {
219
276
  });
220
277
  });
221
278
  await respecfully(sir, 'Signing (Evolution)', async () => {
222
- await ifWeMight(sir, 'evolves the keystone with a valid proof', async () => {
279
+ await ifWe(sir, 'evolves the keystone with a valid proof', async () => {
223
280
  const claim = {
224
281
  target: "comment 123^gib",
225
282
  verb: "post"
@@ -244,7 +301,7 @@ await respecfully(sir, 'Suite B: Service Lifecycle', async () => {
244
301
  });
245
302
  });
246
303
  await respecfully(sir, 'Validation', async () => {
247
- await ifWeMight(sir, 'validates the genesis->signed transition', async () => {
304
+ await ifWe(sir, 'validates the genesis->signed transition', async () => {
248
305
  const errors = await service.validate({
249
306
  prevIbGib: genesisKeystone,
250
307
  currentIbGib: signedKeystone,
@@ -285,7 +342,7 @@ await respecfully(sir, 'Suite C: Security Vectors', async () => {
285
342
  });
286
343
  });
287
344
  await respecfully(sir, 'Wrong Secret (Forgery)', async () => {
288
- await ifWeMight(sir, 'prevents creation of forged frames', async () => {
345
+ await ifWe(sir, 'prevents creation of forged frames', async () => {
289
346
  const claim = { target: "comment 123^gib", verb: "post" };
290
347
  let errorCaught = false;
291
348
  let errorMsg = "";
@@ -311,7 +368,7 @@ await respecfully(sir, 'Suite C: Security Vectors', async () => {
311
368
  });
312
369
  });
313
370
  await respecfully(sir, 'Policy Violation (Restricted Verbs)', async () => {
314
- await ifWeMight(sir, 'throws error if signing forbidden verb with restricted pool', async () => {
371
+ await ifWe(sir, 'throws error if signing forbidden verb with restricted pool', async () => {
315
372
  // Create a specific restricted pool config manually
316
373
  const restrictedPoolId = "read_only_pool";
317
374
  const restrictedConfig = createStandardPoolConfig({
@@ -379,7 +436,7 @@ await respecfully(sir, 'Suite D: Revocation', async () => {
379
436
  });
380
437
  await respecfully(sir, 'Revoke Lifecycle', async () => {
381
438
  let revokedKeystone;
382
- await ifWeMight(sir, 'successfully creates a revocation frame', async () => {
439
+ await ifWe(sir, 'successfully creates a revocation frame', async () => {
383
440
  revokedKeystone = await service.revoke({
384
441
  latestKeystone: genesisKeystone,
385
442
  masterSecret,
@@ -394,7 +451,7 @@ await respecfully(sir, 'Suite D: Revocation', async () => {
394
451
  iReckon(sir, data.revocationInfo.reason).willEqual("Key compromised");
395
452
  iReckon(sir, data.revocationInfo.proof.claim.verb).willEqual(KEYSTONE_VERB_REVOKE);
396
453
  });
397
- await ifWeMight(sir, 'validates the revocation frame', async () => {
454
+ await ifWe(sir, 'validates the revocation frame', async () => {
398
455
  const errors = await service.validate({
399
456
  prevIbGib: genesisKeystone,
400
457
  currentIbGib: revokedKeystone,
@@ -403,7 +460,7 @@ await respecfully(sir, 'Suite D: Revocation', async () => {
403
460
  });
404
461
  iReckon(sir, errors.length).asTo('no validation errors').willEqual(0);
405
462
  });
406
- await ifWeMight(sir, 'consumed the revocation pool (Scorched Earth)', async () => {
463
+ await ifWe(sir, 'consumed the revocation pool (Scorched Earth)', async () => {
407
464
  const data = revokedKeystone.data;
408
465
  const revokePool = data.challengePools.find(p => p.id === POOL_ID_REVOKE);
409
466
  // The pool should exist...
@@ -465,7 +522,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
465
522
  });
466
523
  });
467
524
  await respecfully(sir, 'Happy Path', async () => {
468
- await ifWeMight(sir, 'authorizes and adds a foreign pool', async () => {
525
+ await ifWe(sir, 'authorizes and adds a foreign pool', async () => {
469
526
  const bobPool = await createForeignPool("pool_bob", ["post"]);
470
527
  const updatedKeystone = await service.addPools({
471
528
  latestKeystone: aliceKeystone,
@@ -497,7 +554,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
497
554
  });
498
555
  });
499
556
  await respecfully(sir, 'Permissions & Logic', async () => {
500
- await ifWeMight(sir, 'fails if no pool allows "manage" verb', async () => {
557
+ await ifWe(sir, 'fails if no pool allows "manage" verb', async () => {
501
558
  // 1. Create a restricted keystone
502
559
  let id = "read_only";
503
560
  const restrictedConfig = createStandardPoolConfig({ id, salt: id });
@@ -526,7 +583,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
526
583
  }
527
584
  iReckon(sir, errorCaught).asTo('permission denied').isGonnaBeTrue();
528
585
  });
529
- await ifWeMight(sir, 'fails on ID collision', async () => {
586
+ await ifWe(sir, 'fails on ID collision', async () => {
530
587
  // Try to add "pool_bob" again (it was added in Happy Path)
531
588
  const duplicatePool = await createForeignPool("pool_bob");
532
589
  let errorCaught = false;
@@ -601,7 +658,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
601
658
  });
602
659
  });
603
660
  await respecfully(sir, 'Happy Path', async () => {
604
- await ifWeMight(sir, 'authorizes and adds a foreign pool', async () => {
661
+ await ifWe(sir, 'authorizes and adds a foreign pool', async () => {
605
662
  const bobPool = await createForeignPool("pool_bob", ["post"]);
606
663
  const updatedKeystone = await service.addPools({
607
664
  latestKeystone: aliceKeystone,
@@ -633,7 +690,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
633
690
  });
634
691
  });
635
692
  await respecfully(sir, 'Permissions & Logic', async () => {
636
- await ifWeMight(sir, 'fails if no pool allows "manage" verb', async () => {
693
+ await ifWe(sir, 'fails if no pool allows "manage" verb', async () => {
637
694
  // 1. Create a restricted keystone (read-only)
638
695
  let id = "read_only";
639
696
  const restrictedConfig = createStandardPoolConfig({ id, salt: id });
@@ -662,7 +719,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
662
719
  }
663
720
  iReckon(sir, errorCaught).asTo('permission denied').isGonnaBeTrue();
664
721
  });
665
- await ifWeMight(sir, 'fails on ID collision', async () => {
722
+ await ifWe(sir, 'fails on ID collision', async () => {
666
723
  // Try to add "pool_bob" again (it was added in Happy Path)
667
724
  const duplicatePool = await createForeignPool("pool_bob");
668
725
  let errorCaught = false;
@@ -714,7 +771,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
714
771
  });
715
772
  });
716
773
  await respecfully(sir, 'Proof Granularity & Math', async () => {
717
- await ifWeMight(sir, 'generates exactly the expected number of solutions', async () => {
774
+ await ifWe(sir, 'generates exactly the expected number of solutions', async () => {
718
775
  signedKeystone = await service.sign({
719
776
  latestKeystone: genesisKeystone,
720
777
  masterSecret: aliceSecret,
@@ -728,7 +785,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
728
785
  // 2 Sequential + 2 Random = 4
729
786
  iReckon(sir, solutions.length).asTo('solution count').willEqual(4);
730
787
  });
731
- await ifWeMight(sir, 'verifies the math manually (White-box Crypto Check)', async () => {
788
+ await ifWe(sir, 'verifies the math manually (White-box Crypto Check)', async () => {
732
789
  const proof = signedKeystone.data.proofs[0];
733
790
  const poolSnapshot = genesisKeystone.data.challengePools.find(p => p.id === poolId);
734
791
  // We iterate every solution in the proof and MANUALLY verify the hash relationship
@@ -751,7 +808,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
751
808
  iReckon(sir, calculatedHash).asTo(`Manual hash verification for ${solution.challengeId}`).willEqual(challenge.hash);
752
809
  }
753
810
  });
754
- await ifWeMight(sir, 'verifies FIFO logic (Deterministic Selection)', async () => {
811
+ await ifWe(sir, 'verifies FIFO logic (Deterministic Selection)', async () => {
755
812
  const proof = signedKeystone.data.proofs[0];
756
813
  const poolSnapshot = genesisKeystone.data.challengePools.find(p => p.id === poolId);
757
814
  // The first N keys in the pool should be the FIFO targets.
@@ -765,7 +822,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
765
822
  iReckon(sir, hasFirst).asTo(`Solution includes 1st FIFO ID (${expectedFifoIds[0]})`).isGonnaBeTrue();
766
823
  iReckon(sir, hasSecond).asTo(`Solution includes 2nd FIFO ID (${expectedFifoIds[1]})`).isGonnaBeTrue();
767
824
  });
768
- await ifWeMight(sir, 'verifies Next-Gen Hash-Based Target Binding Selection', async () => {
825
+ await ifWe(sir, 'verifies Next-Gen Hash-Based Target Binding Selection', async () => {
769
826
  const bindingConfig = createStandardPoolConfig({
770
827
  id: "binding_pool",
771
828
  salt: "binding_salt",
@@ -807,7 +864,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
807
864
  iReckon(sir, proofIds.includes(id)).asTo(`proof includes selected ID ${id}`).isGonnaBeTrue();
808
865
  }
809
866
  });
810
- await ifWeMight(sir, 'fails validation if total requested challenges >= size', async () => {
867
+ await ifWe(sir, 'fails validation if total requested challenges >= size', async () => {
811
868
  const invalidConfig = createStandardPoolConfig({
812
869
  id: "invalid_pool",
813
870
  salt: "invalid_salt",
@@ -823,7 +880,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
823
880
  });
824
881
  });
825
882
  await respecfully(sir, 'DTO & Serialization', async () => {
826
- await ifWeMight(sir, 'survives a clone/JSON-cycle without corruption', async () => {
883
+ await ifWe(sir, 'survives a clone/JSON-cycle without corruption', async () => {
827
884
  // 1. Create a DTO (simulate network transmission/storage)
828
885
  // 'clone' does a JSON stringify/parse under the hood (usually) or structured clone.
829
886
  const dto = clone(signedKeystone);
@@ -839,7 +896,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
839
896
  });
840
897
  iReckon(sir, errors.length).asTo('DTO validation errors').willEqual(0);
841
898
  });
842
- await ifWeMight(sir, 'ensures data contains no functions or circular refs', async () => {
899
+ await ifWe(sir, 'ensures data contains no functions or circular refs', async () => {
843
900
  // A crude but effective test: ensure JSON.stringify doesn't throw
844
901
  // and the result is equal to the object (if we parsed it back).
845
902
  const jsonStr = JSON.stringify(signedKeystone);
@@ -858,7 +915,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
858
915
  });
859
916
  });
860
917
  await respecfully(sir, 'KeystoneProfileBuilder and Modular Schemas', async () => {
861
- await ifWeMight(sir, 'compiles configs successfully with medium profile', async () => {
918
+ await ifWe(sir, 'compiles configs successfully with medium profile', async () => {
862
919
  const builder = KeystoneProfileBuilder.buildKeystone('medium')
863
920
  .withUsername('alice')
864
921
  .withEmail('alice@example.com')
@@ -877,7 +934,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
877
934
  iReckon(sir, details.description).asTo('description').willEqual('Alice test keystone');
878
935
  iReckon(sir, details.extraInfo).asTo('extraInfo').willEqual('abc');
879
936
  });
880
- await ifWeMight(sir, 'supports customized overrides', async () => {
937
+ await ifWe(sir, 'supports customized overrides', async () => {
881
938
  const builder = KeystoneProfileBuilder.buildKeystone('test')
882
939
  .customizePool('sync', {
883
940
  behavior: {
@@ -892,7 +949,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
892
949
  });
893
950
  });
894
951
  await respecfully(sir, 'Keystone Metadata Validation', async () => {
895
- await ifWeMight(sir, 'validates correct username and description', async () => {
952
+ await ifWe(sir, 'validates correct username and description', async () => {
896
953
  const service = new KeystoneService_V1();
897
954
  const space = new MockIbGibSpace();
898
955
  const metaspace = new MockMetaspaceService(space);
@@ -913,7 +970,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
913
970
  const errors = await service.validateGenesisKeystone({ keystoneIbGib });
914
971
  iReckon(sir, errors.length).asTo('errors count').willEqual(0);
915
972
  });
916
- await ifWeMight(sir, 'fails validation for invalid username length or character', async () => {
973
+ await ifWe(sir, 'fails validation for invalid username length or character', async () => {
917
974
  const service = new KeystoneService_V1();
918
975
  const space = new MockIbGibSpace();
919
976
  const metaspace = new MockMetaspaceService(space);
@@ -933,7 +990,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
933
990
  iReckon(sir, errors.length).asTo('errors count').willEqual(1);
934
991
  iReckon(sir, errors[0]).includes('invalid username');
935
992
  });
936
- await ifWeMight(sir, 'fails validation for invalid description characters', async () => {
993
+ await ifWe(sir, 'fails validation for invalid description characters', async () => {
937
994
  const service = new KeystoneService_V1();
938
995
  const space = new MockIbGibSpace();
939
996
  const metaspace = new MockMetaspaceService(space);
@@ -956,4 +1013,302 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
956
1013
  });
957
1014
  });
958
1015
  });
1016
+ // ===========================================================================
1017
+ // SUITE E: DELEGATION (Register/Unregister)
1018
+ // ===========================================================================
1019
+ await respecfully(sir, 'Suite E: Delegation (Register/Unregister)', async () => {
1020
+ const service = new KeystoneService_V1();
1021
+ const parentSecret = "ParentMasterSecret_123";
1022
+ const delegateSecret = "DelegateMasterSecret_456";
1023
+ let mockSpace;
1024
+ let mockMetaspace;
1025
+ let parentKeystone;
1026
+ let delegateKeystone;
1027
+ firstOfEach(sir, async () => {
1028
+ mockSpace = new MockIbGibSpace();
1029
+ mockMetaspace = new MockMetaspaceService(mockSpace);
1030
+ const salt = (await getUUID()).substring(0, 16);
1031
+ const defaultConfig = createStandardPoolConfig({ id: POOL_ID_DEFAULT, salt });
1032
+ const manageConfig = createStandardPoolConfig({ id: POOL_ID_MANAGE, salt: salt + "_manage" });
1033
+ manageConfig.allowedVerbs = [KEYSTONE_VERB_MANAGE];
1034
+ // 1. Create Parent Keystone (with manage pool)
1035
+ parentKeystone = await service.genesis({
1036
+ masterSecret: parentSecret,
1037
+ configs: [defaultConfig, manageConfig],
1038
+ metaspace: mockMetaspace,
1039
+ space: mockSpace,
1040
+ });
1041
+ // 2. Create Delegate Keystone
1042
+ const delegateConfig = createStandardPoolConfig({ id: POOL_ID_DEFAULT, salt: salt + "_delegate" });
1043
+ delegateKeystone = await service.genesis({
1044
+ masterSecret: delegateSecret,
1045
+ configs: [delegateConfig],
1046
+ metaspace: mockMetaspace,
1047
+ space: mockSpace,
1048
+ });
1049
+ });
1050
+ await ifWe(sir, 'registers a delegate keystone and evolves parent using manage pool', async () => {
1051
+ // Register the delegate
1052
+ const evolvedParent = await service.registerDelegate({
1053
+ parentKeystone,
1054
+ delegateKeystone,
1055
+ masterSecret: parentSecret,
1056
+ metaspace: mockMetaspace,
1057
+ space: mockSpace,
1058
+ allowedVerbs: [KEYSTONE_VERB_SYNC],
1059
+ });
1060
+ iReckon(sir, evolvedParent).asTo('evolved parent exists').isGonnaBeTruthy();
1061
+ iReckon(sir, evolvedParent.data?.delegates).asTo('delegates map exists').isGonnaBeTruthy();
1062
+ const delegateTjpAddr = getTjpAddr({ ibGib: delegateKeystone });
1063
+ if (!delegateTjpAddr) {
1064
+ throw new Error(`(UNEXPECTED) delegateTjpAddr falsy? (E: 312e986ce4b2ed6c084c03e8f45fa826)`);
1065
+ }
1066
+ const delegateInfo = evolvedParent.data?.delegates?.[delegateTjpAddr];
1067
+ iReckon(sir, delegateInfo).asTo('delegate info registered').isGonnaBeTruthy();
1068
+ iReckon(sir, delegateInfo?.delegateTjpAddr).asTo('delegate tjp matches').willEqual(delegateTjpAddr);
1069
+ });
1070
+ await ifWe(sir, 'gets correct delegate status via parent TJP address', async () => {
1071
+ const parentTjpAddr = getTjpAddr({ ibGib: parentKeystone });
1072
+ if (!parentTjpAddr) {
1073
+ throw new Error(`(UNEXPECTED) parentTjpAddr falsy? (E: b7ce2835ccd951d8c99257328be3b826)`);
1074
+ }
1075
+ const delegateTjpAddr = getTjpAddr({ ibGib: delegateKeystone });
1076
+ if (!delegateTjpAddr) {
1077
+ throw new Error(`(UNEXPECTED) delegateTjpAddr falsy? (E: 3e4878ea19dd8034e827466a8bf09526)`);
1078
+ }
1079
+ // Before registration
1080
+ const statusBefore = await service.getDelegateStatus({
1081
+ parentTjpAddr: parentTjpAddr,
1082
+ delegateTjpAddr: delegateTjpAddr,
1083
+ metaspace: mockMetaspace,
1084
+ space: mockSpace,
1085
+ });
1086
+ iReckon(sir, statusBefore.registered).asTo('initially unregistered').isGonnaBeFalse();
1087
+ // Register
1088
+ const evolvedParent = await service.registerDelegate({
1089
+ parentKeystone,
1090
+ delegateKeystone,
1091
+ masterSecret: parentSecret,
1092
+ metaspace: mockMetaspace,
1093
+ space: mockSpace,
1094
+ allowedVerbs: [KEYSTONE_VERB_SYNC],
1095
+ });
1096
+ // After registration
1097
+ const statusAfter = await service.getDelegateStatus({
1098
+ parentTjpAddr: parentTjpAddr,
1099
+ delegateTjpAddr: delegateTjpAddr,
1100
+ metaspace: mockMetaspace,
1101
+ space: mockSpace,
1102
+ });
1103
+ iReckon(sir, statusAfter.registered).asTo('registered status').isGonnaBeTrue();
1104
+ iReckon(sir, statusAfter.delegateInfo?.delegateTjpAddr).asTo('status tjp matches').willEqual(delegateTjpAddr);
1105
+ });
1106
+ await ifWe(sir, 'unregisters a registered delegate keystone', async () => {
1107
+ // Register first
1108
+ const evolvedParent = await service.registerDelegate({
1109
+ parentKeystone,
1110
+ delegateKeystone,
1111
+ masterSecret: parentSecret,
1112
+ metaspace: mockMetaspace,
1113
+ space: mockSpace,
1114
+ allowedVerbs: [KEYSTONE_VERB_SYNC],
1115
+ });
1116
+ const delegateTjpAddr = getTjpAddr({ ibGib: delegateKeystone });
1117
+ if (!delegateTjpAddr) {
1118
+ throw new Error(`(UNEXPECTED) delegateTjpAddr falsy? (E: 486b486a8c984a52b8d2b22418c20d26)`);
1119
+ }
1120
+ // Unregister
1121
+ const finalParent = await service.unregisterDelegate({
1122
+ parentKeystone: evolvedParent,
1123
+ delegateTjpAddr,
1124
+ masterSecret: parentSecret,
1125
+ metaspace: mockMetaspace,
1126
+ space: mockSpace,
1127
+ });
1128
+ iReckon(sir, finalParent).asTo('final evolved parent exists').isGonnaBeTruthy();
1129
+ const info = finalParent.data?.delegates?.[delegateTjpAddr];
1130
+ iReckon(sir, info).asTo('delegate info removed').isGonnaBeUndefined();
1131
+ });
1132
+ await ifWe(sir, 'throws if parent does not have a manage pool', async () => {
1133
+ // Create a parent WITHOUT a manage pool
1134
+ const salt = (await getUUID()).substring(0, 16);
1135
+ const defaultConfig = createStandardPoolConfig({ id: POOL_ID_DEFAULT, salt });
1136
+ const restrictedParent = await service.genesis({
1137
+ masterSecret: parentSecret,
1138
+ configs: [defaultConfig],
1139
+ metaspace: mockMetaspace,
1140
+ space: mockSpace,
1141
+ });
1142
+ let errorCaught = false;
1143
+ try {
1144
+ await service.registerDelegate({
1145
+ parentKeystone: restrictedParent,
1146
+ delegateKeystone,
1147
+ masterSecret: parentSecret,
1148
+ metaspace: mockMetaspace,
1149
+ space: mockSpace,
1150
+ allowedVerbs: [KEYSTONE_VERB_SYNC],
1151
+ });
1152
+ }
1153
+ catch (e) {
1154
+ errorCaught = true;
1155
+ iReckon(sir, e.message).includes('Manage pool is required');
1156
+ }
1157
+ iReckon(sir, errorCaught).asTo('delegation rejected').isGonnaBeTrue();
1158
+ });
1159
+ });
1160
+ await respecfully(sir, 'Suite G: Delegate & IB Validation', async () => {
1161
+ const service = new KeystoneService_V1();
1162
+ const parentSecret = "ParentMasterSecret_SuiteG";
1163
+ const delegateSecret = "DelegateMasterSecret_SuiteG";
1164
+ let mockSpace;
1165
+ let mockMetaspace;
1166
+ let parentKeystone;
1167
+ let delegateKeystone;
1168
+ firstOfEach(sir, async () => {
1169
+ mockSpace = new MockIbGibSpace();
1170
+ mockMetaspace = new MockMetaspaceService(mockSpace);
1171
+ const salt1 = (await getUUID()).substring(0, 16);
1172
+ const salt2 = (await getUUID()).substring(0, 16);
1173
+ const manageConfig = createStandardPoolConfig({ id: POOL_ID_MANAGE, salt: salt2 });
1174
+ manageConfig.allowedVerbs = [KEYSTONE_VERB_MANAGE];
1175
+ const configs = [
1176
+ createStandardPoolConfig({ id: POOL_ID_DEFAULT, salt: salt1 }),
1177
+ manageConfig
1178
+ ];
1179
+ parentKeystone = await service.genesis({
1180
+ masterSecret: parentSecret,
1181
+ configs,
1182
+ metaspace: mockMetaspace,
1183
+ space: mockSpace,
1184
+ });
1185
+ delegateKeystone = await service.genesis({
1186
+ masterSecret: delegateSecret,
1187
+ configs: [createStandardPoolConfig({ id: POOL_ID_DEFAULT, salt: salt1 })],
1188
+ metaspace: mockMetaspace,
1189
+ space: mockSpace,
1190
+ });
1191
+ });
1192
+ await ifWe(sir, 'validateKeystoneIb returns true for valid keystone ib and false for others', async () => {
1193
+ iReckon(sir, await validateKeystoneIb({ ib: 'keystone' })).isGonnaBeTrue();
1194
+ iReckon(sir, await validateKeystoneIb({ ib: 'keystone user info' })).isGonnaBeTrue();
1195
+ iReckon(sir, await validateKeystoneIb({ ib: 'invalidAtom' })).isGonnaBeFalse();
1196
+ iReckon(sir, await validateKeystoneIb({ ib: 'not_keystone sub_atom' })).isGonnaBeFalse();
1197
+ });
1198
+ await ifWe(sir, 'validateGenesisKeystone fails validation if ib is invalid', async () => {
1199
+ const invalidGenesis = {
1200
+ ...parentKeystone,
1201
+ ib: 'not_a_keystone^' + parentKeystone.gib,
1202
+ };
1203
+ const errors = await validateGenesisKeystone({ keystoneIbGib: invalidGenesis });
1204
+ iReckon(sir, errors.length > 0).isGonnaBeTrue();
1205
+ iReckon(sir, errors[0]).includes('invalid keystone ib');
1206
+ });
1207
+ await ifWe(sir, 'validateKeystoneTransition passes for valid delegate registration', async () => {
1208
+ const evolvedParent = await service.registerDelegate({
1209
+ parentKeystone,
1210
+ delegateKeystone,
1211
+ masterSecret: parentSecret,
1212
+ metaspace: mockMetaspace,
1213
+ space: mockSpace,
1214
+ allowedVerbs: [KEYSTONE_VERB_SYNC],
1215
+ });
1216
+ const errors = await validateKeystoneTransition({
1217
+ currentIbGib: evolvedParent,
1218
+ prevIbGib: parentKeystone,
1219
+ });
1220
+ iReckon(sir, errors.length).willEqual(0);
1221
+ });
1222
+ await ifWe(sir, 'validateKeystoneTransition fails if delegates map is mutated without manage proof', async () => {
1223
+ const evolvedParent = await service.registerDelegate({
1224
+ parentKeystone,
1225
+ delegateKeystone,
1226
+ masterSecret: parentSecret,
1227
+ metaspace: mockMetaspace,
1228
+ space: mockSpace,
1229
+ allowedVerbs: [KEYSTONE_VERB_SYNC],
1230
+ });
1231
+ const tamperedParent = JSON.parse(JSON.stringify(evolvedParent));
1232
+ // Remove the manage verb proof by converting it to sign
1233
+ for (const proof of tamperedParent.data.proofs) {
1234
+ if (proof.claim) {
1235
+ proof.claim.verb = 'sign';
1236
+ }
1237
+ }
1238
+ const errors = await validateKeystoneTransition({
1239
+ currentIbGib: tamperedParent,
1240
+ prevIbGib: parentKeystone,
1241
+ });
1242
+ iReckon(sir, errors.length > 0).isGonnaBeTrue();
1243
+ iReckon(sir, errors.some(e => e.includes('Policy Violation: Delegates map was mutated'))).isGonnaBeTrue();
1244
+ });
1245
+ await ifWe(sir, 'validateKeystoneTransition fails if delegate key does not match delegateTjpAddr', async () => {
1246
+ const evolvedParent = await service.registerDelegate({
1247
+ parentKeystone,
1248
+ delegateKeystone,
1249
+ masterSecret: parentSecret,
1250
+ metaspace: mockMetaspace,
1251
+ space: mockSpace,
1252
+ allowedVerbs: [KEYSTONE_VERB_SYNC],
1253
+ });
1254
+ const tamperedParent = JSON.parse(JSON.stringify(evolvedParent));
1255
+ const delegateTjpAddr = getTjpAddr({ ibGib: delegateKeystone });
1256
+ if (!delegateTjpAddr) {
1257
+ throw new Error(`delegateTjpAddr falsy?`);
1258
+ }
1259
+ const info = tamperedParent.data.delegates[delegateTjpAddr];
1260
+ delete tamperedParent.data.delegates[delegateTjpAddr];
1261
+ tamperedParent.data.delegates['mismatched_key'] = info;
1262
+ const errors = await validateKeystoneTransition({
1263
+ currentIbGib: tamperedParent,
1264
+ prevIbGib: parentKeystone,
1265
+ });
1266
+ iReckon(sir, errors.length > 0).isGonnaBeTrue();
1267
+ iReckon(sir, errors.some(e => e.includes('does not match delegateTjpAddr'))).isGonnaBeTrue();
1268
+ });
1269
+ await ifWe(sir, 'validateKeystoneTransition fails if delegate addresses have invalid keystone ib', async () => {
1270
+ const evolvedParent = await service.registerDelegate({
1271
+ parentKeystone,
1272
+ delegateKeystone,
1273
+ masterSecret: parentSecret,
1274
+ metaspace: mockMetaspace,
1275
+ space: mockSpace,
1276
+ allowedVerbs: [KEYSTONE_VERB_SYNC],
1277
+ });
1278
+ const tamperedParent = JSON.parse(JSON.stringify(evolvedParent));
1279
+ const delegateTjpAddr = getTjpAddr({ ibGib: delegateKeystone });
1280
+ if (!delegateTjpAddr) {
1281
+ throw new Error(`delegateTjpAddr falsy?`);
1282
+ }
1283
+ tamperedParent.data.delegates[delegateTjpAddr].delegateAddr = 'invalid_ib^12345';
1284
+ const errors = await validateKeystoneTransition({
1285
+ currentIbGib: tamperedParent,
1286
+ prevIbGib: parentKeystone,
1287
+ });
1288
+ iReckon(sir, errors.length > 0).isGonnaBeTrue();
1289
+ iReckon(sir, errors.some(e => e.includes('not a valid keystone address'))).isGonnaBeTrue();
1290
+ });
1291
+ await ifWe(sir, 'validateKeystoneTransition fails if thisAddr is not in the parent timeline history', async () => {
1292
+ const evolvedParent = await service.registerDelegate({
1293
+ parentKeystone,
1294
+ delegateKeystone,
1295
+ masterSecret: parentSecret,
1296
+ metaspace: mockMetaspace,
1297
+ space: mockSpace,
1298
+ allowedVerbs: [KEYSTONE_VERB_SYNC],
1299
+ });
1300
+ const tamperedParent = JSON.parse(JSON.stringify(evolvedParent));
1301
+ const delegateTjpAddr = getTjpAddr({ ibGib: delegateKeystone });
1302
+ if (!delegateTjpAddr) {
1303
+ throw new Error(`delegateTjpAddr falsy?`);
1304
+ }
1305
+ tamperedParent.data.delegates[delegateTjpAddr].thisAddr = 'keystone^randomgib';
1306
+ const errors = await validateKeystoneTransition({
1307
+ currentIbGib: tamperedParent,
1308
+ prevIbGib: parentKeystone,
1309
+ });
1310
+ iReckon(sir, errors.length > 0).isGonnaBeTrue();
1311
+ iReckon(sir, errors.some(e => e.includes('not a valid historical address in the parent keystone timeline'))).isGonnaBeTrue();
1312
+ });
1313
+ });
959
1314
  //# sourceMappingURL=keystone-service-v1.respec.mjs.map