@elevasis/core 0.23.0 → 0.24.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 (241) hide show
  1. package/dist/index.d.ts +1326 -552
  2. package/dist/index.js +869 -154
  3. package/dist/knowledge/index.d.ts +487 -209
  4. package/dist/knowledge/index.js +104 -1
  5. package/dist/organization-model/index.d.ts +1326 -552
  6. package/dist/organization-model/index.js +869 -154
  7. package/dist/test-utils/index.d.ts +357 -72
  8. package/dist/test-utils/index.js +795 -142
  9. package/package.json +5 -5
  10. package/src/README.md +14 -14
  11. package/src/__tests__/publish.test.ts +24 -24
  12. package/src/__tests__/template-core-compatibility.test.ts +9 -12
  13. package/src/_gen/__tests__/__snapshots__/contracts.md.snap +2102 -2096
  14. package/src/_gen/__tests__/scaffold-contracts.test.ts +30 -30
  15. package/src/auth/multi-tenancy/credentials/__tests__/encryption.test.ts +217 -217
  16. package/src/auth/multi-tenancy/credentials/server/encryption.ts +69 -69
  17. package/src/auth/multi-tenancy/credentials/server/kek-loader.ts +37 -37
  18. package/src/auth/multi-tenancy/index.ts +26 -26
  19. package/src/auth/multi-tenancy/invitations/api-schemas.ts +104 -104
  20. package/src/auth/multi-tenancy/memberships/api-schemas.ts +143 -143
  21. package/src/auth/multi-tenancy/memberships/index.ts +26 -26
  22. package/src/auth/multi-tenancy/memberships/membership.ts +130 -130
  23. package/src/auth/multi-tenancy/organizations/__tests__/api-schemas.test.ts +194 -194
  24. package/src/auth/multi-tenancy/organizations/api-schemas.ts +136 -136
  25. package/src/auth/multi-tenancy/permissions.test.ts +42 -42
  26. package/src/auth/multi-tenancy/permissions.ts +123 -123
  27. package/src/auth/multi-tenancy/role-management/api-schemas.ts +78 -78
  28. package/src/auth/multi-tenancy/role-management/index.ts +16 -16
  29. package/src/auth/multi-tenancy/theme-presets.ts +45 -45
  30. package/src/auth/multi-tenancy/types.ts +57 -57
  31. package/src/auth/multi-tenancy/users/api-schemas.ts +165 -165
  32. package/src/business/README.md +2 -2
  33. package/src/business/acquisition/activity-events.test.ts +250 -250
  34. package/src/business/acquisition/activity-events.ts +93 -93
  35. package/src/business/acquisition/api-schemas.test.ts +1883 -1843
  36. package/src/business/acquisition/api-schemas.ts +1492 -1497
  37. package/src/business/acquisition/build-templates.test.ts +240 -240
  38. package/src/business/acquisition/build-templates.ts +98 -98
  39. package/src/business/acquisition/crm-next-action.test.ts +262 -262
  40. package/src/business/acquisition/crm-next-action.ts +220 -220
  41. package/src/business/acquisition/crm-priority.test.ts +216 -216
  42. package/src/business/acquisition/crm-priority.ts +349 -349
  43. package/src/business/acquisition/crm-state-actions.test.ts +153 -153
  44. package/src/business/acquisition/deal-ownership.test.ts +351 -351
  45. package/src/business/acquisition/deal-ownership.ts +120 -120
  46. package/src/business/acquisition/derive-actions.test.ts +129 -104
  47. package/src/business/acquisition/derive-actions.ts +74 -84
  48. package/src/business/acquisition/index.ts +171 -170
  49. package/src/business/acquisition/ontology-validation.ts +309 -0
  50. package/src/business/acquisition/stateful.ts +30 -30
  51. package/src/business/acquisition/types.ts +396 -396
  52. package/src/business/clients/api-schemas.test.ts +115 -115
  53. package/src/business/clients/api-schemas.ts +158 -158
  54. package/src/business/clients/index.ts +1 -1
  55. package/src/business/crm/api-schemas.ts +40 -40
  56. package/src/business/crm/index.ts +1 -1
  57. package/src/business/deals/api-schemas.ts +87 -87
  58. package/src/business/deals/index.ts +1 -1
  59. package/src/business/index.ts +5 -5
  60. package/src/business/projects/types.ts +144 -144
  61. package/src/commands/queue/types/task.ts +15 -15
  62. package/src/execution/core/runner-types.ts +61 -61
  63. package/src/execution/core/sse-executions.ts +7 -7
  64. package/src/execution/engine/__tests__/fixtures/test-agents.ts +10 -10
  65. package/src/execution/engine/agent/core/__tests__/agent.test.ts +16 -16
  66. package/src/execution/engine/agent/core/__tests__/error-passthrough.test.ts +4 -4
  67. package/src/execution/engine/agent/core/types.ts +25 -25
  68. package/src/execution/engine/agent/index.ts +6 -6
  69. package/src/execution/engine/agent/reasoning/__tests__/request-builder.test.ts +24 -24
  70. package/src/execution/engine/index.ts +443 -443
  71. package/src/execution/engine/tools/integration/server/adapters/apify/__tests__/apify-run-actor.integration.test.ts +298 -298
  72. package/src/execution/engine/tools/integration/server/adapters/apify/apify-adapter.test.ts +55 -55
  73. package/src/execution/engine/tools/integration/server/adapters/apify/apify-adapter.ts +107 -107
  74. package/src/execution/engine/tools/integration/server/adapters/apollo/apollo-adapter.test.ts +48 -48
  75. package/src/execution/engine/tools/integration/server/adapters/apollo/apollo-adapter.ts +99 -99
  76. package/src/execution/engine/tools/integration/server/adapters/apollo/index.ts +1 -1
  77. package/src/execution/engine/tools/integration/server/adapters/attio/__tests__/attio-crud.integration.test.ts +363 -363
  78. package/src/execution/engine/tools/integration/server/adapters/attio/fetch/get-record/index.test.ts +162 -162
  79. package/src/execution/engine/tools/integration/server/adapters/attio/fetch/list-records/index.test.ts +316 -316
  80. package/src/execution/engine/tools/integration/server/adapters/clickup/clickup-adapter.test.ts +18 -18
  81. package/src/execution/engine/tools/integration/server/adapters/clickup/clickup-adapter.ts +194 -194
  82. package/src/execution/engine/tools/integration/server/adapters/clickup/index.ts +7 -7
  83. package/src/execution/engine/tools/integration/server/adapters/gmail/gmail-adapter.ts +204 -204
  84. package/src/execution/engine/tools/integration/server/adapters/gmail/gmail-tools.ts +105 -105
  85. package/src/execution/engine/tools/integration/server/adapters/google-calendar/google-calendar-adapter.ts +428 -428
  86. package/src/execution/engine/tools/integration/server/adapters/google-calendar/index.ts +2 -2
  87. package/src/execution/engine/tools/integration/server/adapters/google-sheets/__tests__/google-sheets.integration.test.ts +261 -261
  88. package/src/execution/engine/tools/integration/server/adapters/instantly/instantly-tools.ts +1474 -1474
  89. package/src/execution/engine/tools/integration/server/adapters/millionverifier/millionverifier-tools.ts +103 -103
  90. package/src/execution/engine/tools/integration/server/adapters/resend/fetch/send-email/index.test.ts +88 -88
  91. package/src/execution/engine/tools/integration/server/adapters/resend/fetch/send-email/index.ts +141 -141
  92. package/src/execution/engine/tools/integration/server/adapters/resend/fetch/utils/types.ts +76 -76
  93. package/src/execution/engine/tools/integration/server/adapters/signature-api/signature-api-tools.ts +182 -182
  94. package/src/execution/engine/tools/integration/server/adapters/stripe/stripe-tools.ts +310 -310
  95. package/src/execution/engine/tools/integration/service.test.ts +239 -239
  96. package/src/execution/engine/tools/integration/service.ts +172 -172
  97. package/src/execution/engine/tools/integration/tool.ts +255 -255
  98. package/src/execution/engine/tools/lead-service-types.ts +1005 -1005
  99. package/src/execution/engine/tools/messages.ts +43 -43
  100. package/src/execution/engine/tools/platform/acquisition/company-tools.ts +7 -7
  101. package/src/execution/engine/tools/platform/acquisition/contact-tools.ts +6 -6
  102. package/src/execution/engine/tools/platform/acquisition/list-tools.ts +6 -6
  103. package/src/execution/engine/tools/platform/acquisition/types.ts +280 -280
  104. package/src/execution/engine/tools/platform/email/types.ts +97 -97
  105. package/src/execution/engine/tools/registry.ts +704 -704
  106. package/src/execution/engine/tools/tool-maps.ts +831 -831
  107. package/src/execution/engine/tools/types.ts +234 -234
  108. package/src/execution/engine/workflow/types.ts +202 -202
  109. package/src/execution/external/__tests__/api-schemas.test.ts +127 -127
  110. package/src/execution/external/api-schemas.ts +40 -40
  111. package/src/execution/external/index.ts +1 -1
  112. package/src/index.ts +18 -18
  113. package/src/integrations/credentials/__tests__/api-schemas.test.ts +420 -420
  114. package/src/integrations/credentials/api-schemas.ts +146 -146
  115. package/src/integrations/credentials/schemas.ts +200 -200
  116. package/src/integrations/oauth/__tests__/provider-registry.test.ts +7 -7
  117. package/src/integrations/oauth/provider-registry.ts +74 -74
  118. package/src/integrations/oauth/server/credentials.ts +43 -43
  119. package/src/integrations/webhook-endpoints/__tests__/api-schemas.test.ts +327 -327
  120. package/src/integrations/webhook-endpoints/api-schemas.ts +103 -103
  121. package/src/integrations/webhook-endpoints/types.ts +58 -58
  122. package/src/knowledge/README.md +32 -32
  123. package/src/knowledge/__tests__/queries.test.ts +626 -535
  124. package/src/knowledge/format.ts +99 -99
  125. package/src/knowledge/index.ts +5 -5
  126. package/src/knowledge/published.ts +5 -5
  127. package/src/knowledge/queries.ts +269 -218
  128. package/src/operations/activities/api-schemas.ts +80 -80
  129. package/src/operations/activities/types.ts +64 -64
  130. package/src/organization-model/README.md +149 -149
  131. package/src/organization-model/__tests__/content-kinds-registry.test.ts +210 -210
  132. package/src/organization-model/__tests__/defaults.test.ts +168 -168
  133. package/src/organization-model/__tests__/domains/actions.test.ts +78 -56
  134. package/src/organization-model/__tests__/domains/customers.test.ts +299 -299
  135. package/src/organization-model/__tests__/domains/entities.test.ts +56 -56
  136. package/src/organization-model/__tests__/domains/goals.test.ts +493 -493
  137. package/src/organization-model/__tests__/domains/identity.test.ts +280 -280
  138. package/src/organization-model/__tests__/domains/navigation.test.ts +268 -268
  139. package/src/organization-model/__tests__/domains/offerings.test.ts +414 -414
  140. package/src/organization-model/__tests__/domains/policies.test.ts +323 -323
  141. package/src/organization-model/__tests__/domains/resource-mappings.test.ts +293 -293
  142. package/src/organization-model/__tests__/domains/resources.test.ts +382 -283
  143. package/src/organization-model/__tests__/domains/roles.test.ts +463 -463
  144. package/src/organization-model/__tests__/domains/statuses.test.ts +246 -246
  145. package/src/organization-model/__tests__/domains/systems.test.ts +209 -209
  146. package/src/organization-model/__tests__/flatten-additive-merge.test.ts +362 -361
  147. package/src/organization-model/__tests__/foundation.test.ts +77 -77
  148. package/src/organization-model/__tests__/get-resources-for-system.test.ts +144 -144
  149. package/src/organization-model/__tests__/graph.test.ts +1246 -887
  150. package/src/organization-model/__tests__/icons.test.ts +10 -1
  151. package/src/organization-model/__tests__/knowledge.test.ts +251 -15
  152. package/src/organization-model/__tests__/lookup-helpers.test.ts +438 -438
  153. package/src/organization-model/__tests__/migration-helpers.test.ts +591 -591
  154. package/src/organization-model/__tests__/prospecting-ssot.test.ts +103 -103
  155. package/src/organization-model/__tests__/recursive-system-schema.test.ts +535 -506
  156. package/src/organization-model/__tests__/resolve.test.ts +274 -164
  157. package/src/organization-model/__tests__/schema.test.ts +834 -301
  158. package/src/organization-model/__tests__/surface-projection.test.ts +284 -284
  159. package/src/organization-model/catalogs/lead-gen.ts +144 -144
  160. package/src/organization-model/content-kinds/config.ts +36 -36
  161. package/src/organization-model/content-kinds/index.ts +76 -72
  162. package/src/organization-model/content-kinds/pipeline.ts +68 -68
  163. package/src/organization-model/content-kinds/registry.ts +44 -44
  164. package/src/organization-model/content-kinds/status.ts +71 -71
  165. package/src/organization-model/content-kinds/template.ts +83 -83
  166. package/src/organization-model/content-kinds/types.ts +117 -117
  167. package/src/organization-model/contracts.ts +27 -27
  168. package/src/organization-model/defaults.ts +40 -50
  169. package/src/organization-model/domains/actions.ts +333 -239
  170. package/src/organization-model/domains/customers.ts +78 -78
  171. package/src/organization-model/domains/entities.ts +144 -144
  172. package/src/organization-model/domains/goals.ts +83 -83
  173. package/src/organization-model/domains/knowledge.ts +117 -101
  174. package/src/organization-model/domains/navigation.ts +139 -139
  175. package/src/organization-model/domains/offerings.ts +71 -71
  176. package/src/organization-model/domains/policies.ts +102 -102
  177. package/src/organization-model/domains/projects.ts +14 -14
  178. package/src/organization-model/domains/prospecting.ts +395 -395
  179. package/src/organization-model/domains/resources.ts +167 -132
  180. package/src/organization-model/domains/roles.ts +96 -96
  181. package/src/organization-model/domains/sales.test.ts +218 -218
  182. package/src/organization-model/domains/sales.ts +380 -380
  183. package/src/organization-model/domains/shared.ts +63 -63
  184. package/src/organization-model/domains/statuses.ts +339 -339
  185. package/src/organization-model/domains/systems.ts +217 -172
  186. package/src/organization-model/foundation.ts +75 -75
  187. package/src/organization-model/graph/build.ts +1016 -888
  188. package/src/organization-model/graph/index.ts +4 -4
  189. package/src/organization-model/graph/link.ts +10 -10
  190. package/src/organization-model/graph/schema.ts +76 -70
  191. package/src/organization-model/graph/types.ts +73 -67
  192. package/src/organization-model/helpers.ts +289 -241
  193. package/src/organization-model/icons.ts +78 -66
  194. package/src/organization-model/index.ts +130 -128
  195. package/src/organization-model/migration-helpers.ts +247 -244
  196. package/src/organization-model/ontology.ts +661 -0
  197. package/src/organization-model/organization-graph.mdx +110 -90
  198. package/src/organization-model/organization-model.mdx +226 -219
  199. package/src/organization-model/published.ts +289 -235
  200. package/src/organization-model/resolve.ts +146 -91
  201. package/src/organization-model/schema.ts +790 -671
  202. package/src/organization-model/surface-projection.ts +212 -212
  203. package/src/organization-model/types.ts +177 -167
  204. package/src/platform/api/types.ts +38 -38
  205. package/src/platform/constants/versions.ts +3 -3
  206. package/src/platform/index.ts +23 -23
  207. package/src/platform/registry/__tests__/command-view.test.ts +10 -10
  208. package/src/platform/registry/__tests__/resource-link.test.ts +35 -35
  209. package/src/platform/registry/__tests__/resource-registry.integration.test.ts +20 -20
  210. package/src/platform/registry/__tests__/resource-registry.nested-systems.test.ts +245 -245
  211. package/src/platform/registry/__tests__/resource-registry.test.ts +2053 -2053
  212. package/src/platform/registry/__tests__/validation.test.ts +1347 -1347
  213. package/src/platform/registry/command-view.ts +10 -10
  214. package/src/platform/registry/index.ts +103 -103
  215. package/src/platform/registry/resource-link.ts +32 -32
  216. package/src/platform/registry/resource-registry.ts +890 -890
  217. package/src/platform/registry/serialization.ts +295 -295
  218. package/src/platform/registry/serialized-types.ts +166 -166
  219. package/src/platform/registry/stats-types.ts +68 -68
  220. package/src/platform/registry/types.ts +425 -425
  221. package/src/platform/registry/validation.ts +745 -745
  222. package/src/platform/utils/__tests__/validation.test.ts +1084 -1084
  223. package/src/platform/utils/validation.ts +425 -425
  224. package/src/projects/api-schemas.test.ts +39 -39
  225. package/src/projects/api-schemas.ts +291 -291
  226. package/src/reference/_generated/contracts.md +2101 -2096
  227. package/src/reference/glossary.md +76 -76
  228. package/src/scaffold-registry/__tests__/index.test.ts +206 -206
  229. package/src/scaffold-registry/__tests__/schema.test.ts +166 -166
  230. package/src/scaffold-registry/index.ts +392 -392
  231. package/src/scaffold-registry/schema.ts +243 -243
  232. package/src/server.ts +289 -289
  233. package/src/supabase/database.types.ts +3153 -3153
  234. package/src/test-utils/README.md +37 -37
  235. package/src/test-utils/entities.ts +108 -108
  236. package/src/test-utils/fixtures/memberships.ts +82 -82
  237. package/src/test-utils/index.ts +12 -12
  238. package/src/test-utils/organization-model.ts +65 -65
  239. package/src/test-utils/published.ts +6 -6
  240. package/src/test-utils/rls/RLSTestContext.ts +588 -588
  241. package/src/test-utils/test-utils.test.ts +44 -44
