@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
@@ -1,210 +1,35 @@
1
- import { describe, expect, it } from 'vitest'
2
- import {
3
- CONTENT_KIND_REGISTRY,
4
- defineContentType,
5
- lookupContentType,
6
- pipelineKind,
7
- stageKind,
8
- templateKind,
9
- templateStepKind,
10
- statusFlowKind,
11
- statusKind,
12
- configKvKind
13
- } from '../content-kinds/index'
14
- import type { ContentTypeDefinition, ContentTypeKey } from '../content-kinds/types'
15
-
16
- // ---------------------------------------------------------------------------
17
- // CONTENT_KIND_REGISTRY shape (D8: static object literal)
18
- // ---------------------------------------------------------------------------
19
-
20
- describe('CONTENT_KIND_REGISTRY', () => {
21
- it('contains all 7 expected keys', () => {
22
- const expectedKeys: ContentTypeKey[] = [
23
- 'schema:pipeline',
24
- 'schema:stage',
25
- 'schema:template',
26
- 'schema:template-step',
27
- 'schema:status-flow',
28
- 'schema:status',
29
- 'config:kv'
30
- ]
31
- for (const key of expectedKeys) {
32
- expect(CONTENT_KIND_REGISTRY).toHaveProperty(key)
33
- }
34
- })
35
-
36
- it('maps schema:pipeline to the pipelineKind definition', () => {
37
- expect(CONTENT_KIND_REGISTRY['schema:pipeline']).toBe(pipelineKind)
38
- })
39
-
40
- it('maps schema:stage to the stageKind definition', () => {
41
- expect(CONTENT_KIND_REGISTRY['schema:stage']).toBe(stageKind)
42
- })
43
-
44
- it('maps schema:template to the templateKind definition', () => {
45
- expect(CONTENT_KIND_REGISTRY['schema:template']).toBe(templateKind)
46
- })
47
-
48
- it('maps schema:template-step to the templateStepKind definition', () => {
49
- expect(CONTENT_KIND_REGISTRY['schema:template-step']).toBe(templateStepKind)
50
- })
51
-
52
- it('maps schema:status-flow to the statusFlowKind definition', () => {
53
- expect(CONTENT_KIND_REGISTRY['schema:status-flow']).toBe(statusFlowKind)
54
- })
55
-
56
- it('maps schema:status to the statusKind definition', () => {
57
- expect(CONTENT_KIND_REGISTRY['schema:status']).toBe(statusKind)
58
- })
59
-
60
- it('maps config:kv to the configKvKind definition', () => {
61
- expect(CONTENT_KIND_REGISTRY['config:kv']).toBe(configKvKind)
62
- })
63
-
64
- it('has exactly 7 keys (no extra unintended entries)', () => {
65
- expect(Object.keys(CONTENT_KIND_REGISTRY)).toHaveLength(7)
66
- })
67
-
68
- it('every entry has kind, type, payloadSchema, label, and description fields', () => {
69
- for (const [key, def] of Object.entries(CONTENT_KIND_REGISTRY)) {
70
- expect(def).toHaveProperty('kind')
71
- expect(def).toHaveProperty('type')
72
- expect(def).toHaveProperty('payloadSchema')
73
- expect(typeof def.kind).toBe('string')
74
- expect(typeof def.type).toBe('string')
75
- expect(def.label).toBeTruthy()
76
- expect(def.description).toBeTruthy()
77
- // key must equal kind:type
78
- expect(key).toBe(`${def.kind}:${def.type}`)
79
- }
80
- })
81
- })
82
-
83
- // ---------------------------------------------------------------------------
84
- // parentTypes constraint
85
- // ---------------------------------------------------------------------------
86
-
87
- describe('parentTypes constraints', () => {
88
- it('schema:pipeline has empty parentTypes (top-level, no parent required)', () => {
89
- expect(pipelineKind.parentTypes).toEqual([])
90
- })
91
-
92
- it('schema:stage parentTypes is ["schema:pipeline"]', () => {
93
- expect(stageKind.parentTypes).toEqual(['schema:pipeline'])
94
- })
95
-
96
- it('schema:template has empty parentTypes', () => {
97
- expect(templateKind.parentTypes).toEqual([])
98
- })
99
-
100
- it('schema:template-step parentTypes is ["schema:template"]', () => {
101
- expect(templateStepKind.parentTypes).toEqual(['schema:template'])
102
- })
103
-
104
- it('schema:status-flow has empty parentTypes', () => {
105
- expect(statusFlowKind.parentTypes).toEqual([])
106
- })
107
-
108
- it('schema:status parentTypes is ["schema:status-flow"]', () => {
109
- expect(statusKind.parentTypes).toEqual(['schema:status-flow'])
110
- })
111
-
112
- it('config:kv has empty parentTypes', () => {
113
- expect(configKvKind.parentTypes).toEqual([])
114
- })
115
- })
116
-
117
- // ---------------------------------------------------------------------------
118
- // lookupContentType
119
- // ---------------------------------------------------------------------------
120
-
121
- describe('lookupContentType', () => {
122
- it('returns the correct definition for schema:pipeline', () => {
123
- const def = lookupContentType('schema', 'pipeline')
124
- expect(def).toBe(pipelineKind)
125
- })
126
-
127
- it('returns the correct definition for schema:stage', () => {
128
- const def = lookupContentType('schema', 'stage')
129
- expect(def).toBe(stageKind)
130
- })
131
-
132
- it('returns the correct definition for config:kv', () => {
133
- const def = lookupContentType('config', 'kv')
134
- expect(def).toBe(configKvKind)
135
- })
136
-
137
- it('returns undefined for an unregistered kind (D2: not an error)', () => {
138
- const def = lookupContentType('tenant', 'custom-thing')
139
- expect(def).toBeUndefined()
140
- })
141
-
142
- it('returns undefined for unknown kind with valid type', () => {
143
- const def = lookupContentType('unknown', 'pipeline')
144
- expect(def).toBeUndefined()
145
- })
146
-
147
- it('returns undefined for valid kind with unknown type', () => {
148
- const def = lookupContentType('schema', 'not-a-real-type')
149
- expect(def).toBeUndefined()
150
- })
151
-
152
- it('returns undefined for empty kind string', () => {
153
- const def = lookupContentType('', 'pipeline')
154
- expect(def).toBeUndefined()
155
- })
156
-
157
- it('returns undefined for empty type string', () => {
158
- const def = lookupContentType('schema', '')
159
- expect(def).toBeUndefined()
160
- })
161
- })
162
-
163
- // ---------------------------------------------------------------------------
164
- // defineContentType (identity factory, L16)
165
- // ---------------------------------------------------------------------------
166
-
167
- describe('defineContentType', () => {
168
- it('is an identity function — returns the same object reference', () => {
169
- const def: ContentTypeDefinition<{ name: string }> = {
170
- kind: 'tenant',
171
- type: 'custom',
172
- payloadSchema: { safeParse: () => ({ success: true, data: { name: 'x' } }) } as unknown as ContentTypeDefinition<{
173
- name: string
174
- }>['payloadSchema'],
175
- label: 'Custom',
176
- description: 'A tenant-defined type.',
177
- parentTypes: []
178
- }
179
- const result = defineContentType(def)
180
- expect(result).toBe(def)
181
- })
182
-
183
- it('does NOT mutate the input definition', () => {
184
- const def: ContentTypeDefinition<unknown> = {
185
- kind: 'schema',
186
- type: 'pipeline',
187
- payloadSchema: {
188
- safeParse: () => ({ success: true, data: {} })
189
- } as unknown as ContentTypeDefinition<unknown>['payloadSchema'],
190
- parentTypes: []
191
- }
192
- const original = { ...def }
193
- defineContentType(def)
194
- expect(def).toEqual(original)
195
- })
196
-
197
- it('does NOT register the definition globally (no side-effects on CONTENT_KIND_REGISTRY)', () => {
198
- const tenantKey = 'tenant:my-new-type'
199
- defineContentType({
200
- kind: 'tenant',
201
- type: 'my-new-type',
202
- payloadSchema: {
203
- safeParse: () => ({ success: true, data: {} })
204
- } as unknown as ContentTypeDefinition<unknown>['payloadSchema'],
205
- parentTypes: []
206
- })
207
- // After calling defineContentType, the registry must remain unchanged (D8: static)
208
- expect(CONTENT_KIND_REGISTRY).not.toHaveProperty(tenantKey)
209
- })
210
- })
1
+ import { describe, expect, it } from 'vitest'
2
+ import { OrganizationGraphNodeKindSchema } from '../graph/schema'
3
+ import { OrganizationModelSchema } from '../schema'
4
+
5
+ describe('retired System.content bridge', () => {
6
+ it('rejects bridge-era content maps on System entries', () => {
7
+ const result = OrganizationModelSchema.safeParse({
8
+ version: 1,
9
+ branding: { name: 'Test Org' },
10
+ navigation: { sidebar: [] },
11
+ systems: {
12
+ sales: {
13
+ id: 'sales',
14
+ order: 10,
15
+ label: 'Sales',
16
+ content: {
17
+ pipeline: {
18
+ kind: 'schema',
19
+ type: 'pipeline',
20
+ label: 'Pipeline',
21
+ data: { entityId: 'crm.deal' }
22
+ }
23
+ }
24
+ }
25
+ }
26
+ })
27
+
28
+ expect(result.success).toBe(false)
29
+ expect(result.error?.issues.map((issue) => issue.path.join('.'))).toContain('systems.sales')
30
+ })
31
+
32
+ it('rejects content-node as a graph node kind', () => {
33
+ expect(OrganizationGraphNodeKindSchema.safeParse('content-node').success).toBe(false)
34
+ })
35
+ })
@@ -78,7 +78,7 @@ describe('organization-model defaults', () => {
78
78
  describe.skip('DEFAULT_ORGANIZATION_MODEL_SALES via resolveOrganizationModel (deferred — Phase 4: sales domain removed)', () => {
79
79
  it('resolving with sales override produces a schema-valid model', () => {
80
80
  // Previously: resolveOrganizationModel({ sales: DEFAULT_ORGANIZATION_MODEL_SALES })
81
- // Sales data now lives in system.content. Use getAllPipelines(model) from migration-helpers.
81
+ // Sales data now lives in System.ontology.catalogTypes. Use getAllPipelines(model).
82
82
  })
83
83
  })
84
84
 
@@ -86,7 +86,7 @@ describe('organization-model defaults', () => {
86
86
  describe.skip('DEFAULT_ORGANIZATION_MODEL_PROJECTS via resolveOrganizationModel (deferred — Phase 4: projects domain removed)', () => {
87
87
  it('resolving with projects override produces a schema-valid model', () => {
88
88
  // Previously: resolveOrganizationModel({ projects: DEFAULT_ORGANIZATION_MODEL_PROJECTS })
89
- // Project statuses now live in system.content. Use getAllProjectStatuses(model) from migration-helpers.
89
+ // Project statuses now live in System.ontology.catalogTypes. Use getAllProjectStatuses(model).
90
90
  })
91
91
  })
92
92
 
@@ -94,7 +94,7 @@ describe('organization-model defaults', () => {
94
94
  describe.skip('DEFAULT_ORGANIZATION_MODEL_PROSPECTING via resolveOrganizationModel (deferred — Phase 4: prospecting domain removed)', () => {
95
95
  it('resolving with prospecting override produces a schema-valid model', () => {
96
96
  // Previously: resolveOrganizationModel({ prospecting: DEFAULT_ORGANIZATION_MODEL_PROSPECTING })
97
- // Prospecting stages/templates now live in system.content. Use getAllProspectingStages() / getAllBuildTemplates().
97
+ // Prospecting stages/templates now live in System.ontology.catalogTypes.
98
98
  })
99
99
  })
100
100
 
@@ -122,7 +122,7 @@ describe('organization-model defaults', () => {
122
122
  // We keep the data-integrity checks below; the resolveOrganizationModel override test is skipped.
123
123
  it.skip('resolving with statuses override produces a schema-valid model (deferred — Phase 4: statuses field removed from OM schema)', () => {
124
124
  // Previously: resolveOrganizationModel({ statuses: DEFAULT_ORGANIZATION_MODEL_STATUSES })
125
- // Status data now lives in system.content via (schema:status-flow) + (schema:status) content nodes.
125
+ // Status data now lives in System.ontology.catalogTypes.
126
126
  })
127
127
 
128
128
  it('default statuses seed covers all 9 delivery.task values', () => {
@@ -1,40 +1,16 @@
1
1
  import { describe, expect, it } from 'vitest'
2
- import {
3
- ActionsDomainSchema,
4
- ActionInvocationSchema,
5
- CRM_ACTION_ENTRIES,
6
- DEFAULT_ORGANIZATION_MODEL_ACTIONS,
7
- LEAD_GEN_ACTION_ENTRIES
8
- } from '../../domains/actions'
9
-
10
- describe('actions domain', () => {
11
- it('defaults lead-gen action entries with invocation contracts', () => {
12
- const domain = ActionsDomainSchema.parse(LEAD_GEN_ACTION_ENTRIES)
13
-
14
- expect(Object.keys(domain)).toHaveLength(13)
15
- expect(domain['lead-gen.company.source']).toMatchObject({
16
- id: 'lead-gen.company.source',
17
- scope: { domain: 'sales' },
18
- lifecycle: 'active'
19
- })
20
- expect(Object.values(domain).every((action) => action.invocations.length > 0)).toBe(true)
21
- })
22
-
23
- it('defaults CRM action entries for deal actions', () => {
24
- const domain = ActionsDomainSchema.parse(CRM_ACTION_ENTRIES)
25
-
26
- expect(Object.keys(domain)).toHaveLength(9)
27
- expect(domain.mark_no_show).toBeUndefined()
28
- expect(
29
- Object.values(domain).every((action) => action.affects?.includes('crm.deal') && action.resourceId !== undefined)
30
- ).toBe(true)
31
- })
32
-
33
- it('defaults all organization-model actions', () => {
34
- const domain = ActionsDomainSchema.parse(DEFAULT_ORGANIZATION_MODEL_ACTIONS)
35
-
36
- expect(Object.keys(domain)).toHaveLength(22)
37
- })
2
+ import {
3
+ ActionsDomainSchema,
4
+ ActionInvocationSchema,
5
+ DEFAULT_ORGANIZATION_MODEL_ACTIONS
6
+ } from '../../domains/actions'
7
+
8
+ describe('actions domain', () => {
9
+ it('keeps the generic core default action catalog empty', () => {
10
+ const domain = ActionsDomainSchema.parse(DEFAULT_ORGANIZATION_MODEL_ACTIONS)
11
+
12
+ expect(domain).toEqual({})
13
+ })
38
14
 
39
15
  it('accepts entity references in affects', () => {
40
16
  expect(() =>
@@ -321,12 +321,19 @@ describe('resolveOrganizationModel — offerings cross-ref (targetSegmentIds)',
321
321
  // ---------------------------------------------------------------------------
322
322
 
323
323
  describe('resolveOrganizationModel — offerings cross-ref (deliveryFeatureId)', () => {
324
- it('passes when deliveryFeatureId references a declared system', () => {
325
- // 'sales.crm' is in DEFAULT_ORGANIZATION_MODEL.systems
326
- expect(() =>
327
- resolveOrganizationModel({
328
- offerings: {
329
- 'product-with-delivery': {
324
+ it('passes when deliveryFeatureId references a declared system', () => {
325
+ expect(() =>
326
+ resolveOrganizationModel({
327
+ systems: {
328
+ 'sales.crm': {
329
+ id: 'sales.crm',
330
+ order: 10,
331
+ label: 'CRM',
332
+ lifecycle: 'active'
333
+ }
334
+ },
335
+ offerings: {
336
+ 'product-with-delivery': {
330
337
  id: 'product-with-delivery',
331
338
  order: 10,
332
339
  deliveryFeatureId: 'sales.crm'