@ibgib/core-gib 0.1.59 → 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 (206) hide show
  1. package/CHANGELOG.md +12 -1
  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-innerspace/sync-peer-innerspace-v1.mjs +1 -1
  95. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs.map +1 -1
  96. package/dist/sync/sync-peer/sync-peer-types.d.mts +12 -1
  97. package/dist/sync/sync-peer/sync-peer-types.d.mts.map +1 -1
  98. package/dist/sync/sync-peer/sync-peer-v1.d.mts +7 -0
  99. package/dist/sync/sync-peer/sync-peer-v1.d.mts.map +1 -1
  100. package/dist/sync/sync-peer/sync-peer-v1.mjs +43 -1
  101. package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
  102. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.d.mts +2 -0
  103. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.d.mts.map +1 -1
  104. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.mjs +28 -9
  105. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.mjs.map +1 -1
  106. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.d.mts +1 -1
  107. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.d.mts.map +1 -1
  108. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mjs +5 -3
  109. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mjs.map +1 -1
  110. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.d.mts +16 -0
  111. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.d.mts.map +1 -1
  112. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.mjs +223 -79
  113. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.mjs.map +1 -1
  114. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts.map +1 -1
  115. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs +41 -2
  116. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs.map +1 -1
  117. package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts +4 -0
  118. package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts.map +1 -1
  119. package/dist/sync/sync-saga-coordinator.d.mts +6 -0
  120. package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
  121. package/dist/sync/sync-saga-coordinator.mjs +213 -137
  122. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  123. package/dist/sync/sync-withid.pingpong.respec.mjs +70 -2
  124. package/dist/sync/sync-withid.pingpong.respec.mjs.map +1 -1
  125. package/dist/timeline/timeline-api.d.mts.map +1 -1
  126. package/dist/timeline/timeline-api.mjs +1 -14
  127. package/dist/timeline/timeline-api.mjs.map +1 -1
  128. package/dist/witness/space/reconciliation-space/reconciliation-space-base.d.mts.map +1 -1
  129. package/dist/witness/space/reconciliation-space/reconciliation-space-base.mjs +0 -40
  130. package/dist/witness/space/reconciliation-space/reconciliation-space-base.mjs.map +1 -1
  131. package/dist/witness/space/reconciliation-space/reconciliation-space-helper.d.mts.map +1 -1
  132. package/dist/witness/space/reconciliation-space/reconciliation-space-helper.mjs +6 -6
  133. package/dist/witness/space/reconciliation-space/reconciliation-space-helper.mjs.map +1 -1
  134. package/ibgib-foundations.md +2 -1
  135. package/package.json +1 -1
  136. package/src/common/other/graph-helper.mts +7 -6
  137. package/src/keystone/README.md +19 -15
  138. package/src/keystone/docs/CRYPTANALYSIS.md +185 -0
  139. package/src/keystone/docs/architecture.md +24 -1
  140. package/src/keystone/docs/profiles.md +124 -0
  141. package/src/keystone/keystone-config-builder.mts +3 -21
  142. package/src/keystone/keystone-constants.mts +2 -0
  143. package/src/keystone/keystone-helpers.mts +74 -77
  144. package/src/keystone/keystone-policy-types.mts +6 -4
  145. package/src/keystone/keystone-service-v1.mts +4 -9
  146. package/src/keystone/keystone-service-v1.respec.mts +214 -32
  147. package/src/keystone/keystone-types.mts +5 -9
  148. package/src/keystone/policy/IMPLEMENTATION.md +60 -0
  149. package/src/keystone/policy/README.md +94 -0
  150. package/src/keystone/policy/keystone-profile-builder.mts +131 -0
  151. package/src/keystone/policy/profiles/profile-high.json +84 -0
  152. package/src/keystone/policy/profiles/profile-low.json +84 -0
  153. package/src/keystone/policy/profiles/profile-medium.json +84 -0
  154. package/src/keystone/policy/profiles/profile-session.json +84 -0
  155. package/src/keystone/policy/profiles/profile-test.json +84 -0
  156. package/src/keystone/policy/schemas/connect-pool.high.schema.json +23 -0
  157. package/src/keystone/policy/schemas/connect-pool.low.schema.json +23 -0
  158. package/src/keystone/policy/schemas/connect-pool.medium.schema.json +23 -0
  159. package/src/keystone/policy/schemas/keystone.high.schema.json +26 -0
  160. package/src/keystone/policy/schemas/keystone.low.schema.json +26 -0
  161. package/src/keystone/policy/schemas/keystone.medium.schema.json +26 -0
  162. package/src/keystone/policy/schemas/manage-pool.high.schema.json +23 -0
  163. package/src/keystone/policy/schemas/manage-pool.low.schema.json +23 -0
  164. package/src/keystone/policy/schemas/manage-pool.medium.schema.json +23 -0
  165. package/src/keystone/policy/schemas/revoke-pool.high.schema.json +23 -0
  166. package/src/keystone/policy/schemas/revoke-pool.low.schema.json +23 -0
  167. package/src/keystone/policy/schemas/revoke-pool.medium.schema.json +23 -0
  168. package/src/keystone/policy/schemas/sign-pool.high.schema.json +23 -0
  169. package/src/keystone/policy/schemas/sign-pool.low.schema.json +23 -0
  170. package/src/keystone/policy/schemas/sign-pool.medium.schema.json +23 -0
  171. package/src/keystone/policy/schemas/sync-pool.high.schema.json +23 -0
  172. package/src/keystone/policy/schemas/sync-pool.low.schema.json +23 -0
  173. package/src/keystone/policy/schemas/sync-pool.medium.schema.json +23 -0
  174. package/src/sync/docs/security-3b.md +92 -0
  175. package/src/sync/docs/security.md +139 -38
  176. package/src/sync/sync-conflict-adv-multitimelines.withid.respec.mts +706 -0
  177. package/src/sync/sync-conflict-basic-divergence.withid.respec.mts +321 -0
  178. package/src/sync/sync-conflict-basic-multitimelines.withid.respec.mts +374 -0
  179. package/src/sync/sync-conflict-text-merge.withid.respec.mts +347 -0
  180. package/src/sync/sync-innerspace-constants.withid.respec.mts +264 -0
  181. package/src/sync/sync-innerspace-deep-updates.withid.respec.mts +272 -0
  182. package/src/sync/sync-innerspace-dest-ahead.withid.respec.mts +266 -0
  183. package/src/sync/sync-innerspace-multiple-timelines.respec.mts +0 -1
  184. package/src/sync/sync-innerspace-multiple-timelines.withid.respec.mts +273 -0
  185. package/src/sync/sync-innerspace-partial-update.withid.respec.mts +249 -0
  186. package/src/sync/sync-innerspace.withid.respec.mts +265 -0
  187. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mts +1 -1
  188. package/src/sync/sync-peer/sync-peer-types.mts +11 -1
  189. package/src/sync/sync-peer/sync-peer-v1.mts +47 -1
  190. package/src/sync/sync-peer/sync-peer-websocket/README.md +42 -0
  191. package/src/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.mts +26 -9
  192. package/src/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mts +5 -3
  193. package/src/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.mts +242 -78
  194. package/src/sync/sync-saga-context/sync-saga-context-helpers.mts +46 -4
  195. package/src/sync/sync-saga-context/sync-saga-context-types.mts +5 -0
  196. package/src/sync/sync-saga-coordinator.mts +221 -137
  197. package/src/sync/sync-withid.pingpong.respec.mts +76 -3
  198. package/src/timeline/timeline-api.mts +1 -15
  199. package/src/timeline/timeline-api.respec.mts +3 -3
  200. package/src/witness/space/reconciliation-space/reconciliation-space-base.mts +0 -46
  201. package/src/witness/space/reconciliation-space/reconciliation-space-helper.mts +6 -5
  202. package/tsconfig.json +6 -1
  203. package/src/keystone/keystone-policy.schema.json +0 -51
  204. package/src/sync/docs/ping_pong_plan.md +0 -147
  205. package/src/witness/space/reconciliation-space/reconciliation-space-base.mts.OLD.md +0 -884
  206. package/src/witness/space/reconciliation-space/reconciliation-space-helper.mts.OLD.md +0 -125
