@elevasis/core 0.25.0 → 0.26.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 (66) hide show
  1. package/dist/index.d.ts +166 -85
  2. package/dist/index.js +146 -1346
  3. package/dist/knowledge/index.d.ts +27 -38
  4. package/dist/knowledge/index.js +1 -1
  5. package/dist/organization-model/index.d.ts +166 -85
  6. package/dist/organization-model/index.js +146 -1346
  7. package/dist/test-utils/index.d.ts +23 -31
  8. package/dist/test-utils/index.js +75 -1238
  9. package/package.json +1 -1
  10. package/src/_gen/__tests__/__snapshots__/contracts.md.snap +14 -2
  11. package/src/business/acquisition/api-schemas.test.ts +70 -77
  12. package/src/business/acquisition/api-schemas.ts +21 -42
  13. package/src/business/acquisition/derive-actions.test.ts +11 -21
  14. package/src/business/acquisition/derive-actions.ts +61 -14
  15. package/src/business/acquisition/ontology-validation.ts +4 -4
  16. package/src/business/acquisition/types.ts +7 -8
  17. package/src/knowledge/queries.ts +0 -1
  18. package/src/organization-model/__tests__/content-kinds-registry.test.ts +35 -210
  19. package/src/organization-model/__tests__/defaults.test.ts +4 -4
  20. package/src/organization-model/__tests__/domains/actions.test.ts +12 -36
  21. package/src/organization-model/__tests__/domains/offerings.test.ts +13 -6
  22. package/src/organization-model/__tests__/domains/resources.test.ts +497 -350
  23. package/src/organization-model/__tests__/domains/systems.test.ts +6 -7
  24. package/src/organization-model/__tests__/flatten-additive-merge.test.ts +68 -80
  25. package/src/organization-model/__tests__/foundation.test.ts +81 -14
  26. package/src/organization-model/__tests__/graph.test.ts +662 -694
  27. package/src/organization-model/__tests__/knowledge.test.ts +31 -17
  28. package/src/organization-model/__tests__/lookup-helpers.test.ts +128 -438
  29. package/src/organization-model/__tests__/migration-helpers.test.ts +362 -591
  30. package/src/organization-model/__tests__/prospecting-ssot.test.ts +68 -103
  31. package/src/organization-model/__tests__/published-zero-leak.test.ts +17 -0
  32. package/src/organization-model/__tests__/recursive-system-schema.test.ts +159 -532
  33. package/src/organization-model/__tests__/resolve.test.ts +79 -42
  34. package/src/organization-model/__tests__/schema.test.ts +65 -56
  35. package/src/organization-model/catalogs/lead-gen.ts +0 -103
  36. package/src/organization-model/defaults.ts +17 -702
  37. package/src/organization-model/domains/actions.ts +116 -333
  38. package/src/organization-model/domains/knowledge.ts +15 -7
  39. package/src/organization-model/domains/projects.ts +4 -4
  40. package/src/organization-model/domains/prospecting.ts +405 -395
  41. package/src/organization-model/domains/resources.ts +206 -135
  42. package/src/organization-model/domains/sales.ts +5 -5
  43. package/src/organization-model/domains/systems.ts +8 -23
  44. package/src/organization-model/graph/build.ts +223 -294
  45. package/src/organization-model/graph/schema.ts +2 -3
  46. package/src/organization-model/graph/types.ts +12 -14
  47. package/src/organization-model/helpers.ts +130 -218
  48. package/src/organization-model/index.ts +104 -124
  49. package/src/organization-model/migration-helpers.ts +211 -249
  50. package/src/organization-model/ontology.ts +0 -60
  51. package/src/organization-model/organization-graph.mdx +4 -5
  52. package/src/organization-model/organization-model.mdx +1 -1
  53. package/src/organization-model/published.ts +236 -226
  54. package/src/organization-model/resolve.ts +4 -5
  55. package/src/organization-model/schema.ts +610 -704
  56. package/src/organization-model/types.ts +167 -161
  57. package/src/platform/registry/__tests__/validation.test.ts +23 -0
  58. package/src/platform/registry/validation.ts +13 -2
  59. package/src/reference/_generated/contracts.md +14 -2
  60. package/src/organization-model/content-kinds/config.ts +0 -36
  61. package/src/organization-model/content-kinds/index.ts +0 -78
  62. package/src/organization-model/content-kinds/pipeline.ts +0 -68
  63. package/src/organization-model/content-kinds/registry.ts +0 -44
  64. package/src/organization-model/content-kinds/status.ts +0 -71
  65. package/src/organization-model/content-kinds/template.ts +0 -83
  66. package/src/organization-model/content-kinds/types.ts +0 -117