@@ -20,7 +20,16 @@ describe('OrganizationModelIconTokenSchema', () => {
20
20
  })
21
21
 
22
22
  it('rejects random strings outside the built-in and custom namespaces', () => {
23
- for (const token of ['crm', 'lead-gen', 'settings', 'random.icon', 'custom.', 'custom.Bad']) {
23
+ for (const token of [
24
+ 'nav.crm',
25
+ 'feature.sales',
26
+ 'surface.dashboard',
27
+ 'action.approve',
28
+ 'status.success',
29
+ 'random.icon',
30
+ 'custom.',
31
+ 'custom.Bad'
32
+ ]) {
24
33
  expect(OrganizationModelIconTokenSchema.safeParse(token).success).toBe(false)
25
34
  }
26
35
  })
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { describe, expect, it } from 'vitest'
2
2
  import {
3
3
  OrgKnowledgeNodeSchema,
4
4
  OrgKnowledgeKindSchema,
@@ -11,10 +11,12 @@ import { OrganizationGraphEdgeKindSchema } from '../graph/schema'
11
11
  import { buildOrganizationGraph } from '../graph/build'
12
12
  import { DEFAULT_ORGANIZATION_MODEL, DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE } from '../defaults'
13
13
  import { resolveOrganizationModel } from '../resolve'
14
+ import { compileOrganizationOntology } from '../ontology'
15
+ import { byOntology, governedBy, parsePath } from '../../knowledge/queries'
14
16
  import type { OrganizationModel } from '../types'
15
17
 
16
18
  // ---------------------------------------------------------------------------
17
- // OrgKnowledgeNodeSchema shape and validation
19
+ // OrgKnowledgeNodeSchema — shape and validation
18
20
  // ---------------------------------------------------------------------------
19
21
 
20
22
  describe('OrgKnowledgeNodeSchema', () => {
@@ -89,10 +91,10 @@ describe('OrgKnowledgeNodeSchema', () => {
89
91
  it('accepts an optional semantic icon token', () => {
90
92
  const node = OrgKnowledgeNodeSchema.parse({
91
93
  ...makeNode('playbook'),
92
- icon: 'knowledge.playbook'
94
+ icon: 'playbook'
93
95
  })
94
96
 
95
- expect(node.icon).toBe('knowledge.playbook')
97
+ expect(node.icon).toBe('playbook')
96
98
  })
97
99
 
98
100
  it('rejects an unknown icon token', () => {
@@ -121,6 +123,15 @@ describe('OrgKnowledgeNodeSchema', () => {
121
123
 
122
124
  expect(result.success).toBe(false)
123
125
  })
126
+
127
+ it('accepts an optional generated sourceFilePath', () => {
128
+ const node = OrgKnowledgeNodeSchema.parse({
129
+ ...makeNode('reference'),
130
+ sourceFilePath: 'packages/elevasis-core/src/knowledge/nodes/platform/reference.mdx'
131
+ })
132
+
133
+ expect(node.sourceFilePath).toBe('packages/elevasis-core/src/knowledge/nodes/platform/reference.mdx')
134
+ })
124
135
  })
125
136
 
126
137
  describe('resolveOrganizationModel with knowledge owner roles', () => {
@@ -153,8 +164,117 @@ describe('resolveOrganizationModel with knowledge owner roles', () => {
153
164
  })
154
165
  })
155
166
 
167
+ describe('resolveOrganizationModel with ontology knowledge targets', () => {
168
+ it('accepts knowledge links that directly target compiled ontology records', () => {
169
+ expect(() =>
170
+ resolveOrganizationModel({
171
+ systems: {
172
+ 'sales.crm': {
173
+ id: 'sales.crm',
174
+ order: 10,
175
+ label: 'CRM',
176
+ enabled: true,
177
+ ontology: {
178
+ objectTypes: {
179
+ 'sales.crm:object/deal': {
180
+ id: 'sales.crm:object/deal',
181
+ label: 'Deal'
182
+ }
183
+ }
184
+ }
185
+ }
186
+ },
187
+ knowledge: {
188
+ 'knowledge.deal-policy': {
189
+ id: 'knowledge.deal-policy',
190
+ kind: 'reference',
191
+ title: 'Deal Policy',
192
+ summary: 'How deal records are governed.',
193
+ body: 'Deal policy.',
194
+ links: [{ target: { kind: 'ontology', id: 'sales.crm:object/deal' } }],
195
+ updatedAt: '2026-05-14'
196
+ }
197
+ }
198
+ })
199
+ ).not.toThrow()
200
+ })
201
+
202
+ it('rejects knowledge links to unknown ontology records', () => {
203
+ expect(() =>
204
+ resolveOrganizationModel({
205
+ knowledge: {
206
+ 'knowledge.missing-ontology': {
207
+ id: 'knowledge.missing-ontology',
208
+ kind: 'reference',
209
+ title: 'Missing Ontology',
210
+ summary: 'References a missing ontology record.',
211
+ body: 'Missing.',
212
+ links: [{ target: { kind: 'ontology', id: 'sales.crm:object/missing' } }],
213
+ updatedAt: '2026-05-14'
214
+ }
215
+ }
216
+ })
217
+ ).toThrow(/unknown ontology target/)
218
+ })
219
+
220
+ it('compiles authored ontology targets without requiring legacy provenance fields', () => {
221
+ const model = resolveOrganizationModel({
222
+ systems: {
223
+ 'sales.crm': {
224
+ id: 'sales.crm',
225
+ order: 10,
226
+ label: 'CRM',
227
+ enabled: true,
228
+ ontology: {
229
+ objectTypes: {
230
+ 'sales.crm:object/deal': {
231
+ id: 'sales.crm:object/deal',
232
+ label: 'Deal'
233
+ }
234
+ },
235
+ actionTypes: {
236
+ 'sales.crm:action/update-deal': {
237
+ id: 'sales.crm:action/update-deal',
238
+ label: 'Update Deal',
239
+ actsOn: ['sales.crm:object/deal']
240
+ }
241
+ },
242
+ catalogTypes: {
243
+ 'sales.crm:catalog/pipeline': {
244
+ id: 'sales.crm:catalog/pipeline',
245
+ label: 'Pipeline',
246
+ appliesTo: 'sales.crm:object/deal'
247
+ }
248
+ }
249
+ }
250
+ }
251
+ },
252
+ knowledge: {
253
+ 'knowledge.pipeline-policy': {
254
+ id: 'knowledge.pipeline-policy',
255
+ kind: 'reference',
256
+ title: 'Pipeline Policy',
257
+ summary: 'How pipeline ontology is governed.',
258
+ body: 'Pipeline policy.',
259
+ links: [{ target: { kind: 'ontology', id: 'sales.crm:catalog/pipeline' } }],
260
+ updatedAt: '2026-05-14'
261
+ }
262
+ }
263
+ })
264
+ const compiled = compileOrganizationOntology(model)
265
+
266
+ expect(compiled.diagnostics).toEqual([])
267
+ expect(compiled.ontology.objectTypes['sales.crm:object/deal']).not.toHaveProperty('legacyEntityId')
268
+ expect(compiled.ontology.actionTypes['sales.crm:action/update-deal']).not.toHaveProperty('legacyActionId')
269
+ expect(compiled.ontology.catalogTypes['sales.crm:catalog/pipeline']).not.toHaveProperty('legacyContentId')
270
+ expect(model.knowledge['knowledge.pipeline-policy']?.links[0]?.nodeId).toBe(
271
+ 'ontology:sales.crm:catalog/pipeline'
272
+ )
273
+ })
274
+ })
275
+
156
276
  // ---------------------------------------------------------------------------
157
- // OrgKnowledgeKindSchema enum shape
277
+ // OrgKnowledgeKindSchema — enum shape
158
278
  // ---------------------------------------------------------------------------
159
279
 
160
280
  describe('OrgKnowledgeKindSchema', () => {
@@ -171,7 +291,7 @@ describe('OrgKnowledgeKindSchema', () => {
171
291
  })
172
292
 
173
293
  // ---------------------------------------------------------------------------
174
- // OrganizationGraphEdgeKindSchema governs edge is present
294
+ // OrganizationGraphEdgeKindSchema — governs edge is present
175
295
  // ---------------------------------------------------------------------------
176
296
 
177
297
  describe('OrganizationGraphEdgeKindSchema', () => {
@@ -181,7 +301,7 @@ describe('OrganizationGraphEdgeKindSchema', () => {
181
301
  })
182
302
 
183
303
  // ---------------------------------------------------------------------------
184
- // DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE Phase 4: flat Record<id, OrgKnowledgeNode> (D3).
304
+ // DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE — Phase 4: flat Record<id, OrgKnowledgeNode> (D3).
185
305
  // The wrapper shape { version, lastModified, nodes[] } was removed; versioning
186
306
  // is in domainMetadata.knowledge. The default is an empty map {}.
187
307
  // ---------------------------------------------------------------------------
@@ -205,11 +325,11 @@ describe('DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE', () => {
205
325
  })
206
326
 
207
327
  // ---------------------------------------------------------------------------
208
- // buildOrganizationGraph knowledge nodes + governs edges
328
+ // buildOrganizationGraph — knowledge nodes + governs edges
209
329
  // Synthetic OM authored via flat Record<id, OrgKnowledgeNode> per Phase 4 schema.
210
330
  // ---------------------------------------------------------------------------
211
331
 
212
- // Phase 4: knowledge is a flat Record<id, OrgKnowledgeNode> no .nodes array wrapper.
332
+ // Phase 4: knowledge is a flat Record<id, OrgKnowledgeNode> — no .nodes array wrapper.
213
333
  const SYNTHETIC_OM: OrganizationModel = {
214
334
  ...DEFAULT_ORGANIZATION_MODEL,
215
335
  systems: Object.fromEntries(
@@ -295,10 +415,97 @@ describe('buildOrganizationGraph with knowledge', () => {
295
415
  const defaultKnowledgeNodes = defaultGraph.nodes.filter((n) => n.kind === 'knowledge')
296
416
  expect(defaultKnowledgeNodes).toHaveLength(0)
297
417
  })
418
+
419
+ it('emits governs edges from knowledge directly to ontology graph nodes', () => {
420
+ const model = resolveOrganizationModel({
421
+ systems: {
422
+ 'sales.crm': {
423
+ id: 'sales.crm',
424
+ order: 10,
425
+ label: 'CRM',
426
+ enabled: true,
427
+ ontology: {
428
+ objectTypes: {
429
+ 'sales.crm:object/deal': {
430
+ id: 'sales.crm:object/deal',
431
+ label: 'Deal'
432
+ }
433
+ }
434
+ }
435
+ }
436
+ },
437
+ knowledge: {
438
+ 'knowledge.deal-policy': {
439
+ id: 'knowledge.deal-policy',
440
+ kind: 'reference',
441
+ title: 'Deal Policy',
442
+ summary: 'How deal records are governed.',
443
+ body: 'Deal policy.',
444
+ links: [{ target: { kind: 'ontology', id: 'sales.crm:object/deal' } }],
445
+ ownerIds: [],
446
+ updatedAt: '2026-05-14'
447
+ }
448
+ }
449
+ })
450
+ const ontologyGraph = buildOrganizationGraph({ organizationModel: model })
451
+
452
+ expect(
453
+ ontologyGraph.edges.find(
454
+ (edge) =>
455
+ edge.kind === 'governs' &&
456
+ edge.sourceId === 'knowledge:knowledge.deal-policy' &&
457
+ edge.targetId === 'ontology:sales.crm:object/deal'
458
+ )
459
+ ).toBeDefined()
460
+ })
461
+
462
+ it('knowledge query helpers traverse ontology graph node IDs', () => {
463
+ const model = resolveOrganizationModel({
464
+ systems: {
465
+ 'sales.crm': {
466
+ id: 'sales.crm',
467
+ order: 10,
468
+ label: 'CRM',
469
+ enabled: true,
470
+ ontology: {
471
+ objectTypes: {
472
+ 'sales.crm:object/deal': {
473
+ id: 'sales.crm:object/deal',
474
+ label: 'Deal'
475
+ }
476
+ }
477
+ }
478
+ }
479
+ },
480
+ knowledge: {
481
+ 'knowledge.deal-policy': {
482
+ id: 'knowledge.deal-policy',
483
+ kind: 'reference',
484
+ title: 'Deal Policy',
485
+ summary: 'How deal records are governed.',
486
+ body: 'Deal policy.',
487
+ links: [{ target: { kind: 'ontology', id: 'sales.crm:object/deal' } }],
488
+ ownerIds: [],
489
+ updatedAt: '2026-05-14'
490
+ }
491
+ }
492
+ })
493
+ const ontologyGraph = buildOrganizationGraph({ organizationModel: model })
494
+ const nodes = Object.values(model.knowledge)
495
+
496
+ expect(byOntology(ontologyGraph, 'sales.crm:object/deal', nodes).map((node) => node.id)).toEqual([
497
+ 'knowledge.deal-policy'
498
+ ])
499
+ expect(governedBy(ontologyGraph, 'ontology:sales.crm:object/deal')).toEqual(['knowledge:knowledge.deal-policy'])
500
+ expect(parsePath('/by-ontology/sales.crm:object/deal')).toEqual({
501
+ mount: 'by-ontology',
502
+ args: ['sales.crm:object/deal']
503
+ })
504
+ })
298
505
  })
299
506
 
300
507
  // ---------------------------------------------------------------------------
301
- // KnowledgeLinkSchema nodeId format validation
508
+ // KnowledgeLinkSchema — nodeId format validation
302
509
  // ---------------------------------------------------------------------------
303
510
 
304
511
  describe('KnowledgeLinkSchema', () => {
@@ -325,10 +532,19 @@ describe('KnowledgeLinkSchema', () => {
325
532
  expect(() => KnowledgeLinkSchema.parse({ nodeId: 'knowledge:knowledge.test-doc' })).not.toThrow()
326
533
  })
327
534
 
328
- it('accepts content-node: prefixed node IDs (D4 KnowledgeTargetKindSchema includes content-node)', () => {
535
+ it('accepts content-node: prefixed node IDs (D4 — KnowledgeTargetKindSchema includes content-node)', () => {
329
536
  expect(() => KnowledgeLinkSchema.parse({ nodeId: 'content-node:sales.crm:default-pipeline' })).not.toThrow()
330
537
  })
331
538
 
539
+ it('accepts and normalizes ontology graph node IDs', () => {
540
+ const link = KnowledgeLinkSchema.parse({ nodeId: 'ontology:sales.crm:object/deal' })
541
+
542
+ expect(link).toEqual({
543
+ target: { kind: 'ontology', id: 'sales.crm:object/deal' },
544
+ nodeId: 'ontology:sales.crm:object/deal'
545
+ })
546
+ })
547
+
332
548
  it('rejects a bare dotted ID with no kind: prefix', () => {
333
549
  expect(KnowledgeLinkSchema.safeParse({ nodeId: 'sales.crm' }).success).toBe(false)
334
550
  })
@@ -365,6 +581,26 @@ describe('KnowledgeTargetRefSchema', () => {
365
581
  )
366
582
  })
367
583
 
584
+ it('keeps content-node targets as compatibility pass-through links', () => {
585
+ const link = KnowledgeLinkSchema.parse({
586
+ target: { kind: 'content-node', id: 'sales.crm:default-pipeline' }
587
+ })
588
+
589
+ expect(link).toEqual({
590
+ target: { kind: 'content-node', id: 'sales.crm:default-pipeline' },
591
+ nodeId: 'content-node:sales.crm:default-pipeline'
592
+ })
593
+ })
594
+
595
+ it('accepts ontology as a target kind when the id is a valid ontology id', () => {
596
+ expect(KnowledgeTargetKindSchema.safeParse('ontology').success).toBe(true)
597
+ expect(KnowledgeTargetRefSchema.safeParse({ kind: 'ontology', id: 'sales.crm:object/deal' }).success).toBe(true)
598
+ })
599
+
600
+ it('rejects ontology targets with malformed ontology ids', () => {
601
+ expect(KnowledgeTargetRefSchema.safeParse({ kind: 'ontology', id: 'sales.crm.deal' }).success).toBe(false)
602
+ })
603
+
368
604
  it('rejects unknown target kinds', () => {
369
605
  expect(KnowledgeTargetKindSchema.safeParse('integration').success).toBe(false)
370
606
  expect(KnowledgeTargetRefSchema.safeParse({ kind: 'integration', id: 'hubspot' }).success).toBe(false)
@@ -372,10 +608,10 @@ describe('KnowledgeTargetRefSchema', () => {
372
608
  })
373
609
 
374
610
  // ---------------------------------------------------------------------------
375
- // KnowledgeDomainSchema flat Record shape (Phase 4 D3)
611
+ // KnowledgeDomainSchema — flat Record shape (Phase 4 D3)
376
612
  // ---------------------------------------------------------------------------
377
613
 
378
- describe('KnowledgeDomainSchema flat Record<id, OrgKnowledgeNode>', () => {
614
+ describe('KnowledgeDomainSchema — flat Record<id, OrgKnowledgeNode>', () => {
379
615
  it('accepts an empty map', () => {
380
616
  expect(KnowledgeDomainSchema.safeParse({}).success).toBe(true)
381
617
  })
@@ -412,13 +648,13 @@ describe('KnowledgeDomainSchema — flat Record<id, OrgKnowledgeNode>', () => {
412
648
  nodes: []
413
649
  })
414
650
  // 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
651
+ // and the values are not valid OrgKnowledgeNodeSchema — so this should fail
416
652
  expect(result.success).toBe(false)
417
653
  })
418
654
  })
419
655
 
420
656
  // ---------------------------------------------------------------------------
421
- // OrgKnowledgeNodeSchema field length constraints
657
+ // OrgKnowledgeNodeSchema — field length constraints
422
658
  // ---------------------------------------------------------------------------
423
659
 
424
660
  describe('OrgKnowledgeNodeSchema length constraints', () => {