@elevasis/core 0.22.0 → 0.23.0

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 (112) hide show
  1. package/dist/index.d.ts +2330 -2391
  2. package/dist/index.js +2322 -1147
  3. package/dist/knowledge/index.d.ts +702 -1136
  4. package/dist/knowledge/index.js +9 -9
  5. package/dist/organization-model/index.d.ts +2330 -2391
  6. package/dist/organization-model/index.js +2322 -1147
  7. package/dist/test-utils/index.d.ts +703 -1106
  8. package/dist/test-utils/index.js +1735 -1089
  9. package/package.json +1 -1
  10. package/src/__tests__/template-core-compatibility.test.ts +11 -79
  11. package/src/_gen/__tests__/__snapshots__/contracts.md.snap +360 -98
  12. package/src/business/acquisition/api-schemas.test.ts +2 -2
  13. package/src/business/acquisition/api-schemas.ts +7 -9
  14. package/src/business/acquisition/build-templates.test.ts +4 -4
  15. package/src/business/acquisition/build-templates.ts +72 -30
  16. package/src/business/acquisition/crm-state-actions.test.ts +13 -11
  17. package/src/business/acquisition/types.ts +7 -3
  18. package/src/execution/engine/agent/core/types.ts +1 -1
  19. package/src/execution/engine/workflow/types.ts +2 -2
  20. package/src/knowledge/README.md +8 -7
  21. package/src/knowledge/__tests__/queries.test.ts +74 -73
  22. package/src/knowledge/format.ts +10 -9
  23. package/src/knowledge/index.ts +1 -1
  24. package/src/knowledge/published.ts +1 -1
  25. package/src/knowledge/queries.ts +26 -25
  26. package/src/organization-model/README.md +66 -26
  27. package/src/organization-model/__tests__/content-kinds-registry.test.ts +210 -0
  28. package/src/organization-model/__tests__/defaults.test.ts +72 -98
  29. package/src/organization-model/__tests__/domains/actions.test.ts +56 -0
  30. package/src/organization-model/__tests__/domains/customers.test.ts +299 -295
  31. package/src/organization-model/__tests__/domains/entities.test.ts +56 -0
  32. package/src/organization-model/__tests__/domains/goals.test.ts +493 -479
  33. package/src/organization-model/__tests__/domains/identity.test.ts +280 -279
  34. package/src/organization-model/__tests__/domains/navigation.test.ts +268 -212
  35. package/src/organization-model/__tests__/domains/offerings.test.ts +414 -419
  36. package/src/organization-model/__tests__/domains/policies.test.ts +323 -0
  37. package/src/organization-model/__tests__/domains/resource-mappings.test.ts +271 -271
  38. package/src/organization-model/__tests__/domains/resources.test.ts +159 -37
  39. package/src/organization-model/__tests__/domains/roles.test.ts +147 -86
  40. package/src/organization-model/__tests__/domains/statuses.test.ts +246 -243
  41. package/src/organization-model/__tests__/domains/systems.test.ts +67 -51
  42. package/src/organization-model/__tests__/flatten-additive-merge.test.ts +361 -0
  43. package/src/organization-model/__tests__/foundation.test.ts +74 -102
  44. package/src/organization-model/__tests__/get-resources-for-system.test.ts +144 -0
  45. package/src/organization-model/__tests__/graph.test.ts +899 -71
  46. package/src/organization-model/__tests__/knowledge.test.ts +173 -52
  47. package/src/organization-model/__tests__/lookup-helpers.test.ts +438 -0
  48. package/src/organization-model/__tests__/migration-helpers.test.ts +591 -0
  49. package/src/organization-model/__tests__/prospecting-ssot.test.ts +36 -27
  50. package/src/organization-model/__tests__/recursive-system-schema.test.ts +520 -0
  51. package/src/organization-model/__tests__/resolve.test.ts +174 -23
  52. package/src/organization-model/__tests__/schema.test.ts +291 -114
  53. package/src/organization-model/__tests__/surface-projection.test.ts +207 -97
  54. package/src/organization-model/catalogs/lead-gen.ts +144 -0
  55. package/src/organization-model/content-kinds/config.ts +36 -0
  56. package/src/organization-model/content-kinds/index.ts +74 -0
  57. package/src/organization-model/content-kinds/pipeline.ts +68 -0
  58. package/src/organization-model/content-kinds/registry.ts +44 -0
  59. package/src/organization-model/content-kinds/status.ts +71 -0
  60. package/src/organization-model/content-kinds/template.ts +83 -0
  61. package/src/organization-model/content-kinds/types.ts +117 -0
  62. package/src/organization-model/contracts.ts +13 -3
  63. package/src/organization-model/defaults.ts +488 -96
  64. package/src/organization-model/domains/actions.ts +239 -0
  65. package/src/organization-model/domains/customers.ts +78 -75
  66. package/src/organization-model/domains/entities.ts +144 -0
  67. package/src/organization-model/domains/goals.ts +83 -80
  68. package/src/organization-model/domains/knowledge.ts +74 -16
  69. package/src/organization-model/domains/navigation.ts +107 -384
  70. package/src/organization-model/domains/offerings.ts +71 -66
  71. package/src/organization-model/domains/policies.ts +102 -0
  72. package/src/organization-model/domains/projects.ts +14 -48
  73. package/src/organization-model/domains/prospecting.ts +62 -181
  74. package/src/organization-model/domains/resources.ts +81 -24
  75. package/src/organization-model/domains/roles.ts +13 -10
  76. package/src/organization-model/domains/sales.ts +10 -219
  77. package/src/organization-model/domains/shared.ts +57 -57
  78. package/src/organization-model/domains/statuses.ts +339 -130
  79. package/src/organization-model/domains/systems.ts +186 -29
  80. package/src/organization-model/foundation.ts +54 -67
  81. package/src/organization-model/graph/build.ts +682 -54
  82. package/src/organization-model/graph/link.ts +1 -1
  83. package/src/organization-model/graph/schema.ts +24 -9
  84. package/src/organization-model/graph/types.ts +20 -7
  85. package/src/organization-model/helpers.ts +231 -26
  86. package/src/organization-model/index.ts +116 -5
  87. package/src/organization-model/migration-helpers.ts +249 -0
  88. package/src/organization-model/organization-graph.mdx +16 -15
  89. package/src/organization-model/organization-model.mdx +89 -41
  90. package/src/organization-model/published.ts +120 -18
  91. package/src/organization-model/resolve.ts +117 -54
  92. package/src/organization-model/schema.ts +561 -140
  93. package/src/organization-model/surface-projection.ts +116 -122
  94. package/src/organization-model/types.ts +102 -21
  95. package/src/platform/constants/versions.ts +1 -1
  96. package/src/platform/registry/__tests__/command-view.test.ts +6 -8
  97. package/src/platform/registry/__tests__/resource-link.test.ts +13 -8
  98. package/src/platform/registry/__tests__/resource-registry.integration.test.ts +16 -31
  99. package/src/platform/registry/__tests__/resource-registry.nested-systems.test.ts +245 -0
  100. package/src/platform/registry/__tests__/resource-registry.test.ts +9 -7
  101. package/src/platform/registry/__tests__/validation.test.ts +15 -11
  102. package/src/platform/registry/resource-registry.ts +20 -8
  103. package/src/platform/registry/serialization.ts +7 -7
  104. package/src/platform/registry/types.ts +3 -3
  105. package/src/platform/registry/validation.ts +17 -15
  106. package/src/reference/_generated/contracts.md +362 -99
  107. package/src/reference/glossary.md +18 -18
  108. package/src/supabase/database.types.ts +60 -0
  109. package/src/test-utils/test-utils.test.ts +1 -6
  110. package/src/organization-model/__tests__/domains/operations.test.ts +0 -203
  111. package/src/organization-model/domains/features.ts +0 -31
  112. package/src/organization-model/domains/operations.ts +0 -85
