@ibgib/space-gib 0.0.1 → 0.0.3

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 (33) hide show
  1. package/dist/client/bootstrap.mjs +1 -1
  2. package/dist/client/bootstrap.mjs.map +1 -1
  3. package/dist/client/chunk-2KJC5XKE.mjs +31 -0
  4. package/dist/client/chunk-2KJC5XKE.mjs.map +7 -0
  5. package/dist/client/chunk-QNIXTRFO.mjs +235 -0
  6. package/dist/client/chunk-QNIXTRFO.mjs.map +7 -0
  7. package/dist/client/index.html +47 -9
  8. package/dist/client/index.mjs +1 -1
  9. package/dist/client/script.mjs +1 -1
  10. package/dist/client/style.css +26 -0
  11. package/dist/server/server.mjs +5752 -1010
  12. package/dist/server/server.mjs.map +4 -4
  13. package/package.json +1 -1
  14. package/src/client/AUTO-GENERATED-version.mts +1 -1
  15. package/src/client/api/space-gib-api-bridge.mts +119 -8
  16. package/src/client/dev-tools.mts +717 -31
  17. package/src/client/index.html +47 -9
  18. package/src/client/style.css +26 -0
  19. package/src/common/keystone-policies.json +64 -0
  20. package/src/common/keystone-policies.mts +39 -86
  21. package/src/server/serve-gib/handlers/api/debug/ws-echo.handler.mts +13 -12
  22. package/src/server/serve-gib/handlers/api/keystone/keystone-evolve.handler.mts +14 -167
  23. package/src/server/serve-gib/handlers/api/keystone/keystone-genesis.handler.mts +6 -6
  24. package/src/server/serve-gib/handlers/api/keystone/keystone-get.respec.mts +3 -3
  25. package/src/server/serve-gib/handlers/api/keystone/keystone-post.handler.mts +10 -25
  26. package/src/server/serve-gib/handlers/ws/sync-upgrade-handler-base.mts +205 -0
  27. package/src/server/serve-gib/handlers/ws/sync-upgrade.handler.mts +13 -487
  28. package/src/server/serve-gib/handlers/ws/ws-helper.mts +80 -3
  29. package/dist/client/chunk-CT47Z5WU.mjs +0 -21
  30. package/dist/client/chunk-CT47Z5WU.mjs.map +0 -7
  31. package/dist/client/chunk-RHEDTRKF.mjs +0 -235
  32. package/dist/client/chunk-RHEDTRKF.mjs.map +0 -7
  33. package/dist/respec-gib.node.mjs +0 -5
@@ -73,7 +73,7 @@
73
73
  <p class="placeholder-text">Left Panel Content</p>
74
74
  </div>
75
75
  </aside>
76
-
76
+
77
77
  <!-- Left Resizer -->
78
78
  <div id="left-resizer" class="resizer resizer-v"></div>
79
79
 
@@ -103,15 +103,53 @@
103
103
  <!-- DEV TOOLS — remove or hide once WS sync is confirmed working -->
104
104
  <section class="dev-panel" id="dev-panel" aria-label="Developer tools">
105
105
  <h2 class="dev-panel-title">Dev Tools</h2>
106
- <div class="dev-panel-row">
107
- <button id="btn-print-dev-state" class="dev-btn">Print Dev State</button>
108
- <button id="btn-create-domain-keystone" class="dev-btn">1. Create Domain Keystone (I)</button>
109
- <button id="btn-create-test-ibgib" class="dev-btn" disabled>2. Create Test IbGib (X)</button>
110
- <button id="btn-create-session-keystone" class="dev-btn" disabled>3. Create Session Keystone (S)</button>
111
- <button id="btn-evolve-domain-keystone" class="dev-btn" disabled>4. Evolve Domain Keystone (I^I1)</button>
112
- <button id="btn-perform-sync" class="dev-btn" disabled>5. Perform Sync Handshake (S)</button>
113
- <button id="btn-test-ws" class="dev-btn">Test WebSocket Echo</button>
106
+
107
+ <!-- Row 00: Raw POC buttons -->
108
+ <div class="dev-panel-row-container">
109
+ <span class="dev-panel-row-label">00</span>
110
+ <div class="dev-panel-row">
111
+ <button id="btn-print-dev-state" class="dev-btn">Print Dev State</button>
112
+ <button id="btn-create-domain-keystone" class="dev-btn">1. Create Domain Keystone (I)</button>
113
+ <button id="btn-create-test-ibgib" class="dev-btn" disabled>2. Create Test IbGib (X)</button>
114
+ <button id="btn-create-session-keystone" class="dev-btn" disabled>3. Create Session Keystone
115
+ (S)</button>
116
+ <button id="btn-evolve-domain-keystone" class="dev-btn" disabled>4. Evolve Domain Keystone
117
+ (I^I1)</button>
118
+ <button id="btn-perform-sync" class="dev-btn" disabled>5. Perform Sync Handshake (S)</button>
119
+ <button id="btn-test-ws" class="dev-btn">Test WebSocket Echo</button>
120
+ </div>
114
121
  </div>