@@ -12,7 +12,8 @@ import { KeystoneChallengePool, KeystoneClaim, KeystoneIbGib_V1, KeystonePoolCon
12
12
  import { createRevocationPoolConfig, createStandardPoolConfig } from './keystone-config-builder.mjs';
13
13
  import { POOL_ID_DEFAULT, POOL_ID_REVOKE, KEYSTONE_VERB_REVOKE, KEYSTONE_VERB_MANAGE } from './keystone-constants.mjs';
14
14
  import { KeystoneService_V1 } from './keystone-service-v1.mjs';
15
- import { addToBindingMap } from './keystone-helpers.mjs';
15
+ import { selectChallengeIds, validateChallengePool } from './keystone-helpers.mjs';
16
+ import { KeystoneProfileBuilder } from './policy/keystone-profile-builder.mjs';
16
17
 
17
18
  const logalot = GLOBAL_LOG_A_LOT;
18
19
 
@@ -131,7 +132,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
131
132
 
132
133
  await respecfully(sir, 'Derivation Logic', async () => {
133
134
 
134
- await ifWe(sir, 'derivePoolSecret with same inputs returns same output', async () => {
135
+ await ifWeMight(sir, 'derivePoolSecret with same inputs returns same output', async () => {
135
136
  const strategy = KeystoneStrategyFactory.create({ config });
136
137
 
137
138
  const secretA = await strategy.derivePoolSecret({ masterSecret });
@@ -141,7 +142,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
141
142
  iReckon(sir, secretA).asTo('secret length').isGonnaBeTruthy();
142
143
  });
143
144
 
144
- await ifWe(sir, 'derivePoolSecret with different master secret returns different output', async () => {
145
+ await ifWeMight(sir, 'derivePoolSecret with different master secret returns different output', async () => {
145
146
  const strategy = KeystoneStrategyFactory.create({ config });
146
147
 
147
148
  const secretA = await strategy.derivePoolSecret({ masterSecret });
@@ -150,7 +151,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
150
151
  iReckon(sir, secretA).asTo('secrets differ').not.willEqual(secretB);
151
152
  });
152
153
 
153
- await ifWe(sir, 'derivePoolSecret with different salt returns different output', async () => {
154
+ await ifWeMight(sir, 'derivePoolSecret with different salt returns different output', async () => {
154
155
  // Modify salt in a copy of config
155
156
  const configB = { ...config, salt: "OtherPool" };
156
157
  const strategyA = KeystoneStrategyFactory.create({ config });
@@ -165,7 +166,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
165
166
 
166
167
  await respecfully(sir, 'Challenge/Solution Logic', async () => {
167
168
 
168
- await ifWe(sir, 'generateSolution -> generateChallenge -> validateSolution loop works', async () => {
169
+ await ifWeMight(sir, 'generateSolution -> generateChallenge -> validateSolution loop works', async () => {
169
170
  const strategy = KeystoneStrategyFactory.create({ config });
170
171
  const poolSecret = await strategy.derivePoolSecret({ masterSecret });
171
172
  const challengeId = "a3ff7843552870fc28bef2b"; // arbitrary random challengeId
@@ -184,7 +185,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
184
185
  iReckon(sir, isValid).asTo('valid pair should pass').isGonnaBeTrue();
185
186
  });
186
187
 
187
- await ifWe(sir, 'validateSolution fails for mismatched values', async () => {
188
+ await ifWeMight(sir, 'validateSolution fails for mismatched values', async () => {
188
189
  const strategy = KeystoneStrategyFactory.create({ config });
189
190
  const poolSecret = await strategy.derivePoolSecret({ masterSecret });
190
191
  const challengeId = "8c994f3ed598f150e25513"; // arbitrary random challengeId
@@ -200,7 +201,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
200
201
  iReckon(sir, isValid).asTo('tampered solution should fail').isGonnaBeFalse();
201
202
  });
202
203
 
203
- await ifWe(sir, 'validateSolution fails for mismatched challenge hashes', async () => {
204
+ await ifWeMight(sir, 'validateSolution fails for mismatched challenge hashes', async () => {
204
205
  const strategy = KeystoneStrategyFactory.create({ config });
205
206
  const poolSecret = await strategy.derivePoolSecret({ masterSecret });
206
207
 
@@ -241,7 +242,7 @@ await respecfully(sir, 'Suite B: Service Lifecycle', async () => {
241
242
  });
242
243
 
243
244
  await respecfully(sir, 'Genesis', async () => {
244
- await ifWe(sir, 'creates a valid genesis frame and persists it', async () => {
245
+ await ifWeMight(sir, 'creates a valid genesis frame and persists it', async () => {
245
246
  const salt = (await getUUID()).substring(0, 16);
246
247
  const config = createStandardPoolConfig({
247
248
  id: POOL_ID_DEFAULT,
@@ -273,7 +274,7 @@ await respecfully(sir, 'Suite B: Service Lifecycle', async () => {
273
274
  });
274
275
 
275
276
  await respecfully(sir, 'Signing (Evolution)', async () => {
276
- await ifWe(sir, 'evolves the keystone with a valid proof', async () => {
277
+ await ifWeMight(sir, 'evolves the keystone with a valid proof', async () => {
277
278
  const claim: Partial<KeystoneClaim> = {
278
279
  target: "comment 123^gib",
279
280
  verb: "post"
@@ -303,7 +304,7 @@ await respecfully(sir, 'Suite B: Service Lifecycle', async () => {
303
304
  });
304
305
 
305
306
  await respecfully(sir, 'Validation', async () => {
306
- await ifWe(sir, 'validates the genesis->signed transition', async () => {
307
+ await ifWeMight(sir, 'validates the genesis->signed transition', async () => {
307
308
  const errors = await service.validate({
308
309
  prevIbGib: genesisKeystone,
309
310
  currentIbGib: signedKeystone,
@@ -352,7 +353,7 @@ await respecfully(sir, 'Suite C: Security Vectors', async () => {
352
353
  });
353
354
 
354
355
  await respecfully(sir, 'Wrong Secret (Forgery)', async () => {
355
- await ifWe(sir, 'prevents creation of forged frames', async () => {
356
+ await ifWeMight(sir, 'prevents creation of forged frames', async () => {
356
357
  const claim: Partial<KeystoneClaim> = { target: "comment 123^gib", verb: "post" };
357
358
 
358
359
  let errorCaught = false;
@@ -381,7 +382,7 @@ await respecfully(sir, 'Suite C: Security Vectors', async () => {
381
382
  });
382
383
 
383
384
  await respecfully(sir, 'Policy Violation (Restricted Verbs)', async () => {
384
- await ifWe(sir, 'throws error if signing forbidden verb with restricted pool', async () => {
385
+ await ifWeMight(sir, 'throws error if signing forbidden verb with restricted pool', async () => {
385
386
  // Create a specific restricted pool config manually
386
387
  const restrictedPoolId = "read_only_pool";
387
388
  const restrictedConfig = createStandardPoolConfig({
@@ -461,7 +462,7 @@ await respecfully(sir, 'Suite D: Revocation', async () => {
461
462
  await respecfully(sir, 'Revoke Lifecycle', async () => {
462
463
  let revokedKeystone: KeystoneIbGib_V1;
463
464
 
464
- await ifWe(sir, 'successfully creates a revocation frame', async () => {
465
+ await ifWeMight(sir, 'successfully creates a revocation frame', async () => {
465
466
  revokedKeystone = await service.revoke({
466
467
  latestKeystone: genesisKeystone,
467
468
  masterSecret,
@@ -479,7 +480,7 @@ await respecfully(sir, 'Suite D: Revocation', async () => {
479
480
  iReckon(sir, data.revocationInfo!.proof.claim.verb).willEqual(KEYSTONE_VERB_REVOKE);
480
481
  });
481
482
 
482
- await ifWe(sir, 'validates the revocation frame', async () => {
483
+ await ifWeMight(sir, 'validates the revocation frame', async () => {
483
484
  const errors = await service.validate({
484
485
  prevIbGib: genesisKeystone,
485
486
  currentIbGib: revokedKeystone!,
@@ -490,7 +491,7 @@ await respecfully(sir, 'Suite D: Revocation', async () => {
490
491
  iReckon(sir, errors.length).asTo('no validation errors').willEqual(0);
491
492
  });
492
493
 
493
- await ifWe(sir, 'consumed the revocation pool (Scorched Earth)', async () => {
494
+ await ifWeMight(sir, 'consumed the revocation pool (Scorched Earth)', async () => {
494
495
  const data = revokedKeystone!.data!;
495
496
  const revokePool = data.challengePools.find(p => p.id === POOL_ID_REVOKE);
496
497
 
@@ -528,7 +529,6 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
528
529
  const strategy = KeystoneStrategyFactory.create({ config });
529
530
  const poolSecret = await strategy.derivePoolSecret({ masterSecret: bobSecret });
530
531
  const challenges: { [id: string]: any } = {};
531
- const bindingMap: { [char: string]: string[] } = {};
532
532
 
533
533
  for (let i = 0; i < 10; i++) {
534
534
  // Manually replicate ID gen for test
@@ -540,14 +540,12 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
540
540
  });
541
541
  const challenge = await strategy.generateChallenge({ solution });
542
542
  challenges[challengeId] = challenge;
543
- addToBindingMap(bindingMap, challengeId);
544
543
  }
545
544
 
546
545
  return {
547
546
  id,
548
547
  config,
549
548
  challenges,
550
- bindingMap,
551
549
  isForeign: true,
552
550
  metadata: { owner: 'Bob' }
553
551
  };
@@ -569,7 +567,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
569
567
  });
570
568
 
571
569
  await respecfully(sir, 'Happy Path', async () => {
572
- await ifWe(sir, 'authorizes and adds a foreign pool', async () => {
570
+ await ifWeMight(sir, 'authorizes and adds a foreign pool', async () => {
573
571
  const bobPool = await createForeignPool("pool_bob", ["post"]);
574
572
 
575
573
  const updatedKeystone = await service.addPools({
@@ -608,7 +606,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
608
606
  });
609
607
 
610
608
  await respecfully(sir, 'Permissions & Logic', async () => {
611
- await ifWe(sir, 'fails if no pool allows "manage" verb', async () => {
609
+ await ifWeMight(sir, 'fails if no pool allows "manage" verb', async () => {
612
610
  // 1. Create a restricted keystone
613
611
  let id = "read_only";
614
612
  const restrictedConfig = createStandardPoolConfig({ id, salt: id });
@@ -641,7 +639,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
641
639
  iReckon(sir, errorCaught).asTo('permission denied').isGonnaBeTrue();
642
640
  });
643
641
 
644
- await ifWe(sir, 'fails on ID collision', async () => {
642
+ await ifWeMight(sir, 'fails on ID collision', async () => {
645
643
  // Try to add "pool_bob" again (it was added in Happy Path)
646
644
  const duplicatePool = await createForeignPool("pool_bob");
647
645
 
@@ -688,7 +686,6 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
688
686
  const strategy = KeystoneStrategyFactory.create({ config });
689
687
  const poolSecret = await strategy.derivePoolSecret({ masterSecret: bobSecret });
690
688
  const challenges: { [id: string]: any } = {};
691
- const bindingMap: { [char: string]: string[] } = {};
692
689
 
693
690
  // Generate a small set of challenges
694
691
  for (let i = 0; i < 10; i++) {
@@ -700,14 +697,12 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
700
697
  });
701
698
  const challenge = await strategy.generateChallenge({ solution });
702
699
  challenges[challengeId] = challenge;
703
- addToBindingMap(bindingMap, challengeId);
704
700
  }
705
701
 
706
702
  return {
707
703
  id,
708
704
  config,
709
705
  challenges,
710
- bindingMap,
711
706
  isForeign: true,
712
707
  metadata: { owner: 'Bob', role: 'Delegate' }
713
708
  };
@@ -732,7 +727,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
732
727
  });
733
728
 
734
729
  await respecfully(sir, 'Happy Path', async () => {
735
- await ifWe(sir, 'authorizes and adds a foreign pool', async () => {
730
+ await ifWeMight(sir, 'authorizes and adds a foreign pool', async () => {
736
731
  const bobPool = await createForeignPool("pool_bob", ["post"]);
737
732
 
738
733
  const updatedKeystone = await service.addPools({
@@ -771,7 +766,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
771
766
  });
772
767
 
773
768
  await respecfully(sir, 'Permissions & Logic', async () => {
774
- await ifWe(sir, 'fails if no pool allows "manage" verb', async () => {
769
+ await ifWeMight(sir, 'fails if no pool allows "manage" verb', async () => {
775
770
  // 1. Create a restricted keystone (read-only)
776
771
  let id = "read_only";
777
772
  const restrictedConfig = createStandardPoolConfig({ id, salt: id });
@@ -804,7 +799,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
804
799
  iReckon(sir, errorCaught).asTo('permission denied').isGonnaBeTrue();
805
800
  });
806
801
 
807
- await ifWe(sir, 'fails on ID collision', async () => {
802
+ await ifWeMight(sir, 'fails on ID collision', async () => {
808
803
  // Try to add "pool_bob" again (it was added in Happy Path)
809
804
  const duplicatePool = await createForeignPool("pool_bob");
810
805
 
@@ -866,7 +861,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
866
861
 
867
862
  await respecfully(sir, 'Proof Granularity & Math', async () => {
868
863
 
869
- await ifWe(sir, 'generates exactly the expected number of solutions', async () => {
864
+ await ifWeMight(sir, 'generates exactly the expected number of solutions', async () => {
870
865
  signedKeystone = await service.sign({
871
866
  latestKeystone: genesisKeystone,
872
867
  masterSecret: aliceSecret,
@@ -883,7 +878,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
883
878
  iReckon(sir, solutions.length).asTo('solution count').willEqual(4);
884
879
  });
885
880
 
886
- await ifWe(sir, 'verifies the math manually (White-box Crypto Check)', async () => {
881
+ await ifWeMight(sir, 'verifies the math manually (White-box Crypto Check)', async () => {
887
882
  const proof = signedKeystone.data!.proofs[0];
888
883
  const poolSnapshot = genesisKeystone.data!.challengePools.find(p => p.id === poolId)!;
889
884
 
@@ -912,7 +907,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
912
907
  }
913
908
  });
914
909
 
915
- await ifWe(sir, 'verifies FIFO logic (Deterministic Selection)', async () => {
910
+ await ifWeMight(sir, 'verifies FIFO logic (Deterministic Selection)', async () => {
916
911
  const proof = signedKeystone.data!.proofs[0];
917
912
  const poolSnapshot = genesisKeystone.data!.challengePools.find(p => p.id === poolId)!;
918
913
 
@@ -930,11 +925,75 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
930
925
  iReckon(sir, hasFirst).asTo(`Solution includes 1st FIFO ID (${expectedFifoIds[0]})`).isGonnaBeTrue();
931
926
  iReckon(sir, hasSecond).asTo(`Solution includes 2nd FIFO ID (${expectedFifoIds[1]})`).isGonnaBeTrue();
932
927
  });
928
+
929
+ await ifWeMight(sir, 'verifies Next-Gen Hash-Based Target Binding Selection', async () => {
930
+ const bindingConfig = createStandardPoolConfig({
931
+ id: "binding_pool",
932
+ salt: "binding_salt",
933
+ sequential: 0,
934
+ random: 0,
935
+ targetBinding: 3,
936
+ size: 20
937
+ }) as KeystonePoolConfig_HashV1;
938
+
939
+ const tempGenesis = await service.genesis({
940
+ masterSecret: aliceSecret,
941
+ configs: [bindingConfig],
942
+ metaspace: mockMetaspace,
943
+ space: mockSpace as any,
944
+ });
945
+
946
+ // Evolve using the binding pool
947
+ const evolved = await service.sign({
948
+ latestKeystone: tempGenesis,
949
+ masterSecret: aliceSecret,
950
+ poolId: "binding_pool",
951
+ claim: {
952
+ verb: "sign",
953
+ target: "some_target_address^gib"
954
+ },
955
+ metaspace: mockMetaspace,
956
+ space: mockSpace as any,
957
+ });
958
+
959
+ const proof = evolved.data!.proofs[0];
960
+ iReckon(sir, proof.solutions.length).asTo('proof solutions count').willEqual(3);
961
+
962
+ // Now, let's verify that the selection is perfectly deterministic.
963
+ // If we run selectChallengeIds manually with the same pool and target, it must return the same IDs.
964
+ const poolSnapshot = tempGenesis.data!.challengePools.find(p => p.id === "binding_pool")!;
965
+ const selectedIds = await selectChallengeIds({
966
+ pool: poolSnapshot,
967
+ targetAddr: "some_target_address^gib"
968
+ });
969
+
970
+ const proofIds = proof.solutions.map(s => s.challengeId);
971
+ iReckon(sir, selectedIds.length).asTo('selected IDs count').willEqual(3);
972
+ for (const id of selectedIds) {
973
+ iReckon(sir, proofIds.includes(id)).asTo(`proof includes selected ID ${id}`).isGonnaBeTrue();
974
+ }
975
+ });
976
+
977
+ await ifWeMight(sir, 'fails validation if total requested challenges >= size', async () => {
978
+ const invalidConfig = createStandardPoolConfig({
979
+ id: "invalid_pool",
980
+ salt: "invalid_salt",
981
+ sequential: 5,
982
+ random: 5,
983
+ targetBinding: 6,
984
+ size: 15 // total requested is 5+5+6 = 16 >= 15
985
+ });
986
+
987
+ const errors = await validateChallengePool({ pool: { id: "invalid_pool", config: invalidConfig, challenges: {} } });
988
+ iReckon(sir, errors.length > 0).asTo('errors length is positive').isGonnaBeTrue();
989
+ const hasCorrectError = errors.some(e => e.includes("Total requested challenges"));
990
+ iReckon(sir, hasCorrectError).asTo('validation error content').isGonnaBeTrue();
991
+ });
933
992
  });
934
993
 
935
994
  await respecfully(sir, 'DTO & Serialization', async () => {
936
995
 
937
- await ifWe(sir, 'survives a clone/JSON-cycle without corruption', async () => {
996
+ await ifWeMight(sir, 'survives a clone/JSON-cycle without corruption', async () => {
938
997
  // 1. Create a DTO (simulate network transmission/storage)
939
998
  // 'clone' does a JSON stringify/parse under the hood (usually) or structured clone.
940
999
  const dto = clone(signedKeystone);
@@ -954,7 +1013,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
954
1013
  iReckon(sir, errors.length).asTo('DTO validation errors').willEqual(0);
955
1014
  });
956
1015
 
957
- await ifWe(sir, 'ensures data contains no functions or circular refs', async () => {
1016
+ await ifWeMight(sir, 'ensures data contains no functions or circular refs', async () => {
958
1017
  // A crude but effective test: ensure JSON.stringify doesn't throw
959
1018
  // and the result is equal to the object (if we parsed it back).
960
1019
 
@@ -978,4 +1037,127 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
978
1037
  });
979
1038
 
980
1039
  });
1040
+
1041
+ await respecfully(sir, 'KeystoneProfileBuilder and Modular Schemas', async () => {
1042
+
1043
+ await ifWeMight(sir, 'compiles configs successfully with medium profile', async () => {
1044
+ const builder = KeystoneProfileBuilder.buildKeystone('medium')
1045
+ .withUsername('alice')
1046
+ .withEmail('alice@example.com')
1047
+ .withDescription('Alice test keystone')
1048
+ .withDetails({ extraInfo: 'abc' });
1049
+
1050
+ const configs = await builder.compileConfigs();
1051
+ iReckon(sir, configs.length).asTo('number of pools').willEqual(5);
1052
+
1053
+ // Verify unique salt derivation per pool
1054
+ const salts = configs.map(c => c.salt);
1055
+ const uniqueSalts = new Set(salts);
1056
+ iReckon(sir, uniqueSalts.size).asTo('unique salts count').willEqual(5);
1057
+
1058
+ // Verify frameDetails unification
1059
+ const details = builder.getFrameDetails();
1060
+ iReckon(sir, details.username).asTo('username').willEqual('alice');
1061
+ iReckon(sir, details.email).asTo('email').willEqual('alice@example.com');
1062
+ iReckon(sir, details.description).asTo('description').willEqual('Alice test keystone');
1063
+ iReckon(sir, details.extraInfo).asTo('extraInfo').willEqual('abc');
1064
+ });
1065
+
1066
+ await ifWeMight(sir, 'supports customized overrides', async () => {
1067
+ const builder = KeystoneProfileBuilder.buildKeystone('test')
1068
+ .customizePool('sync', {
1069
+ behavior: {
1070
+ size: 15,
1071
+ targetBindingCount: 4
1072
+ }
1073
+ });
1074
+
1075
+ const configs = await builder.compileConfigs();
1076
+ const syncPool = configs.find(c => c.id === 'sync')!;
1077
+ iReckon(sir, syncPool.behavior.size).asTo('customized size').willEqual(15);
1078
+ iReckon(sir, syncPool.behavior.targetBindingCount).asTo('customized target binding').willEqual(4);
1079
+ });
1080
+
1081
+ });
1082
+
1083
+ await respecfully(sir, 'Keystone Metadata Validation', async () => {
1084
+
1085
+ await ifWeMight(sir, 'validates correct username and description', async () => {
1086
+ const service = new KeystoneService_V1();
1087
+ const space = new MockIbGibSpace();
1088
+ const metaspace = new MockMetaspaceService(space);
1089
+
1090
+ const builder = KeystoneProfileBuilder.buildKeystone('test')
1091
+ .withUsername('alice_123.test')
1092
+ .withDescription('Valid description: yes, it is!')
1093
+ .withDetails({ client: 'respec' });
1094
+
1095
+ const configs = await builder.compileConfigs();
1096
+ const frameDetails = builder.getFrameDetails();
1097
+
1098
+ // Should succeed without error
1099
+ const keystoneIbGib = await service.genesis({
1100
+ masterSecret: 'mysecret',
1101
+ configs,
1102
+ metaspace: metaspace as any,
1103
+ space: space as any,
1104
+ frameDetails
1105
+ });
1106
+
1107
+ const errors = await service.validateGenesisKeystone({ keystoneIbGib });
1108
+ iReckon(sir, errors.length).asTo('errors count').willEqual(0);
1109
+ });
1110
+
1111
+ await ifWeMight(sir, 'fails validation for invalid username length or character', async () => {
1112
+ const service = new KeystoneService_V1();
1113
+ const space = new MockIbGibSpace();
1114
+ const metaspace = new MockMetaspaceService(space);
1115
+
1116
+ const builder = KeystoneProfileBuilder.buildKeystone('test')
1117
+ .withUsername('invalid_user_name_that_is_way_too_long_for_the_sixty_three_char_limit_and_will_fail_regex_check')
1118
+ .withDetails({ client: 'respec' });
1119
+
1120
+ const configs = await builder.compileConfigs();
1121
+ const frameDetails = builder.getFrameDetails();
1122
+
1123
+ const keystoneIbGib = await service.genesis({
1124
+ masterSecret: 'mysecret',
1125
+ configs,
1126
+ metaspace: metaspace as any,
1127
+ space: space as any,
1128
+ frameDetails
1129
+ });
1130
+
1131
+ const errors = await service.validateGenesisKeystone({ keystoneIbGib });
1132
+ iReckon(sir, errors.length).asTo('errors count').willEqual(1);
1133
+ iReckon(sir, errors[0]).includes('invalid username');
1134
+ });
1135
+
1136
+ await ifWeMight(sir, 'fails validation for invalid description characters', async () => {
1137
+ const service = new KeystoneService_V1();
1138
+ const space = new MockIbGibSpace();
1139
+ const metaspace = new MockMetaspaceService(space);
1140
+
1141
+ const builder = KeystoneProfileBuilder.buildKeystone('test')
1142
+ .withUsername('alice')
1143
+ .withDescription('Invalid desc with weird emoji 🚀')
1144
+ .withDetails({ client: 'respec' });
1145
+
1146
+ const configs = await builder.compileConfigs();
1147
+ const frameDetails = builder.getFrameDetails();
1148
+
1149
+ const keystoneIbGib = await service.genesis({
1150
+ masterSecret: 'mysecret',
1151
+ configs,
1152
+ metaspace: metaspace as any,
1153
+ space: space as any,
1154
+ frameDetails
1155
+ });
1156
+
1157
+ const errors = await service.validateGenesisKeystone({ keystoneIbGib });
1158
+ iReckon(sir, errors.length).asTo('errors count').willEqual(1);
1159
+ iReckon(sir, errors[0]).includes('invalid description');
1160
+ });
1161
+
1162
+ });
981
1163
  });
@@ -111,10 +111,12 @@ export interface KeystonePoolBehavior {
111
111
  selectRandomly: number;
112
112
 
113
113
  /**
114
- * Number of hex characters from the Target's Gib to match.
114
+ * Number of challenges to draw deterministically from the pool using
115
+ * next-gen hash-based index selection (drawing without replacement)
116
+ * bound to the full target address (`ib` + `gib`).
115
117
  * @default 0
116
118
  */
117
- targetBindingChars: number;
119
+ targetBindingCount: number;
118
120
  }
119
121
 
120
122
  export interface KeystonePoolConfigBase {
@@ -227,13 +229,7 @@ export interface KeystoneChallengePool {
227
229
  */
228
230
  challenges: { [challengeId: string]: KeystoneChallenge };
229
231
 
230
- /**
231
- * Explicit Buckets for Target Binding.
232
- * Key: Hex Character ('0'-'f').
233
- * Value: Array of Challenge IDs that satisfy this bucket.
234
- * Note: A single ID may appear in multiple buckets (Coverage Strategy).
235
- */
236
- bindingMap: { [hexChar: string]: string[] };
232
+
237
233
 
238
234
  /**
239
235
  * If true, this pool's secrets are NOT derived from the Keystone's
@@ -0,0 +1,60 @@
1
+ # Implementation Plan: Modular Policy Schemas & Keystone Profile Builder
2
+
3
+ This document outlines the step-by-step development tasks to transition the Keystone policy engine to a modular JSON-schema composed architecture with a fluent builder.
4
+
5
+ Parent Architecture Doc: [ARCHITECTURE.md](../../../../../docs/identity/ARCHITECTURE.md)
6
+
7
+ ---
8
+
9
+ ## 📋 Task Checklist
10
+
11
+ - [x] **1. Modular JSON Schema & Profiles Definitions**
12
+ - [x] Create schemas: `sync-pool.schema.json`, `manage-pool.schema.json`, `revoke-pool.schema.json`, `connect-pool.schema.json`, `sign-pool.schema.json` under `libs/core-gib/src/keystone/policy/schemas/`.
13
+ - [x] Define composite schemas `keystone.high.schema.json`, `keystone.medium.schema.json`, `keystone.low.schema.json`.
14
+ - [x] Migrate JSON profile files to use new schema locations.
15
+
16
+ - [x] **2. Type System Refactoring**
17
+ - [x] Update [keystone-policy-types.mts](../keystone-policy-types.mts) to support composite profiles and new metadata schemas.
18
+
19
+ - [x] **3. Implement `KeystoneProfileBuilder`**
20
+ - [x] Create `keystone-profile-builder.mts` inside `libs/core-gib/src/keystone/policy/`.
21
+ - [x] Implement `buildKeystone`, `withUsername`, `withEmail`, `withDescription`, `withDetails`.
22
+ - [x] Implement `customizePool` and `compileConfigs` with unique salt derivation and `frameDetails` unification.
23
+
24
+ - [x] **4. Build Pipeline Integration**
25
+ - [x] Update `build-core-gib.mts` to copy new schema/profile directories to `dist`.
26
+
27
+ - [x] **5. Downstream Consumption Refactoring**
28
+ - [x] Refactor space-gib's `keystone-creator.mts` to use the new builder.
29
+
30
+ - [x] **6. Automated Verification**
31
+ - [x] Add integration tests in `keystone-service-v1.respec.mts` ensuring the builder and modular schemas are correctly parsed, validated, and applied.
32
+
33
+ - [x] **7. Documentation & Architecture Sync**
34
+ - [x] Update [ARCHITECTURE.md](../../../../../docs/identity/ARCHITECTURE.md) with corrected code snippets (including fluent builder code samples) and clickable links to the actual code files (like schemas and builder implementation) for reference.
35
+
36
+ ---
37
+
38
+ ## 🛠️ Build & Verification Guide
39
+
40
+ Use the following commands from the monorepo root to build and verify your changes:
41
+
42
+ ### 1. Build core-gib
43
+ Check if core-gib compiles clean:
44
+ ```powershell
45
+ npm run build:core-gib
46
+ ```
47
+
48
+ ### 2. Monorepo Chain Build
49
+ Build all libraries and compile the downstream `space-gib` application to test integration:
50
+ ```powershell
51
+ npm run chain:build:core-gib
52
+ ```
53
+
54
+ ### 3. Run Space-Gib Client
55
+ To manually test the Keystone creation process via the space-gib UI, run:
56
+ ```powershell
57
+ npm run dev:space-gib
58
+ ```
59
+
60
+
@@ -0,0 +1,94 @@
1
+ # Keystone Identity Policies & Fluent Builder
2
+
3
+ This module manages Keystone Identity Policies, including security preset profiles (`high`, `medium`, `low`), modular schema composition, and the fluent configuration builder.
4
+
5
+ ---
6
+
7
+ ## 📖 Documentation Index
8
+
9
+ * **[Policy Architecture](../../../../../docs/identity/ARCHITECTURE.md)**: Conceptual design of separate pool behaviors, verbs, and composed schemas.
10
+ * **[Implementation Roadmap](./IMPLEMENTATION.md)**: Current development checklist and tasks.
11
+
12
+ ---
13
+
14
+ ## 🛠️ Usage: Fluent Builder API
15
+
16
+ The `KeystoneProfileBuilder` provides a fluid interface to construct, enrich, and customize Keystone configurations before genesis.
17
+
18
+ ### Basic Identity Creation
19
+
20
+ ```typescript
21
+ import { KeystoneProfileBuilder } from "@ibgib/core-gib/dist/keystone/policy/keystone-profile-builder.mjs";
22
+
23
+ // Build a medium-security identity config salted for a specific user
24
+ const configs = KeystoneProfileBuilder
25
+ .buildKeystone('medium')
26
+ .withUsername('alice')
27
+ .withEmail('alice@example.com')
28
+ .withDescription('Main user identity for Space-Gib')
29
+ .compileConfigs();
30
+
31
+ // Pass these configurations directly to genesis
32
+ const identity = await keystoneService.genesis({
33
+ masterSecret,
34
+ configs,
35
+ metaspace,
36
+ space
37
+ });
38
+ ```
39
+
40
+ ### Unifying Identity Details
41
+
42
+ The metadata provided to `withUsername`, `withEmail`, `withDescription`, and `withDetails` are automatically consolidated into the unified `frameDetails` field of the genesis frame:
43
+
44
+ ```typescript
45
+ const configs = KeystoneProfileBuilder
46
+ .buildKeystone('low')
47
+ .withUsername('bob')
48
+ .withDetails({
49
+ device: 'Pixel 8 Pro',
50
+ os: 'Android 14'
51
+ })
52
+ .compileConfigs();
53
+ ```
54
+
55
+ ### Runtime Customizations
56
+
57
+ If an application needs to customize a specific pool's parameters dynamically (for example, raising KDF hash rounds on the sync pool for higher-security environments), use `customizePool`:
58
+
59
+ ```typescript
60
+ const configs = KeystoneProfileBuilder
61
+ .buildKeystone('medium')
62
+ .withUsername('charlie')
63
+ .customizePool('sync', {
64
+ rounds: 5, // Override base medium profile rounds
65
+ })
66
+ .compileConfigs();
67
+ ```
68
+
69
+ ---
70
+
71
+ ## ⚠️ TypeScript & JSON Config Integration
72
+
73
+ If downstream projects import or load their own JSON configurations (e.g., custom `.json` files representing schemas or behavior configurations) rather than relying solely on the built-in profiles, TypeScript requires explicit path tracking in projects using `"composite": true`.
74
+
75
+ To prevent compiler errors like `TS6307: File '...' is not listed within the file list...`, ensure your project's `tsconfig.json` contains:
76
+
77
+ 1. `"resolveJsonModule": true` under `compilerOptions` to allow static importing of JSON files as ES modules.
78
+ 2. The folder/wildcard path of the JSON files added to the `"include"` array. For example:
79
+
80
+ ```json
81
+ {
82
+ "compilerOptions": {
83
+ "composite": true,
84
+ "resolveJsonModule": true,
85
+ "module": "ESNext"
86
+ },
87
+ "include": [
88
+ "src/**/*.ts",
89
+ "src/**/*.mts",
90
+ "src/custom-policies/*.json"
91
+ ]
92
+ }
93
+ ```
94
+