@@ -3,7 +3,9 @@ import {
3
3
  OrgKnowledgeNodeSchema,
4
4
  OrgKnowledgeKindSchema,
5
5
  KnowledgeDomainSchema,
6
- KnowledgeLinkSchema
6
+ KnowledgeLinkSchema,
7
+ KnowledgeTargetKindSchema,
8
+ KnowledgeTargetRefSchema
7
9
  } from '../domains/knowledge'
8
10
  import { OrganizationGraphEdgeKindSchema } from '../graph/schema'
9
11
  import { buildOrganizationGraph } from '../graph/build'
@@ -101,6 +103,24 @@ describe('OrgKnowledgeNodeSchema', () => {
101
103
 
102
104
  expect(result.success).toBe(false)
103
105
  })
106
+
107
+ it('accepts an optional externalUrl', () => {
108
+ const node = OrgKnowledgeNodeSchema.parse({
109
+ ...makeNode('reference'),
110
+ externalUrl: 'https://docs.elevasis.com/technical/architecture'
111
+ })
112
+
113
+ expect(node.externalUrl).toBe('https://docs.elevasis.com/technical/architecture')
114
+ })
115
+
116
+ it('rejects an invalid externalUrl', () => {
117
+ const result = OrgKnowledgeNodeSchema.safeParse({
118
+ ...makeNode('reference'),
119
+ externalUrl: 'not-a-url'
120
+ })
121
+
122
+ expect(result.success).toBe(false)
123
+ })
104
124
  })