122
+
123
+ <!-- Row 1B: Phase 1B -->
124
+ <div class="dev-panel-row-container">
125
+ <span class="dev-panel-row-label">1B</span>
126
+ <div class="dev-panel-row">
127
+ <button id="btn-1b-setup" class="dev-btn">1B Setup</button>
128
+ <button id="btn-1b-sync" class="dev-btn" disabled>1B Sync</button>
129
+ <button id="btn-1b-check" class="dev-btn" disabled>1B Check</button>
130
+ </div>
131
+ </div>
132
+
133
+ <!-- Row 2B: Phase 2B -->
134
+ <div class="dev-panel-row-container">
135
+ <span class="dev-panel-row-label">2B</span>
136
+ <div class="dev-panel-row">
137
+ <button id="btn-2b-setup" class="dev-btn">2B Setup</button>
138
+ <button id="btn-2b-sync" class="dev-btn" disabled>2B Sync</button>
139
+ <button id="btn-2b-check" class="dev-btn" disabled>2B Check</button>
140
+ </div>
141
+ </div>
142
+
143
+ <!-- Row 3B: Phase 3B -->
144
+ <div class="dev-panel-row-container">
145
+ <span class="dev-panel-row-label">3B</span>
146
+ <div class="dev-panel-row">
147
+ <button id="btn-3b-setup" class="dev-btn">3B Setup</button>
148
+ <button id="btn-3b-sync" class="dev-btn" disabled>3B Sync</button>
149
+ <button id="btn-3b-check" class="dev-btn" disabled>3B Check</button>
150
+ </div>
151
+ </div>
152
+
115
153
  <pre id="dev-panel-log" class="dev-panel-log" aria-live="polite" aria-label="Dev log"></pre>
116
154
  </section>
117
155
  </div>
@@ -603,3 +603,29 @@ body::before {
603
603
  word-break: break-all;
604
604
  min-height: 3rem;
605
605
  }
606
+
607
+ /* dev tools row styles */
608
+ .dev-panel-row-container {
609
+ display: flex;
610
+ align-items: center;
611
+ gap: 1.25rem;
612
+ border-bottom: 1px solid rgba(255, 204, 68, 0.08);
613
+ padding-bottom: 0.85rem;
614
+ }
615
+ .dev-panel-row-container:last-of-type {
616
+ border-bottom: none;
617
+ padding-bottom: 0;
618
+ }
619
+ .dev-panel-row-label {
620
+ font-family: var(--font-mono);
621
+ font-size: 0.85rem;
622
+ font-weight: 700;
623
+ color: var(--clr-warn);
624
+ min-width: 2.2rem;
625
+ text-align: center;
626
+ border: 1px solid rgba(255, 204, 68, 0.25);
627
+ border-radius: var(--radius-sm);
628
+ padding: 0.25rem 0.45rem;
629
+ background: rgba(255, 204, 68, 0.06);
630
+ user-select: none;
631
+ }
@@ -0,0 +1,64 @@
1
+ {
2
+ "$schema": "../../../../libs/core-gib/src/keystone/keystone-policy.schema.json",
3
+ "behaviorProfiles": {
4
+ "standard": {
5
+ "size": 200,
6
+ "replenish": "top-up",
7
+ "selectSequentially": 2,
8
+ "selectRandomly": 2,
9
+ "targetBindingChars": 5
10
+ },
11
+ "high-security": {
12
+ "size": 2000,
13
+ "replenish": "replace-all",
14
+ "selectSequentially": 5,
15
+ "selectRandomly": 5,
16
+ "targetBindingChars": 16
17
+ },
18
+ "session-connect": {
19
+ "size": 20,
20
+ "replenish": "top-up",
21
+ "selectSequentially": 2,
22
+ "selectRandomly": 2,
23
+ "targetBindingChars": 3
24
+ }
25
+ },
26
+ "pools": {
27
+ "sync": {
28
+ "id": "sync",
29
+ "allowedVerbs": [
30
+ "sync"
31
+ ],
32
+ "behaviorProfile": "standard",
33
+ "algo": "SHA-256",
34
+ "rounds": 1
35
+ },
36
+ "manage": {
37
+ "id": "manage",
38
+ "allowedVerbs": [
39
+ "manage"
40
+ ],
41
+ "behaviorProfile": "high-security",
42
+ "algo": "SHA-512",
43
+ "rounds": 10
44
+ },
45
+ "revoke": {
46
+ "id": "revoke",
47
+ "allowedVerbs": [
48
+ "revoke"
49
+ ],
50
+ "behaviorProfile": "high-security",
51
+ "algo": "SHA-512",
52
+ "rounds": 10
53
+ },
54
+ "connect": {
55
+ "id": "connect",
56
+ "allowedVerbs": [
57
+ "connect"
58
+ ],
59
+ "behaviorProfile": "session-connect",
60
+ "algo": "SHA-256",
61
+ "rounds": 1
62
+ }
63
+ }
64
+ }
@@ -12,15 +12,39 @@
12
12
 