@@ -118,13 +118,12 @@ describe('SystemStatusSchema', () => {
118
118
  })
119
119
  })
120
120
 
121
- describe('resolveOrganizationModel - systems domain integration', () => {
122
- it('omitting systems keeps default system entries', () => {
123
- const model = resolveOrganizationModel({})
124
-
125
- expect(Object.keys(model.systems).length).toBeGreaterThan(Object.keys(DEFAULT_ORGANIZATION_MODEL_SYSTEMS).length)
126
- expect(model.systems['sales.crm']?.path).toBe('/crm')
127
- })
121
+ describe('resolveOrganizationModel - systems domain integration', () => {
122
+ it('omitting systems keeps the generic systems domain empty', () => {
123
+ const model = resolveOrganizationModel({})
124
+
125
+ expect(model.systems).toEqual(DEFAULT_ORGANIZATION_MODEL_SYSTEMS)
126
+ })
128
127
 
129
128
  it('accepts valid responsible role, knowledge, and goal references', () => {
130
129
  expect(() =>
@@ -24,7 +24,7 @@ import type { DeepPartial, OrganizationModel } from '../types'
24
24
 
25
25
  describe('flatten: deepMerge produces additive-by-id behavior across all 9 flattened domains', () => {
26
26
  // Phase 4 (D1): 'statuses' top-level field removed from OrganizationModel.
27
- // Status data moved into system.content as (schema:status-flow) / (schema:status) nodes.
27
+ // Status data moved into System.ontology.catalogTypes.
28
28
  // The remaining 8 domains are all Record<string, Entry> after the flatten.
29
29
  const FLATTENED_DOMAINS = [
30
30
  'systems',
@@ -59,12 +59,9 @@ describe('flatten: deepMerge produces additive-by-id behavior across all 9 flatt
59
59
  }
60
60
  })
61
61
 
62
- expect(Object.keys(model.systems)).toHaveLength(baseSize + 1)
63
- expect(model.systems['tenant.workspace']?.label).toBe('Tenant Workspace')
64
- // Default systems survive
65
- expect(model.systems['dashboard']).toBeDefined()
66
- expect(model.systems['operations']).toBeDefined()
67
- })
62
+ expect(Object.keys(model.systems)).toHaveLength(baseSize + 1)
63
+ expect(model.systems['tenant.workspace']?.label).toBe('Tenant Workspace')
64
+ })
68
65
 
69
66
  it('merges a tenant role additively without clobbering default roles', () => {
70
67
  const baseSize = Object.keys(DEFAULT_ORGANIZATION_MODEL.roles).length
@@ -83,11 +80,10 @@ describe('flatten: deepMerge produces additive-by-id behavior across all 9 flatt
83
80
  expect(model.roles['role.tenant-lead']?.title).toBe('Tenant Lead')
84
81
  })
85
82
 
86
- it('merges a tenant action additively while preserving the default action catalog', () => {
87
- const baseSize = Object.keys(DEFAULT_ORGANIZATION_MODEL.actions).length
88
- expect(baseSize).toBeGreaterThan(0)
89
-
90
- const model = resolveOrganizationModel({
83
+ it('merges a tenant action additively while preserving the default action catalog', () => {
84
+ const baseSize = Object.keys(DEFAULT_ORGANIZATION_MODEL.actions).length
85
+
86
+ const model = resolveOrganizationModel({
91
87
  actions: {
92
88
  'tenant.custom-action': {
93
89
  id: 'tenant.custom-action',
@@ -98,12 +94,10 @@ describe('flatten: deepMerge produces additive-by-id behavior across all 9 flatt
98
94
  }
99
95
  }
100
96
  })
101
-
102
- expect(Object.keys(model.actions)).toHaveLength(baseSize + 1)
103
- expect(model.actions['tenant.custom-action']?.label).toBe('Custom Action')
104
- expect(model.actions['lead-gen.company.source']).toBeDefined()
105
- expect(model.actions['send_reply']).toBeDefined()
106
- })
97
+
98
+ expect(Object.keys(model.actions)).toHaveLength(baseSize + 1)
99
+ expect(model.actions['tenant.custom-action']?.label).toBe('Custom Action')
100
+ })
107
101
 
108
102
  it('overrides an existing system by id (last write wins on the same map key)', () => {
109
103
  const model = resolveOrganizationModel({
@@ -119,29 +113,23 @@ describe('flatten: deepMerge produces additive-by-id behavior across all 9 flatt
119
113
  })
120
114
 
121
115
  expect(model.systems['dashboard']?.label).toBe('Tenant Dashboard')
122
- // Other defaults remain
123
- expect(model.systems['operations']).toBeDefined()
124
- })
125
-
126
- it('merges nested fields within a single entry deeply (not replacing the whole entry)', () => {
127
- // Overriding only `label` on a default system preserves its other fields.
128
- const defaultDashboard = DEFAULT_ORGANIZATION_MODEL.systems['dashboard']
129
- expect(defaultDashboard).toBeDefined()
130
-
131
- const model = resolveOrganizationModel({
132
- systems: {
133
- dashboard: {
134
- id: 'dashboard',
135
- order: defaultDashboard!.order,
136
- label: 'Renamed'
137
- }
138
- }
139
- })
140
-
141
- const merged = model.systems['dashboard']
142
- expect(merged?.label).toBe('Renamed')
143
- // Path from defaults survives because object merge is deep per-key.
144
- expect(merged?.path).toBe(defaultDashboard!.path)
116
+ })
117
+
118
+ it('adds a complete system entry when no generic default entry exists', () => {
119
+ const model = resolveOrganizationModel({
120
+ systems: {
121
+ dashboard: {
122
+ id: 'dashboard',
123
+ order: 10,
124
+ label: 'Renamed',
125
+ path: '/'
126
+ }
127
+ }
128
+ })
129
+
130
+ const merged = model.systems['dashboard']
131
+ expect(merged?.label).toBe('Renamed')
132
+ expect(merged?.path).toBe('/')
145
133
  })
146
134
 
147
135
  it('confirms no special-case mergeSystemsById helper exists in resolve.ts', async () => {
@@ -216,23 +204,18 @@ describe('flatten: deepMerge produces additive-by-id behavior across all 9 flatt
216
204
  })
217
205
  })
218
206
 
219
- it('override entry omitting order preserves the base order value', () => {
220
- const baseOrder = DEFAULT_ORGANIZATION_MODEL.systems['dashboard']!.order
221
-
222
- const override: DeepPartial<OrganizationModel> = {
223
- systems: {
224
- dashboard: {
225
- id: 'dashboard',
226
- label: 'Renamed Dashboard'
207
+ it('override entry omitting required order is rejected when no base entry exists', () => {
208
+ const override: DeepPartial<OrganizationModel> = {
209
+ systems: {
210
+ dashboard: {
211
+ id: 'dashboard',
212
+ label: 'Renamed Dashboard'
227
213
  }
228
214
  }
229
215
  }
230
216
 
231
- const resolved = resolveOrganizationModel(override)
232
-
233
- expect(resolved.systems['dashboard']!.order).toBe(baseOrder)
234
- expect(resolved.systems['dashboard']!.label).toBe('Renamed Dashboard')
235
- })
217
+ expect(() => resolveOrganizationModel(override)).toThrow()
218
+ })
236
219
 
237
220
  it('throws when system map key does not match the entry id', () => {
238
221
  const badOverride: DeepPartial<OrganizationModel> = {
@@ -255,13 +238,20 @@ describe('flatten: deepMerge produces additive-by-id behavior across all 9 flatt
255
238
  // deepMerge hits Array.isArray(existing) => returns override value directly.
256
239
  const singleRef = [{ actionId: 'lead-gen.company.source', intent: 'exposes' as const }]
257
240
 
258
- const override: DeepPartial<OrganizationModel> = {
259
- systems: {
260
- 'sales.lead-gen': {
261
- id: 'sales.lead-gen',
262
- order: DEFAULT_ORGANIZATION_MODEL.systems['sales.lead-gen']!.order,
263
- label: 'Lead Gen',
264
- actions: singleRef
241
+ const override: DeepPartial<OrganizationModel> = {
242
+ actions: {
243
+ 'lead-gen.company.source': {
244
+ id: 'lead-gen.company.source',
245
+ order: 10,
246
+ label: 'Source companies'
247
+ }
248
+ },
249
+ systems: {
250
+ 'sales.lead-gen': {
251
+ id: 'sales.lead-gen',
252
+ order: 10,
253
+ label: 'Lead Gen',
254
+ actions: singleRef
265
255
  }
266
256
  }
267
257
  }
@@ -280,23 +270,21 @@ describe('flatten: deepMerge produces additive-by-id behavior across all 9 flatt
280
270
  expect(withEmpty.systems).toEqual(withNone.systems)
281
271
  })
282
272
 
283
- it('field set to undefined in override is skipped and retains the base value', () => {
284
- const basePath = DEFAULT_ORGANIZATION_MODEL.systems['dashboard']!.path
285
-
286
- const override: DeepPartial<OrganizationModel> = {
287
- systems: {
288
- dashboard: {
289
- id: 'dashboard',
290
- order: DEFAULT_ORGANIZATION_MODEL.systems['dashboard']!.order,
291
- label: 'Dashboard',
292
- path: undefined
273
+ it('field set to undefined in override is skipped and retains the base value', () => {
274
+ const override: DeepPartial<OrganizationModel> = {
275
+ systems: {
276
+ dashboard: {
277
+ id: 'dashboard',
278
+ order: 10,
279
+ label: 'Dashboard',
280
+ path: undefined
293
281
  }
294
282
  }
295
283
  }
296
284
 
297
- const resolved = resolveOrganizationModel(override)
298
-
299
- expect(resolved.systems['dashboard']!.path).toBe(basePath)
285
+ const resolved = resolveOrganizationModel(override)
286
+
287
+ expect(resolved.systems['dashboard']!.path).toBeUndefined()
300
288
  })
301
289
 
302
290
  it('simultaneous override of systems, roles, and actions merges each domain independently without cross-contamination', () => {
@@ -343,12 +331,12 @@ describe('flatten: deepMerge produces additive-by-id behavior across all 9 flatt
343
331
  const replacementInvocations = [{ kind: 'slash-command' as const, command: '/custom-source' }]
344
332
 
345
333
  const override: DeepPartial<OrganizationModel> = {
346
- actions: {
347
- 'lead-gen.company.source': {
348
- id: 'lead-gen.company.source',
349
- order: DEFAULT_ORGANIZATION_MODEL.actions['lead-gen.company.source']!.order,
350
- label: 'Source companies',
351
- invocations: replacementInvocations
334
+ actions: {
335
+ 'lead-gen.company.source': {
336
+ id: 'lead-gen.company.source',
337
+ order: 10,
338
+ label: 'Source companies',
339
+ invocations: replacementInvocations
352
340
  }
353
341
  }
354
342
  }
@@ -1,11 +1,77 @@
1
1
  import { describe, expect, it } from 'vitest'
2
- import { createFoundationOrganizationModel } from '../foundation'
3
-
4
- describe('createFoundationOrganizationModel', () => {
5
- it('builds the foundation model from derived sidebar navigation', () => {
6
- const result = createFoundationOrganizationModel({
7
- branding: { organizationName: 'Acme', productName: 'Acme OS', shortName: 'Acme' }
8
- })
2
+ import { createFoundationOrganizationModel } from '../foundation'
3
+
4
+ const foundationFixture = {
5
+ branding: { organizationName: 'Acme', productName: 'Acme OS', shortName: 'Acme' },
6
+ systems: {
7
+ dashboard: { id: 'dashboard', order: 10, label: 'Dashboard', lifecycle: 'active' as const },
8
+ sales: { id: 'sales', order: 20, label: 'Sales', lifecycle: 'active' as const },
9
+ clients: { id: 'clients', order: 30, label: 'Clients', lifecycle: 'active' as const },
10
+ projects: { id: 'projects', order: 40, label: 'Projects', lifecycle: 'active' as const },
11
+ operations: { id: 'operations', order: 50, label: 'Operations', lifecycle: 'active' as const },
12
+ 'settings.account': { id: 'settings.account', order: 60, label: 'Account', lifecycle: 'active' as const }
13
+ },
14
+ navigation: {
15
+ sidebar: {
16
+ primary: {
17
+ dashboard: {
18
+ type: 'surface' as const,
19
+ label: 'Dashboard',
20
+ path: '/',
21
+ surfaceType: 'dashboard' as const,
22
+ order: 10,
23
+ targets: { systems: ['dashboard'] }
24
+ },
25
+ sales: {
26
+ type: 'surface' as const,
27
+ label: 'Sales',
28
+ path: '/sales',
29
+ surfaceType: 'page' as const,
30
+ order: 20,
31
+ targets: { systems: ['sales'] }
32
+ },
33
+ clients: {
34
+ type: 'surface' as const,
35
+ label: 'Clients',
36
+ path: '/clients',
37
+ surfaceType: 'list' as const,
38
+ order: 30,
39
+ targets: { systems: ['clients'] }
40
+ },
41
+ projects: {
42
+ type: 'surface' as const,
43
+ label: 'Projects',
44
+ path: '/projects',
45
+ surfaceType: 'page' as const,
46
+ order: 40,
47
+ targets: { systems: ['projects'] }
48
+ },
49
+ 'operations-overview': {
50
+ type: 'surface' as const,
51
+ label: 'Operations',
52
+ path: '/operations',
53
+ surfaceType: 'page' as const,
54
+ order: 50,
55
+ targets: { systems: ['operations'] }
56
+ }
57
+ },
58
+ bottom: {
59
+ 'settings-account': {
60
+ type: 'surface' as const,
61
+ label: 'Account',
62
+ path: '/settings/account',
63
+ surfaceType: 'settings' as const,
64
+ order: 10,
65
+ targets: { systems: ['settings.account'] }
66
+ }
67
+ }
68
+ }
69
+ }
70
+ }
71
+
72
+ describe('createFoundationOrganizationModel', () => {
73
+ it('builds the foundation model from derived sidebar navigation', () => {
74
+ const result = createFoundationOrganizationModel(foundationFixture)
9
75
 
10
76
  expect(result.canonical.branding.organizationName).toBe('Acme')
11
77
  expect(result.homeLabel).toBe('Dashboard')
@@ -27,13 +93,11 @@ describe('createFoundationOrganizationModel', () => {
27
93
 
28
94
  it.skip('passes deeper overrides through to the canonical model (deferred - Phase 4: sales domain removed)', () => {
29
95
  // Previously tested: result.canonical.sales.pipelines.
30
- // Re-enable with a content-node based pipeline override test if needed.
96
+ // Re-enable with an ontology catalog based pipeline override test if needed.
31
97
  })
32
98
 
33
- it('exposes a working getOrganizationSurface lookup', () => {
34
- const result = createFoundationOrganizationModel({
35
- branding: { organizationName: 'Acme', productName: 'Acme OS', shortName: 'Acme' }
36
- })
99
+ it('exposes a working getOrganizationSurface lookup', () => {
100
+ const result = createFoundationOrganizationModel(foundationFixture)
37
101
 
38
102
  const clientsSurface = result.getOrganizationSurface('clients')
39
103
  expect(clientsSurface).toBeDefined()
@@ -44,8 +108,11 @@ describe('createFoundationOrganizationModel', () => {
44
108
  })
45
109
 
46
110
  it('does not require hardcoded system-backed foundation surfaces', () => {
47
- const result = createFoundationOrganizationModel({
48
- navigation: {
111
+ const result = createFoundationOrganizationModel({
112
+ systems: {
113
+ dashboard: { id: 'dashboard', order: 10, label: 'Dashboard', lifecycle: 'active' }
114
+ },
115
+ navigation: {
49
116
  sidebar: {
50
117
  primary: {
51
118
  dashboard: {