105
125
 
106
126
  describe('resolveOrganizationModel with knowledge owner roles', () => {
@@ -117,8 +137,9 @@ describe('resolveOrganizationModel with knowledge owner roles', () => {
117
137
  it('passes when ownerIds reference declared role ids', () => {
118
138
  expect(() =>
119
139
  resolveOrganizationModel({
120
- roles: { roles: [{ id: 'role.ops-lead', title: 'Ops Lead' }] },
121
- knowledge: { nodes: [node] }
140
+ roles: { 'role.ops-lead': { id: 'role.ops-lead', order: 10, title: 'Ops Lead' } },
141
+ // Phase 4: knowledge is a flat Record<id, OrgKnowledgeNode>
142
+ knowledge: { 'knowledge.test-owner': node }
122
143
  })
123
144
  ).not.toThrow()
124
145
  })
@@ -126,7 +147,7 @@ describe('resolveOrganizationModel with knowledge owner roles', () => {
126
147
  it('throws when ownerIds reference unknown role ids', () => {
127
148
  expect(() =>
128
149
  resolveOrganizationModel({
129
- knowledge: { nodes: [node] }
150
+ knowledge: { 'knowledge.test-owner': node }
130
151
  })
131
152
  ).toThrow(/unknown owner role/)
132
153
  })
@@ -160,60 +181,79 @@ describe('OrganizationGraphEdgeKindSchema', () => {
160
181
  })
161
182
 
162
183
  // ---------------------------------------------------------------------------
163
- // DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE — post Wave 2a: nodes is empty array
184
+ // DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE — Phase 4: flat Record<id, OrgKnowledgeNode> (D3).
185
+ // The wrapper shape { version, lastModified, nodes[] } was removed; versioning
186
+ // is in domainMetadata.knowledge. The default is an empty map {}.
164
187
  // ---------------------------------------------------------------------------
165
188
 
166
189
  describe('DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE', () => {
167
- it('has an empty nodes array after Wave 2a pilot literal removal', () => {
168
- expect(DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE.nodes).toEqual([])
190
+ it('is an empty object (flat map with no pre-seeded nodes)', () => {
191
+ expect(DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE).toEqual({})
169
192
  })
170
193
 
171
194
  it('passes KnowledgeDomainSchema.parse without throwing', () => {
172
195
  expect(() => KnowledgeDomainSchema.parse(DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE)).not.toThrow()
173
196
  })
197
+
198
+ it('does not have a .nodes array (wrapper shape was removed in Phase 4)', () => {
199
+ expect(DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE).not.toHaveProperty('nodes')
200
+ })
201
+
202
+ it('does not have a .version field (moved to domainMetadata.knowledge)', () => {
203
+ expect(DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE).not.toHaveProperty('version')
204
+ })
174
205
  })
175
206
 
176
207
  // ---------------------------------------------------------------------------
177
208
  // buildOrganizationGraph — knowledge nodes + governs edges
178
- // Synthetic OM used so tests are independent of DEFAULT_ORGANIZATION_MODEL
179
- // knowledge nodes (empty after Wave 2a, Decision 2-B).
209
+ // Synthetic OM authored via flat Record<id, OrgKnowledgeNode> per Phase 4 schema.
180
210
  // ---------------------------------------------------------------------------
181
211
 
212
+ // Phase 4: knowledge is a flat Record<id, OrgKnowledgeNode> — no .nodes array wrapper.
182
213
  const SYNTHETIC_OM: OrganizationModel = {
183
214
  ...DEFAULT_ORGANIZATION_MODEL,
215
+ systems: Object.fromEntries(
216
+ Object.entries(DEFAULT_ORGANIZATION_MODEL.systems).map(([key, system]) => [
217
+ key,
218
+ key === 'sales.crm' || key === 'sales.lead-gen'
219
+ ? { ...system, governedByKnowledge: ['knowledge.test-playbook-1'] }
220
+ : system
221
+ ])
222
+ ),
184
223
  knowledge: {
185
- nodes: [
186
- {
187
- id: 'knowledge.test-playbook-1',
188
- kind: 'playbook',
189
- title: 'Test Playbook',
190
- summary: 'Test playbook summary.',
191
- body: '## Overview\n\nContent.',
192
- links: [{ nodeId: 'feature:sales.crm' }, { nodeId: 'feature:sales.lead-gen' }],
193
- ownerIds: [],
194
- updatedAt: '2026-01-01'
195
- },
196
- {
197
- id: 'knowledge.test-strategy-1',
198
- kind: 'strategy',
199
- title: 'Test Strategy',
200
- summary: 'Test strategy summary.',
201
- body: '## Strategy\n\nContent.',
202
- links: [{ nodeId: 'feature:sales.lead-gen' }],
203
- ownerIds: [],
204
- updatedAt: '2026-01-02'
205
- },
206
- {
207
- id: 'knowledge.test-reference-1',
208
- kind: 'reference',
209
- title: 'Test Reference',
210
- summary: 'Test reference summary.',
211
- body: '## Reference\n\nContent.',
212
- links: [],
213
- ownerIds: [],
214
- updatedAt: '2026-01-03'
215
- }
216
- ]
224
+ 'knowledge.test-playbook-1': {
225
+ id: 'knowledge.test-playbook-1',
226
+ kind: 'playbook',
227
+ title: 'Test Playbook',
228
+ summary: 'Test playbook summary.',
229
+ body: '## Overview\n\nContent.',
230
+ links: [
231
+ { target: { kind: 'system', id: 'sales.crm' }, nodeId: 'system:sales.crm' },
232
+ { target: { kind: 'system', id: 'sales.lead-gen' }, nodeId: 'system:sales.lead-gen' }
233
+ ],
234
+ ownerIds: [],
235
+ updatedAt: '2026-01-01'
236
+ },
237
+ 'knowledge.test-strategy-1': {
238
+ id: 'knowledge.test-strategy-1',
239
+ kind: 'strategy',
240
+ title: 'Test Strategy',
241
+ summary: 'Test strategy summary.',
242
+ body: '## Strategy\n\nContent.',
243
+ links: [],
244
+ ownerIds: [],
245
+ updatedAt: '2026-01-02'
246
+ },
247
+ 'knowledge.test-reference-1': {
248
+ id: 'knowledge.test-reference-1',
249
+ kind: 'reference',
250
+ title: 'Test Reference',
251
+ summary: 'Test reference summary.',
252
+ body: '## Reference\n\nContent.',
253
+ links: [],
254
+ ownerIds: [],
255
+ updatedAt: '2026-01-03'
256
+ }
217
257
  }
218
258
  }
219
259
 
@@ -222,11 +262,11 @@ describe('buildOrganizationGraph with knowledge', () => {
222
262
 
223
263
  it('emits a knowledge node for each synthetic node', () => {
224
264
  const knowledgeNodes = graph.nodes.filter((n) => n.kind === 'knowledge')
225
- expect(knowledgeNodes.length).toBe(SYNTHETIC_OM.knowledge.nodes.length)
265
+ expect(knowledgeNodes.length).toBe(Object.keys(SYNTHETIC_OM.knowledge).length)
226
266
  })
227
267
 
228
268
  it('knowledge nodes carry sourceId matching the OM node id', () => {
229
- for (const omNode of SYNTHETIC_OM.knowledge.nodes) {
269
+ for (const omNode of Object.values(SYNTHETIC_OM.knowledge)) {
230
270
  const graphNode = graph.nodes.find((n) => n.sourceId === omNode.id)
231
271
  expect(graphNode).toBeDefined()
232
272
  expect(graphNode?.kind).toBe('knowledge')
@@ -236,12 +276,12 @@ describe('buildOrganizationGraph with knowledge', () => {
236
276
 
237
277
  it('emits governs edges for nodes that have links', () => {
238
278
  const governsEdges = graph.edges.filter((e) => e.kind === 'governs')
239
- const totalLinks = SYNTHETIC_OM.knowledge.nodes.reduce((sum, n) => sum + n.links.length, 0)
279
+ const totalLinks = Object.values(SYNTHETIC_OM.knowledge).reduce((sum, n) => sum + n.links.length, 0)
240
280
  expect(governsEdges.length).toBe(totalLinks)
241
281
  })
242
282
 
243
283
  it('links targetId resolves to an existing graph node id for at least one node', () => {
244
- const nodeWithLinks = SYNTHETIC_OM.knowledge.nodes.find((n) => n.links.length > 0)
284
+ const nodeWithLinks = Object.values(SYNTHETIC_OM.knowledge).find((n) => n.links.length > 0)
245
285
  expect(nodeWithLinks).toBeDefined()
246
286
 
247
287
  const graphNodeIds = new Set(graph.nodes.map((n) => n.id))
@@ -262,9 +302,22 @@ describe('buildOrganizationGraph with knowledge', () => {
262
302
  // ---------------------------------------------------------------------------
263
303
 
264
304
  describe('KnowledgeLinkSchema', () => {
265
- it('accepts a valid kind:dotted-path nodeId', () => {
266
- expect(() => KnowledgeLinkSchema.parse({ nodeId: 'feature:sales.crm' })).not.toThrow()
267
- expect(() => KnowledgeLinkSchema.parse({ nodeId: 'feature:sales.lead-gen' })).not.toThrow()
305
+ it('accepts and normalizes a canonical typed target', () => {
306
+ const link = KnowledgeLinkSchema.parse({ target: { kind: 'system', id: 'sales.crm' } })
307
+
308
+ expect(link).toEqual({
309
+ target: { kind: 'system', id: 'sales.crm' },
310
+ nodeId: 'system:sales.crm'
311
+ })
312
+ })
313
+
314
+ it('accepts and normalizes a legacy kind:dotted-path nodeId', () => {
315
+ const link = KnowledgeLinkSchema.parse({ nodeId: 'system:sales.lead-gen' })
316
+
317
+ expect(link).toEqual({
318
+ target: { kind: 'system', id: 'sales.lead-gen' },
319
+ nodeId: 'system:sales.lead-gen'
320
+ })
268
321
  })
269
322
 
270
323
  it('accepts resource: and knowledge: prefixed node IDs', () => {
@@ -272,8 +325,11 @@ describe('KnowledgeLinkSchema', () => {
272
325
  expect(() => KnowledgeLinkSchema.parse({ nodeId: 'knowledge:knowledge.test-doc' })).not.toThrow()
273
326
  })
274
327
 
328
+ it('accepts content-node: prefixed node IDs (D4 — KnowledgeTargetKindSchema includes content-node)', () => {
329
+ expect(() => KnowledgeLinkSchema.parse({ nodeId: 'content-node:sales.crm:default-pipeline' })).not.toThrow()
330
+ })
331
+
275
332
  it('rejects a bare dotted ID with no kind: prefix', () => {
276
- // NodeIdStringSchema requires kind:dotted-path format
277
333
  expect(KnowledgeLinkSchema.safeParse({ nodeId: 'sales.crm' }).success).toBe(false)
278
334
  })
279
335
 
@@ -282,8 +338,7 @@ describe('KnowledgeLinkSchema', () => {
282
338
  })
283
339
 
284
340
  it('rejects a nodeId with uppercase characters', () => {
285
- // NodeIdStringSchema regex requires lowercase
286
- expect(KnowledgeLinkSchema.safeParse({ nodeId: 'Feature:Sales.CRM' }).success).toBe(false)
341
+ expect(KnowledgeLinkSchema.safeParse({ nodeId: 'system:Sales.CRM' }).success).toBe(false)
287
342
  })
288
343
 
289
344
  it('rejects a link missing the nodeId field', () => {
@@ -295,6 +350,73 @@ describe('KnowledgeLinkSchema', () => {
295
350
  })
296
351
  })
297
352
 
353
+ describe('KnowledgeTargetRefSchema', () => {
354
+ it('accepts modeled target kinds', () => {
355
+ expect(KnowledgeTargetRefSchema.safeParse({ kind: 'system', id: 'sales.crm' }).success).toBe(true)
356
+ expect(KnowledgeTargetRefSchema.safeParse({ kind: 'customer-segment', id: 'customer.enterprise' }).success).toBe(
357
+ true
358
+ )
359
+ })
360
+
361
+ it('accepts content-node as a target kind (D4)', () => {
362
+ expect(KnowledgeTargetKindSchema.safeParse('content-node').success).toBe(true)
363
+ expect(KnowledgeTargetRefSchema.safeParse({ kind: 'content-node', id: 'sales.crm:default-pipeline' }).success).toBe(
364
+ true
365
+ )
366
+ })
367
+
368
+ it('rejects unknown target kinds', () => {
369
+ expect(KnowledgeTargetKindSchema.safeParse('integration').success).toBe(false)
370
+ expect(KnowledgeTargetRefSchema.safeParse({ kind: 'integration', id: 'hubspot' }).success).toBe(false)
371
+ })
372
+ })
373
+
374
+ // ---------------------------------------------------------------------------
375
+ // KnowledgeDomainSchema — flat Record shape (Phase 4 D3)
376
+ // ---------------------------------------------------------------------------
377
+
378
+ describe('KnowledgeDomainSchema — flat Record<id, OrgKnowledgeNode>', () => {
379
+ it('accepts an empty map', () => {
380
+ expect(KnowledgeDomainSchema.safeParse({}).success).toBe(true)
381
+ })
382
+
383
+ it('defaults to empty map when undefined', () => {
384
+ const result = KnowledgeDomainSchema.safeParse(undefined)
385
+ expect(result.success).toBe(true)
386
+ if (result.success) {
387
+ expect(result.data).toEqual({})
388
+ }
389
+ })
390
+
391
+ it('accepts a Record keyed by knowledge node ids', () => {
392
+ const result = KnowledgeDomainSchema.safeParse({
393
+ 'knowledge.my-playbook': {
394
+ id: 'knowledge.my-playbook',
395
+ kind: 'playbook',
396
+ title: 'My Playbook',
397
+ summary: 'A test playbook.',
398
+ body: '## Content',
399
+ links: [],
400
+ ownerIds: [],
401
+ updatedAt: '2026-05-01'
402
+ }
403
+ })
404
+ expect(result.success).toBe(true)
405
+ })
406
+
407
+ it('rejects the old wrapper shape { version, lastModified, nodes[] }', () => {
408
+ // The old wrapper-with-array shape does not parse as a Record<id, OrgKnowledgeNode>
409
+ const result = KnowledgeDomainSchema.safeParse({
410
+ version: 1,
411
+ lastModified: '2026-05-10',
412
+ nodes: []
413
+ })
414
+ // Each key ('version', 'lastModified', 'nodes') would be parsed as a knowledge node id,
415
+ // and the values are not valid OrgKnowledgeNodeSchema — so this should fail
416
+ expect(result.success).toBe(false)
417
+ })
418
+ })
419
+
298
420
  // ---------------------------------------------------------------------------
299
421
  // OrgKnowledgeNodeSchema — field length constraints
300
422
  // ---------------------------------------------------------------------------
@@ -347,7 +469,6 @@ describe('OrgKnowledgeNodeSchema length constraints', () => {
347
469
  })
348
470
 
349
471
  it('rejects id with uppercase characters', () => {
350
- // ModelIdSchema requires lowercase kebab/dot/underscore separated IDs
351
472
  const result = OrgKnowledgeNodeSchema.safeParse({ ...BASE, id: 'Knowledge.Test' })
352
473
  expect(result.success).toBe(false)
353
474
  })