13
13
  import { HashAlgorithm } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
14
14
  import {
15
- KeystoneReplenishStrategy,
16
- KeystoneChallengeType,
17
- KeystoneIbGib_V1,
18
- KeystoneSolution
19
- } from '@ibgib/core-gib/dist/keystone/keystone-types.mjs';
20
- import { KeystoneStrategyFactory } from '@ibgib/core-gib/dist/keystone/strategy/keystone-strategy-factory.mjs';
15
+ SESSION_KEYSTONE_POLICY as CORE_SESSION_KEYSTONE_POLICY,
16
+ getConnectChallenge as coreGetConnectChallenge,
17
+ checkConnectSolution as coreCheckConnectSolution
18
+ } from '@ibgib/core-gib/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mjs';
19
+ import { createPoolConfigFromJson, KeystonePoolTemplate, KeystoneBehaviorProfileTemplate } from '@ibgib/core-gib/dist/keystone/keystone-config-builder.mjs';
20
+ import { KeystonePoolConfig } from '@ibgib/core-gib/dist/keystone/keystone-types.mjs';
21
+
22
+ import rawPolicies from './keystone-policies.json' assert { type: 'json' };
21
23
 
22
24
  // ---------------------------------------------------------------------------
23
- // 1. Session Keystone (S) Policies
25
+ // 1. JSON Configuration Mapping & Hybrid Fallbacks
26
+ // ---------------------------------------------------------------------------
27
+
28
+ export const behaviorProfiles = rawPolicies.behaviorProfiles as Record<string, KeystoneBehaviorProfileTemplate>;
29
+ export const pools = rawPolicies.pools as Record<string, KeystonePoolTemplate>;
30
+
31
+ /**
32
+ * Resolves a pool config by key from the JSON policy file, with fallback behavior.
33
+ */
34
+ export function getSpaceGibPoolConfig(poolKey: string, salt: string): KeystonePoolConfig {
35
+ const template = pools[poolKey];
36
+ if (!template) {
37
+ throw new Error(`Pool template not found in space-gib JSON config: ${poolKey}`);
38
+ }
39
+ return createPoolConfigFromJson({
40
+ template,
41
+ behaviorProfiles,
42
+ salt
43
+ });
44
+ }
45
+
46
+ // ---------------------------------------------------------------------------
47
+ // 2. Compatibility Layer: Session Keystone (S) Policies
24
48
  // ---------------------------------------------------------------------------
25
49
 
26
50
  /**
@@ -31,12 +55,7 @@ export const SESSION_KEYSTONE_POLICY = {
31
55
  /**
32
56
  * Shared parameters across all session pools
33
57
  */
34
- COMMON: {
35
- ALGO: HashAlgorithm.sha_256,
36
- TYPE: KeystoneChallengeType.hash_reveal_v1,
37
- ROUNDS: 2,
38
- REPLENISH: KeystoneReplenishStrategy.topUp,
39
- },
58
+ COMMON: CORE_SESSION_KEYSTONE_POLICY.COMMON,
40
59
 
41
60
  /**
42
61
  * The primary authorization pool for sync actions (e.g. putting/getting ibgibs).
@@ -56,28 +75,16 @@ export const SESSION_KEYSTONE_POLICY = {
56
75
  /**
57
76
  * Dedicated pool for the WebSocket sync protocol handshake.
58
77
  */
59
- HANDSHAKE_POOL: {
60
- ID: 'handshake',
61
- VERB: 'handshake',
62
- SIZE: 10,
63
- SELECT_SEQUENTIALLY: 2,
64
- SELECT_RANDOMLY: 2,
65
- TARGET_BINDING_CHARS: 0,
66
- /** Number of IDs the server should demand during the handshake. */
67
- SERVER_DEMAND_COUNT: 3,
68
- }
78
+ CONNECT_POOL: CORE_SESSION_KEYSTONE_POLICY.CONNECT_POOL
69
79
  } as const;
70
80
 
71
81
 
72
82
  // ---------------------------------------------------------------------------
73
- // 2. Domain/Identity Keystone (I) Policies
83
+ // 3. Compatibility Layer: Domain/Identity Keystone (I) Policies
74
84
  // ---------------------------------------------------------------------------
75
85
 
76
86
  /**
77
87
  * Server-side minimum requirements for long-lived primary identity keystones.
78
- *
79
- * [Nag] These are initial placeholder standards and should be reviewed for
80
- * production hardening.
81
88
  */
82
89
  export const DOMAIN_KEYSTONE_SECURITY_STANDARDS = {
83
90
  MIN_DEFAULT_POOL_SIZE: 50,
@@ -89,71 +96,17 @@ export const DOMAIN_KEYSTONE_SECURITY_STANDARDS = {
89
96
 
90
97
 
91
98
  // ---------------------------------------------------------------------------
92
- // 3. Upfront Picket-Fence Handshake Helpers
99
+ // 4. Upfront Picket-Fence Connect Helpers
93
100
  // ---------------------------------------------------------------------------
94
101
 
95
102
  /**
96
103
  * Returns the lexicographically first challenge from the session keystone's
97
- * 'handshake' pool to be used as a deterministic, dynamic upfront pre-filter challenge.
104
+ * 'connect' pool to be used as a deterministic, dynamic upfront pre-filter challenge.
98
105
  */
99
- export function getHandshakeChallenge(keystone: KeystoneIbGib_V1): { challengeId: string; challenge: any } {
100
- const handshakePool = (keystone.data?.challengePools ?? []).find(
101
- (p) => p.id === SESSION_KEYSTONE_POLICY.HANDSHAKE_POOL.ID
102
- );
103
- if (!handshakePool) {
104
- throw new Error(`Keystone missing "${SESSION_KEYSTONE_POLICY.HANDSHAKE_POOL.ID}" pool`);
105
- }
106
-
107
- const challengeIds = Object.keys(handshakePool.challenges).sort();
108
- if (challengeIds.length === 0) {
109
- throw new Error(`Handshake pool has no challenges`);
110
- }
111
-
112
- const challengeId = challengeIds[0];
113
- const challenge = handshakePool.challenges[challengeId];
114
- return { challengeId, challenge };
115
- }
106
+ export const getConnectChallenge = coreGetConnectChallenge;
116
107
 
117
108
  /**
118
109
  * Cryptographically validates the upfront picket-fence solution against the session keystone.
119
- * Verifies that the client solved the lexicographically first challenge from the 'handshake' pool.
110
+ * Verifies that the client solved the lexicographically first challenge from the 'connect' pool.
120
111
  */
121
- export async function checkHandshakeSolution(
122
- keystone: KeystoneIbGib_V1,
123
- solutionValue: string
124
- ): Promise<boolean> {
125
- const handshakePool = (keystone.data?.challengePools ?? []).find(
126
- (p) => p.id === SESSION_KEYSTONE_POLICY.HANDSHAKE_POOL.ID
127
- );
128
- if (!handshakePool) {
129
- return false;
130
- }
131
-
132
- const { challengeId, challenge } = getHandshakeChallenge(keystone);
133
- const strategy = KeystoneStrategyFactory.create({ config: handshakePool.config });
134
- const solution: KeystoneSolution = {
135
- type: 'hash-reveal-v1',
136
- challengeId,
137
- poolId: SESSION_KEYSTONE_POLICY.HANDSHAKE_POOL.ID,
138
- value: solutionValue
139
- };
140
-
141
- return await strategy.validateSolution({ solution, challenge });
142
- }
143
-
144
- // this is what we had by default inside the sync saga coordinator
145
- // const primaryPoolConfig: KeystonePoolConfig_HashV1 = {
146
- // allowedVerbs: [KEYSTONE_VERB_MANAGE],
147
- // id: SESSION_IDENTITY_KEYSTONE_PRIMARY_POOL_ID,
148
- // salt: sagaId,
149
- // behavior: {
150
- // size: SESSION_IDENTITY_KEYSTONE_CONFIG_SIZE, // Large pool for many signatures
151
- // replenish: SESSION_IDENTITY_KEYSTONE_CONFIG_REPLENISH_STRATEGY,
152
- // selectSequentially: SESSION_IDENTITY_KEYSTONE_CONFIG_SEQUENTIAL,
153
- // selectRandomly: SESSION_IDENTITY_KEYSTONE_CONFIG_RANDOM,
154
- // targetBindingChars: SESSION_IDENTITY_KEYSTONE_CONFIG_TARGET_BINDING,
155
- // },
156
- // type: KeystoneChallengeType.hash_reveal_v1,
157
- // algo: SESSION_IDENTITY_KEYSTONE_CONFIG_ALGO,
158
- // rounds: SESSION_IDENTITY_KEYSTONE_CONFIG_ROUNDS,
159
- // };
112
+ export const checkConnectSolution = coreCheckConnectSolution;
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * This is a diagnostic-only endpoint. The goal is to confirm that:
10
10
  * 1. Traefik correctly forwards WS upgrade requests to the container
11
- * 2. The Node.js `upgrade` event fires and we can accept the handshake
11
+ * 2. The Node.js `upgrade` event fires and we can accept the connect handshake
12
12
  * 3. The browser client can open a wss:// connection and exchange frames
13
13
  *
14
14
  * Once WS sync is confirmed end-to-end, this handler can be removed or
@@ -30,7 +30,8 @@ import { extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs
30
30
 
31
31
  import { GLOBAL_LOG_A_LOT } from '../../../constants.mjs';
32
32
  import {
33
- encodeTextFrame, decodeTextFrame, encodeCloseFrame, performHandshake
33
+ encodeTextFrame, decodeTextFrame, encodeCloseFrame, performConnect,
34
+ WebSocketFrameDecoder
34
35
  } from '../../ws/ws-helper.mjs';
35
36
  import { API_PATH_REGEXES } from '../../../../path-constants.mjs';
36
37
 
@@ -63,27 +64,27 @@ export function handleWsEchoUpgrade(req: IncomingMessage, socket: Socket, head:
63
64
  try {
64
65
  if (logalot) { console.log(`${lc_fn} starting...`); }
65
66
 
66
- const ok = performHandshake(req, socket);
67
+ const ok = performConnect(req, socket);
67
68
  if (!ok) { return; }
68
69
 
69
70
  // Send the "connected" greeting
70
71
  socket.write(encodeTextFrame(JSON.stringify({ status: 'connected', msg: 'ws-echo ready' })));
71
72
 
72
73
  // Echo loop
74
+ const decoder = new WebSocketFrameDecoder();
73
75
  socket.on('data', (data: Buffer) => {
74
76
  try {
75
- const text = decodeTextFrame(data);
76
- if (text === null) {
77
- // Close frame or unsupported opcode — send close and end
78
- socket.write(encodeCloseFrame(1000));
79
- socket.end();
80
- return;
77
+ decoder.addChunk(data);
78
+ let frameText = decoder.nextFrame();
79
+ while (frameText !== null) {
80
+ if (logalot) { console.log(`${lc_fn} echo: ${frameText}`); }
81
+ socket.write(encodeTextFrame(JSON.stringify({ echo: frameText })));
82
+ frameText = decoder.nextFrame();
81
83
  }
82
- if (logalot) { console.log(`${lc_fn} echo: ${text}`); }
83
- socket.write(encodeTextFrame(JSON.stringify({ echo: text })));
84
84
  } catch (error) {
85
85
  console.error(`${lc_fn} error in data handler: ${extractErrorMsg(error)}`);
86
- socket.destroy();
86
+ socket.write(encodeCloseFrame(1000));
87
+ socket.end();
87
88
  }
88
89
  });
89
90
 
@@ -10,19 +10,16 @@
10
10
  * them to the domain metaspace to authorize the sync session.
11
11
  */
12
12
 
13
- import { extractErrorMsg, pretty } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
13
+ import { extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
14
14
  import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
15
- import { validateIbGibIntrinsically } from '@ibgib/ts-gib/dist/V1/validate-helper.mjs';
16
- import { getGibInfo } from '@ibgib/ts-gib/dist/V1/transforms/transform-helper.mjs';
17
15
  import { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
16
+ import { validateAndRegisterEvolveKeystone } from '@ibgib/core-gib/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mjs';
17
+ import { KeystoneIbGib_V1 } from '@ibgib/core-gib/dist/keystone/keystone-types.mjs';
18
18
 
19
19
  import { GLOBAL_LOG_A_LOT } from '../../../constants.mjs';
20
20
  import { ServeGibHandlerWithMetaspaceBase } from '../../handler-base.mjs';
21
21
  import { API_PATH_REGEXES } from '../../../../path-constants.mjs';
22
- import { DomainInfo, ParamsWithDomain, RequestContext, ResponseResult } from '../../../types.mjs';
23
- import { KeystoneService_V1 } from '@ibgib/core-gib/dist/keystone/keystone-service-v1.mjs';
24
- import { KeystoneIbGib_V1 } from '@ibgib/core-gib/dist/keystone/keystone-types.mjs';
25
- import { IbGibSpaceAny } from '@ibgib/core-gib/dist/witness/space/space-base-v1.mjs';
22
+ import { ParamsWithDomain, RequestContext, ResponseResult } from '../../../types.mjs';
26
23
 
27
24
  const logalot = GLOBAL_LOG_A_LOT || true;
28
25
 
@@ -50,8 +47,9 @@ export class KeystoneEvolveHandler extends ServeGibHandlerWithMetaspaceBase<Evol
50
47
  domainAddr,
51
48
  domainInfo: this.getDomainInfo({ domainAddr })
52
49
  };
50
+ } else {
51
+ return undefined;
53
52
  }
54
- return undefined;
55
53
  }
56
54
 
57
55
  protected override async validateQueryParams({ queryParams }: { queryParams: any; }): Promise<string[]> {
@@ -82,142 +80,19 @@ export class KeystoneEvolveHandler extends ServeGibHandlerWithMetaspaceBase<Evol
82
80
  return this.error(400, 'Invalid request. Body must contain keystoneIbGib (E: e234647f79282982c8012fe8015f5826)');
83
81
  }
84
82
 
85
- const addr = getIbGibAddr({ ibGib: keystoneIbGib });
86
-
87
- // 1. Intrinsic hash validation
88
- const intrinsicErrors = await validateIbGibIntrinsically({ ibGib: keystoneIbGib });
89
- if (intrinsicErrors && intrinsicErrors.length > 0) {
90
- return this.error(422, 'Intrinsic keystone validation failed. (E: 6efeb756cb0fb6c3187c8448c5035826)', { errors: intrinsicErrors });
91
- }
92
-
93
- // 2. Verify URL :domainAddr matches the keystone's tjp
94
- const { tjpGib } = getGibInfo({ ibGibAddr: addr });
95
- const expectedTjpGib = getGibInfo({ ibGibAddr: domainAddr }).punctiliarHash;
96
- if (tjpGib !== expectedTjpGib) {
97
- return this.error(422, `Keystone tjpGib (${tjpGib}) does not match URL domainAddr tjpGib (${expectedTjpGib}) (E: 703d3c64b7382f21f863c1e83533c826)`);
98
- }
99
-
100
- // 3. Load previous frame (the current tip in metaspace)
101
83
  const space = await reqCtx.metaspace.getLocalUserSpace({ lock: false });
102
84
  if (!space) {
103
85
  return this.error(500, 'No local user space found (E: a1144e5d6cd9641fb82d6b359f131126)');
104
86
  }
105
- const keystoneService = new KeystoneService_V1();
106
- let prevIbGib: KeystoneIbGib_V1;
107
- try {
108
- prevIbGib = await keystoneService.getLatestKeystone({
109
- addr: domainAddr,
110
- metaspace: reqCtx.metaspace,
111
- space
112
- });
113
- } catch (error) {
114
- return this.error(422, `Could not retrieve previous keystone tip for ${domainAddr} (E: bc2da8fb4dbda2c65851de9dd0b0eb26)`, { error: extractErrorMsg(error) });
115
- }
116
87
 
117
- // 4. Validate Evolution Transition
118
- const validationErrors = await keystoneService.validate({
119
- currentIbGib: keystoneIbGib,
120
- prevIbGib
88
+ // Delegate all intrinsic checks, transition rules, pool restrictions, and registration/persistence to core-gib helper
89
+ await validateAndRegisterEvolveKeystone({
90
+ domainAddr,
91
+ keystoneIbGib,
92
+ relatedIbGibs,
93
+ metaspace: reqCtx.metaspace,
94
+ space
121
95
  });
122
- if (validationErrors && validationErrors.length > 0) {
123
- return this.error(422, 'Keystone evolution validation failed', { errors: validationErrors });
124
- }
125
-
126
- // 5. Check Single Pool Restriction
127
- const restrictionError = this.validateSinglePoolRestriction(keystoneIbGib);
128
- if (restrictionError) {
129
- return this.error(422, restrictionError); /* <<<< returns early */
130
- }
131
-
132
- // 6. Route by claim verb
133
- const proofs = keystoneIbGib.data?.proofs ?? [];
134
- if (proofs.length !== 1) { throw new Error(`(UNEXPECTED) evolving keystone with proofs.length !== 1? we just checked that the length of proofs was exactly 1 in checkSinglePoolRestriction (E: 3021bb0ce9783e27c8e3492820aeb926)`); }
135
- const { claim } = proofs[0];
136
- if (!claim) { throw new Error(`proof.claim is falsy (E: e1dd983db341185528a75768919ea826)`); }
137
- const { verb } = claim;
138
- if (!verb) { throw new Error(`(UNEXPECTED) claim.verb falsy? atow (05/15/2026) I thought all claims should have a verb. I could be wrong of course as it's still early days. (E: 933a9856d6625b547d7ec158d678a826)`); }
139
-
140
- switch (verb) {
141
- case 'sync':
142
- return await this.handleSyncEvolution(reqCtx, keystoneIbGib, relatedIbGibs, space);
143
- default:
144
- throw new Error(`non-sync keystone evolution not yet implemented (E: 83cb29bf67d681542bfd486d0f91e726)`);
145
- // return await this.handleDefaultEvolution(reqCtx, keystoneIbGib, space);
146
- }
147
- } catch (error) {
148
- console.error(`${lc} ${extractErrorMsg(error)}`);
149
- return this.error(500, `Internal error evolving keystone`, { details: extractErrorMsg(error) });
150
- } finally {
151
- if (logalot) { console.log(`${lc} complete.`); }
152
- }
153
- }
154
-
155
- protected validateSinglePoolRestriction(keystoneIbGib: KeystoneIbGib_V1): string | undefined {
156
- const proofs = keystoneIbGib.data?.proofs ?? [];
157
- if (proofs.length === 0) {
158
- return 'No proofs found in evolved keystone data';
159
- }
160
-
161
- const poolIds = new Set<string>();
162
- for (const proof of proofs) {
163
- for (const solution of proof.solutions || []) {
164
- if (solution.poolId) {
165
- poolIds.add(solution.poolId);
166
- }
167
- }
168
- }
169
-
170
- if (poolIds.size > 1) {
171
- return `Multiple pools evolved (${Array.from(poolIds).join(', ')}). Only one pool evolution allowed at a time.`;
172
- }
173
-
174
- return undefined; // no error
175
- }
176
-
177
- protected async handleSyncEvolution(
178
- reqCtx: RequestContext<EvolveParams>,
179
- keystoneIbGib: KeystoneIbGib_V1,
180
- relatedIbGibs: IbGib_V1[],
181
- space: IbGibSpaceAny
182
- ): Promise<ResponseResult> {
183
- const lc = `${this.lc}[${this.handleSyncEvolution.name}]`;
184
- try {
185
- if (logalot) { console.log(`${lc} starting... (I: 80cf7ba10a781fad87171b747de10826)`); }
186
-
187
- if (logalot) { console.log(`${lc} starting...`); }
188
-
189
- const proofs = keystoneIbGib.data?.proofs ?? [];
190
- if (proofs.length !== 1) { throw new Error(`(UNEXPECTED) proofs.length !== 1? (E: ac9748a187f87455bc01fdeeb4363826)`); }
191
- const claim = proofs[0].claim;
192
- const sAddr = claim?.target;
193
- if (!sAddr) {
194
- return this.error(422, 'No target address found in sync claim');
195
- }
196
-
197
- // Validate S^Stjp (session keystone ibgib) from relatedIbGibs
198
- const sIbGib = relatedIbGibs.find(ibGib => getIbGibAddr({ ibGib }) === sAddr) as KeystoneIbGib_V1 | undefined;
199
- if (!sIbGib) {
200
- return this.error(422, `Session keystone ${sAddr} must be provided in relatedIbGibs`);
201
- }
202
-
203
- const sIntrinsicErrors = await validateIbGibIntrinsically({ ibGib: sIbGib });
204
- if (sIntrinsicErrors && sIntrinsicErrors.length > 0) {
205
- return this.error(422, 'Intrinsic validation failed for S^Stjp', { errors: sIntrinsicErrors });
206
- }
207
-
208
- const keystoneService = new KeystoneService_V1();
209
- const sGenesisErrors = await keystoneService.validateGenesisKeystone({ keystoneIbGib: sIbGib });
210
- if (sGenesisErrors && sGenesisErrors.length > 0) {
211
- return this.error(422, 'Genesis validation failed for S^Stjp', { errors: sGenesisErrors });
212
- }
213
-
214
- // Persist both I and S
215
- await reqCtx.metaspace!.put({ ibGibs: [keystoneIbGib, sIbGib], space });
216
- await reqCtx.metaspace!.registerNewIbGib({ ibGib: keystoneIbGib, space });
217
- await reqCtx.metaspace!.registerNewIbGib({ ibGib: sIbGib, space });
218
-
219
- const addr = getIbGibAddr({ ibGib: keystoneIbGib });
220
- if (logalot) { console.log(`${lc} domain evolution stored and registered: ${addr}`); }
221
96
 
222
97
  return this.ok({
223
98
  message: `Successfully evolved domain keystone with session keystone`,
@@ -225,37 +100,9 @@ export class KeystoneEvolveHandler extends ServeGibHandlerWithMetaspaceBase<Evol
225
100
 
226
101
  } catch (error) {
227
102
  console.error(`${lc} ${extractErrorMsg(error)}`);
228
- throw error;
103
+ return this.error(422, `Evolve validation/persistence failed: ${extractErrorMsg(error)}`);
229
104
  } finally {
230
105
  if (logalot) { console.log(`${lc} complete.`); }
231
106
  }
232
107
  }
233
-
234
- protected async handleDefaultEvolution(
235
- reqCtx: RequestContext<EvolveParams>,
236
- keystoneIbGib: KeystoneIbGib_V1,
237
- space: IbGibSpaceAny
238
- ): Promise<ResponseResult> {
239
- const lc = `${this.lc}[${this.handleDefaultEvolution.name}]`;
240
- try {
241
- if (logalot) { console.log(`${lc} starting... (I: 8b755b4087b16c0d760d3ca397fad726)`); }
242
-
243
- // Persist only I
244
- await reqCtx.metaspace!.put({ ibGibs: [keystoneIbGib], space });
245
- await reqCtx.metaspace!.registerNewIbGib({ ibGib: keystoneIbGib, space });
246
-
247
- const addr = getIbGibAddr({ ibGib: keystoneIbGib });
248
- if (logalot) { console.log(`${lc} domain evolution stored and registered: ${addr} (I: 990d686a19d645afaa624e386caac826)`); }
249
-
250
- return this.ok({
251
- message: `Successfully evolved domain keystone. (I: 4cd058a08a171069982a7f3808cbe826)`,
252
- });
253
- } catch (error) {
254
- console.error(`${lc} ${extractErrorMsg(error)}`);
255
- throw error;
256
- } finally {
257
- if (logalot) { console.log(`${lc} complete.`); }
258
- }
259
- }
260
-
261
108
  }
@@ -74,12 +74,12 @@ export class KeystoneGenesisHandler extends ServeGibHandlerBase<undefined, undef
74
74
  try {
75
75
  parsed = JSON.parse(reqCtx.body);
76
76
  } catch {
77
- return this.error(400, 'Request body must be valid JSON');
77
+ return this.error(400, 'Request body must be valid JSON (E: dd8618857568f8fc5e9c62b8ed135826)');
78
78
  }
79
79
 
80
80
  const { keystoneIbGib } = parsed;
81
81
  if (!keystoneIbGib) {
82
- return this.error(400, 'Body must contain keystoneIbGib');
82
+ return this.error(400, 'Body must contain keystoneIbGib (E: 9c8c5d979d7842cd716ba64f69349c26)');
83
83
  }
84
84
 
85
85
  // ----------------------------------------------------------------
@@ -87,7 +87,7 @@ export class KeystoneGenesisHandler extends ServeGibHandlerBase<undefined, undef
87
87
  // ----------------------------------------------------------------
88
88
  const intrinsicErrors = await validateIbGibIntrinsically({ ibGib: keystoneIbGib });
89
89
  if (intrinsicErrors) {
90
- return this.error(422, 'Intrinsic keystone validation failed', { errors: intrinsicErrors });
90
+ return this.error(422, 'Intrinsic keystone validation failed (E: 76d388e198f23a87dd6596f59c36e826)', { errors: intrinsicErrors });
91
91
  }
92
92
 
93
93
  // ----------------------------------------------------------------
@@ -98,7 +98,7 @@ export class KeystoneGenesisHandler extends ServeGibHandlerBase<undefined, undef
98
98
  keystoneIbGib
99
99
  });
100
100
  if (keystoneErrors && keystoneErrors.length > 0) {
101
- return this.error(422, 'Keystone genesis validation failed', { errors: keystoneErrors });
101
+ return this.error(422, `Keystone genesis validation failed. Errors: ${keystoneErrors} (E: 8384285be7a8ab0d41cfd1df2e2aa826)`, { errors: keystoneErrors });
102
102
  }
103
103
 
104
104
  // ----------------------------------------------------------------
@@ -108,12 +108,12 @@ export class KeystoneGenesisHandler extends ServeGibHandlerBase<undefined, undef
108
108
  const { tjpGib, punctiliarHash } = getGibInfo({ ibGibAddr: addr });
109
109
  const domainGib = tjpGib || punctiliarHash;
110
110
  if (!domainGib) {
111
- return this.error(422, `Could not extract domain identifier from keystone address: ${addr}`);
111
+ return this.error(422, `Could not extract domain identifier from keystone address: ${addr} (E: 2758588a6d7cc77f078e97989feed326)`);
112
112
  }
113
113
 
114
114
  const domainRootPath = getDomainRootPath(domainGib, reqCtx.dataDir);
115
115
  if (existsSync(domainRootPath)) {
116
- return this.error(409, `Domain already exists for this keystone (tjpGib: ${domainGib}). Use PUT /api/keystone/evolve/:domainAddr to evolve.`);
116
+ return this.error(409, `Domain already exists for this keystone (tjpGib: ${domainGib}). Use PUT /api/keystone/evolve/:domainAddr to evolve. (E: 1c56c8885781c86df89cbdfc1b310626)`);
117
117
  }
118
118
 
119
119
  // ----------------------------------------------------------------