@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,36 +1,38 @@
1
- import { describe, expect, it } from 'vitest'
2
- import { ZodError } from 'zod'
3
- import { bindResourceDescriptor } from '../../../platform/registry/types'
4
- import {
5
- DEFAULT_ORGANIZATION_MODEL_RESOURCES,
6
- EventIdSchema,
1
+ import { describe, expect, it } from 'vitest'
2
+ import { ZodError } from 'zod'
3
+ import { bindResourceDescriptor } from '../../../platform/registry/types'
4
+ import {
5
+ ContractRefSchema,
6
+ DEFAULT_ORGANIZATION_MODEL_RESOURCES,
7
+ EventIdSchema,
7
8
  ResourceEntrySchema,
8
9
  ResourceKindSchema,
9
10
  ResourceOntologyBindingSchema,
10
11
  ResourcesDomainSchema,
11
- defineResource,
12
- defineResources
13
- } from '../../domains/resources'
14
- import { resolveOrganizationModel } from '../../resolve'
15
-
16
- const VALID_SYSTEM = {
17
- id: 'sys.lead-gen',
18
- order: 10,
19
- title: 'Lead Generation Pipeline',
20
- description: 'Coordinates prospecting, enrichment, qualification, and outreach preparation.',
21
- kind: 'operational' as const,
22
- status: 'active' as const
23
- }
24
-
25
- const VALID_ROLE = {
26
- id: 'role.sales-ops',
27
- order: 10,
28
- title: 'Sales Ops'
29
- }
30
-
31
- const WORKFLOW_RESOURCE = {
32
- id: 'LGN-01-company-scrape',
33
- order: 10,
12
+ defineResource,
13
+ defineResources,
14
+ parseContractRef
15
+ } from '../../domains/resources'
16
+ import { resolveOrganizationModel } from '../../resolve'
17
+
18
+ const VALID_SYSTEM = {
19
+ id: 'sys.lead-gen',
20
+ order: 10,
21
+ title: 'Lead Generation Pipeline',
22
+ description: 'Coordinates prospecting, enrichment, qualification, and outreach preparation.',
23
+ kind: 'operational' as const,
24
+ status: 'active' as const
25
+ }
26
+
27
+ const VALID_ROLE = {
28
+ id: 'role.sales-ops',
29
+ order: 10,
30
+ title: 'Sales Ops'
31
+ }
32
+
33
+ const WORKFLOW_RESOURCE = {
34
+ id: 'LGN-01-company-scrape',
35
+ order: 10,
34
36
  kind: 'workflow' as const,
35
37
  systemPath: 'sys.lead-gen',
36
38
  title: 'Company Scrape',
@@ -38,195 +40,195 @@ const WORKFLOW_RESOURCE = {
38
40
  ownerRoleId: 'role.sales-ops',
39
41
  status: 'active' as const,
40
42
  codeRefs: [
41
- {
42
- path: 'operations/src/lead-gen/company-scrape/index.ts',
43
- role: 'entrypoint' as const,
44
- symbol: 'companyScrapeWorkflow',
45
- description: 'Workflow definition bound to this OM resource descriptor.'
46
- }
47
- ]
48
- }
49
-
50
- const WORKFLOW_EVENT_EMISSION = {
51
- eventKey: 'processed',
52
- label: 'Processed',
53
- payloadSchema: 'leadgen.company.processed',
54
- lifecycle: 'active' as const
55
- }
56
-
57
- const AGENT_RESOURCE = {
58
- id: 'command-center-assistant',
59
- order: 20,
60
- kind: 'agent' as const,
61
- systemPath: 'sys.lead-gen',
62
- ownerRoleId: 'role.sales-ops',
63
- status: 'active' as const,
64
- agentKind: 'platform' as const,
65
- actsAsRoleId: 'role.sales-ops',
66
- sessionCapable: true,
67
- invocations: [{ kind: 'slash-command' as const, command: '/work handoff' }]
68
- }
69
-
70
- const INTEGRATION_RESOURCE = {
71
- id: 'attio-crm',
72
- order: 30,
73
- kind: 'integration' as const,
74
- systemPath: 'sys.lead-gen',
75
- ownerRoleId: 'role.sales-ops',
76
- status: 'active' as const,
77
- provider: 'attio'
78
- }
79
-
80
- const SCRIPT_RESOURCE = {
81
- id: 'leadgen-backfill-script',
82
- order: 40,
83
- kind: 'script' as const,
84
- systemPath: 'sys.lead-gen',
85
- ownerRoleId: 'role.sales-ops',
86
- status: 'active' as const,
87
- language: 'typescript' as const,
88
- source: {
89
- file: 'scripts/leadgen/backfill.ts'
90
- }
91
- }
92
-
93
- function resolveWithResources(resources: Record<string, unknown>) {
94
- return resolveOrganizationModel({
95
- roles: { 'role.sales-ops': VALID_ROLE },
96
- systems: { 'sys.lead-gen': VALID_SYSTEM },
97
- resources: resources as Record<string, typeof WORKFLOW_RESOURCE>
98
- })
99
- }
100
-
101
- describe('ResourceEntrySchema', () => {
102
- it('accepts workflow, agent, integration, and script descriptors with required systemPath', () => {
103
- expect(ResourceEntrySchema.safeParse(WORKFLOW_RESOURCE).success).toBe(true)
104
- expect(ResourceEntrySchema.safeParse(AGENT_RESOURCE).success).toBe(true)
105
- expect(ResourceEntrySchema.safeParse(INTEGRATION_RESOURCE).success).toBe(true)
106
- expect(ResourceEntrySchema.safeParse(SCRIPT_RESOURCE).success).toBe(true)
107
- })
108
-
109
- it('rejects resources without a systemPath', () => {
110
- const { systemPath: _systemPath, ...resourceWithoutSystem } = WORKFLOW_RESOURCE
111
-
112
- expect(ResourceEntrySchema.safeParse(resourceWithoutSystem).success).toBe(false)
113
- })
114
-
115
- it('defaults codeRefs and accepts resource-level implementation breadcrumbs', () => {
116
- const withCodeRefs = ResourceEntrySchema.safeParse(WORKFLOW_RESOURCE)
117
- const withoutCodeRefs = ResourceEntrySchema.safeParse({
118
- ...WORKFLOW_RESOURCE,
119
- codeRefs: undefined
120
- })
121
-
122
- expect(withCodeRefs.success).toBe(true)
123
- expect(withoutCodeRefs.success).toBe(true)
124
-
125
- if (withCodeRefs.success) {
126
- expect(withCodeRefs.data.codeRefs).toEqual(WORKFLOW_RESOURCE.codeRefs)
127
- }
128
- if (withoutCodeRefs.success) {
129
- expect(withoutCodeRefs.data.codeRefs).toEqual([])
130
- }
131
- })
132
-
133
- it('rejects codeRefs with an empty path', () => {
134
- expect(
135
- ResourceEntrySchema.safeParse({
136
- ...WORKFLOW_RESOURCE,
137
- codeRefs: [
138
- {
139
- path: ' ',
140
- role: 'entrypoint'
141
- }
142
- ]
143
- }).success
144
- ).toBe(false)
145
- })
146
-
147
- it('rejects codeRefs with an invalid role', () => {
148
- expect(
149
- ResourceEntrySchema.safeParse({
150
- ...WORKFLOW_RESOURCE,
151
- codeRefs: [
152
- {
153
- path: 'operations/src/lead-gen/company-scrape/index.ts',
154
- role: 'runtime'
155
- }
156
- ]
157
- }).success
158
- ).toBe(false)
159
- })
160
-
161
- it('rejects multi-system membership', () => {
162
- expect(
163
- ResourceEntrySchema.safeParse({
164
- ...WORKFLOW_RESOURCE,
165
- systemPath: ['sys.lead-gen', 'sys.crm']
166
- }).success
167
- ).toBe(false)
168
- })
169
-
170
- it('rejects an agent kind outside the code-side mirror enum', () => {
171
- expect(
172
- ResourceEntrySchema.safeParse({
173
- ...AGENT_RESOURCE,
174
- agentKind: 'runner'
175
- }).success
176
- ).toBe(false)
177
- })
178
-
179
- it('defaults agent invocations and accepts slash-command orchestration entries', () => {
180
- const result = ResourceEntrySchema.safeParse({
181
- ...AGENT_RESOURCE,
182
- invocations: undefined
183
- })
184
-
185
- expect(result.success).toBe(true)
186
- if (result.success) {
187
- expect(result.data.kind).toBe('agent')
188
- if (result.data.kind === 'agent') {
189
- expect(result.data.invocations).toEqual([])
190
- }
191
- }
192
-
193
- expect(ResourceEntrySchema.safeParse(AGENT_RESOURCE).success).toBe(true)
194
- })
195
-
196
- it('rejects malformed agent invocation entries', () => {
197
- expect(
198
- ResourceEntrySchema.safeParse({
199
- ...AGENT_RESOURCE,
200
- invocations: [{ kind: 'slash-command', command: 'work handoff' }]
201
- }).success
202
- ).toBe(false)
203
- })
204
-
43
+ {
44
+ path: 'operations/src/lead-gen/company-scrape/index.ts',
45
+ role: 'entrypoint' as const,
46
+ symbol: 'companyScrapeWorkflow',
47
+ description: 'Workflow definition bound to this OM resource descriptor.'
48
+ }
49
+ ]
50
+ }
51
+
52
+ const WORKFLOW_EVENT_EMISSION = {
53
+ eventKey: 'processed',
54
+ label: 'Processed',
55
+ payloadSchema: 'leadgen.company.processed',
56
+ lifecycle: 'active' as const
57
+ }
58
+
59
+ const AGENT_RESOURCE = {
60
+ id: 'command-center-assistant',
61
+ order: 20,
62
+ kind: 'agent' as const,
63
+ systemPath: 'sys.lead-gen',
64
+ ownerRoleId: 'role.sales-ops',
65
+ status: 'active' as const,
66
+ agentKind: 'platform' as const,
67
+ actsAsRoleId: 'role.sales-ops',
68
+ sessionCapable: true,
69
+ invocations: [{ kind: 'slash-command' as const, command: '/work handoff' }]
70
+ }
71
+
72
+ const INTEGRATION_RESOURCE = {
73
+ id: 'attio-crm',
74
+ order: 30,
75
+ kind: 'integration' as const,
76
+ systemPath: 'sys.lead-gen',
77
+ ownerRoleId: 'role.sales-ops',
78
+ status: 'active' as const,
79
+ provider: 'attio'
80
+ }
81
+
82
+ const SCRIPT_RESOURCE = {
83
+ id: 'leadgen-backfill-script',
84
+ order: 40,
85
+ kind: 'script' as const,
86
+ systemPath: 'sys.lead-gen',
87
+ ownerRoleId: 'role.sales-ops',
88
+ status: 'active' as const,
89
+ language: 'typescript' as const,
90
+ source: {
91
+ file: 'scripts/leadgen/backfill.ts'
92
+ }
93
+ }
94
+
95
+ function resolveWithResources(resources: Record<string, unknown>) {
96
+ return resolveOrganizationModel({
97
+ roles: { 'role.sales-ops': VALID_ROLE },
98
+ systems: { 'sys.lead-gen': VALID_SYSTEM },
99
+ resources: resources as Record<string, typeof WORKFLOW_RESOURCE>
100
+ })
101
+ }
102
+
103
+ describe('ResourceEntrySchema', () => {
104
+ it('accepts workflow, agent, integration, and script descriptors with required systemPath', () => {
105
+ expect(ResourceEntrySchema.safeParse(WORKFLOW_RESOURCE).success).toBe(true)
106
+ expect(ResourceEntrySchema.safeParse(AGENT_RESOURCE).success).toBe(true)
107
+ expect(ResourceEntrySchema.safeParse(INTEGRATION_RESOURCE).success).toBe(true)
108
+ expect(ResourceEntrySchema.safeParse(SCRIPT_RESOURCE).success).toBe(true)
109
+ })
110
+
111
+ it('rejects resources without a systemPath', () => {
112
+ const { systemPath: _systemPath, ...resourceWithoutSystem } = WORKFLOW_RESOURCE
113
+
114
+ expect(ResourceEntrySchema.safeParse(resourceWithoutSystem).success).toBe(false)
115
+ })
116
+
117
+ it('defaults codeRefs and accepts resource-level implementation breadcrumbs', () => {
118
+ const withCodeRefs = ResourceEntrySchema.safeParse(WORKFLOW_RESOURCE)
119
+ const withoutCodeRefs = ResourceEntrySchema.safeParse({
120
+ ...WORKFLOW_RESOURCE,
121
+ codeRefs: undefined
122
+ })
123
+
124
+ expect(withCodeRefs.success).toBe(true)
125
+ expect(withoutCodeRefs.success).toBe(true)
126
+
127
+ if (withCodeRefs.success) {
128
+ expect(withCodeRefs.data.codeRefs).toEqual(WORKFLOW_RESOURCE.codeRefs)
129
+ }
130
+ if (withoutCodeRefs.success) {
131
+ expect(withoutCodeRefs.data.codeRefs).toEqual([])
132
+ }
133
+ })
134
+
135
+ it('rejects codeRefs with an empty path', () => {
136
+ expect(
137
+ ResourceEntrySchema.safeParse({
138
+ ...WORKFLOW_RESOURCE,
139
+ codeRefs: [
140
+ {
141
+ path: ' ',
142
+ role: 'entrypoint'
143
+ }
144
+ ]
145
+ }).success
146
+ ).toBe(false)
147
+ })
148
+
149
+ it('rejects codeRefs with an invalid role', () => {
150
+ expect(
151
+ ResourceEntrySchema.safeParse({
152
+ ...WORKFLOW_RESOURCE,
153
+ codeRefs: [
154
+ {
155
+ path: 'operations/src/lead-gen/company-scrape/index.ts',
156
+ role: 'runtime'
157
+ }
158
+ ]
159
+ }).success
160
+ ).toBe(false)
161
+ })
162
+
163
+ it('rejects multi-system membership', () => {
164
+ expect(
165
+ ResourceEntrySchema.safeParse({
166
+ ...WORKFLOW_RESOURCE,
167
+ systemPath: ['sys.lead-gen', 'sys.crm']
168
+ }).success
169
+ ).toBe(false)
170
+ })
171
+
172
+ it('rejects an agent kind outside the code-side mirror enum', () => {
173
+ expect(
174
+ ResourceEntrySchema.safeParse({
175
+ ...AGENT_RESOURCE,
176
+ agentKind: 'runner'
177
+ }).success
178
+ ).toBe(false)
179
+ })
180
+
181
+ it('defaults agent invocations and accepts slash-command orchestration entries', () => {
182
+ const result = ResourceEntrySchema.safeParse({
183
+ ...AGENT_RESOURCE,
184
+ invocations: undefined
185
+ })
186
+
187
+ expect(result.success).toBe(true)
188
+ if (result.success) {
189
+ expect(result.data.kind).toBe('agent')
190
+ if (result.data.kind === 'agent') {
191
+ expect(result.data.invocations).toEqual([])
192
+ }
193
+ }
194
+
195
+ expect(ResourceEntrySchema.safeParse(AGENT_RESOURCE).success).toBe(true)
196
+ })
197
+
198
+ it('rejects malformed agent invocation entries', () => {
199
+ expect(
200
+ ResourceEntrySchema.safeParse({
201
+ ...AGENT_RESOURCE,
202
+ invocations: [{ kind: 'slash-command', command: 'work handoff' }]
203
+ }).success
204
+ ).toBe(false)
205
+ })
206
+
205
207
  it('accepts event emissions on workflow and agent resources only', () => {
206
- const workflowResult = ResourceEntrySchema.safeParse({
207
- ...WORKFLOW_RESOURCE,
208
- emits: [WORKFLOW_EVENT_EMISSION]
209
- })
210
- const agentResult = ResourceEntrySchema.safeParse({
211
- ...AGENT_RESOURCE,
212
- emits: [{ eventKey: 'approved', label: 'Approved' }]
213
- })
214
- const integrationResult = ResourceEntrySchema.safeParse({
215
- ...INTEGRATION_RESOURCE,
216
- emits: [{ eventKey: 'received', label: 'Received' }]
217
- })
218
-
219
- expect(workflowResult.success).toBe(true)
220
- expect(agentResult.success).toBe(true)
221
- expect(integrationResult.success).toBe(true)
222
- if (workflowResult.success && workflowResult.data.kind === 'workflow') {
223
- expect(workflowResult.data.emits).toEqual([WORKFLOW_EVENT_EMISSION])
224
- }
225
- if (agentResult.success && agentResult.data.kind === 'agent') {
226
- expect(agentResult.data.emits).toEqual([{ eventKey: 'approved', label: 'Approved' }])
227
- }
228
- if (integrationResult.success && integrationResult.data.kind === 'integration') {
229
- expect('emits' in integrationResult.data).toBe(false)
208
+ const workflowResult = ResourceEntrySchema.safeParse({
209
+ ...WORKFLOW_RESOURCE,
210
+ emits: [WORKFLOW_EVENT_EMISSION]
211
+ })
212
+ const agentResult = ResourceEntrySchema.safeParse({
213
+ ...AGENT_RESOURCE,
214
+ emits: [{ eventKey: 'approved', label: 'Approved' }]
215
+ })
216
+ const integrationResult = ResourceEntrySchema.safeParse({
217
+ ...INTEGRATION_RESOURCE,
218
+ emits: [{ eventKey: 'received', label: 'Received' }]
219
+ })
220
+
221
+ expect(workflowResult.success).toBe(true)
222
+ expect(agentResult.success).toBe(true)
223
+ expect(integrationResult.success).toBe(true)
224
+ if (workflowResult.success && workflowResult.data.kind === 'workflow') {
225
+ expect(workflowResult.data.emits).toEqual([WORKFLOW_EVENT_EMISSION])
226
+ }
227
+ if (agentResult.success && agentResult.data.kind === 'agent') {
228
+ expect(agentResult.data.emits).toEqual([{ eventKey: 'approved', label: 'Approved' }])
229
+ }
230
+ if (integrationResult.success && integrationResult.data.kind === 'integration') {
231
+ expect('emits' in integrationResult.data).toBe(false)
230
232
  }
231
233
  })
232
234
 
@@ -285,136 +287,281 @@ describe('ResourceEntrySchema', () => {
285
287
  })
286
288
 
287
289
  it('validates derived event id format', () => {
288
- expect(EventIdSchema.parse('crm.deal:won')).toBe('crm.deal:won')
289
- expect(EventIdSchema.parse('LGN-01-company-scrape:processed')).toBe('LGN-01-company-scrape:processed')
290
- expect(() => EventIdSchema.parse('crm.deal.won')).toThrow()
291
- })
292
- })
293
-
294
- describe('ResourcesDomainSchema', () => {
295
- it('defaults resources to an empty record when omitted', () => {
296
- const result = ResourcesDomainSchema.safeParse({})
297
-
298
- expect(result.success).toBe(true)
299
- if (result.success) {
300
- expect(result.data).toEqual(DEFAULT_ORGANIZATION_MODEL_RESOURCES)
301
- }
302
- })
303
-
304
- it.each(['workflow', 'agent', 'integration', 'script'] as const)('accepts kind "%s"', (kind) => {
305
- expect(ResourceKindSchema.safeParse(kind).success).toBe(true)
306
- })
307
- })
308
-
309
- describe('resolveOrganizationModel - resources domain integration', () => {
310
- it('accepts valid resources with system and role references', () => {
311
- const model = resolveWithResources({
312
- 'LGN-01-company-scrape': WORKFLOW_RESOURCE,
313
- 'command-center-assistant': AGENT_RESOURCE,
314
- 'attio-crm': INTEGRATION_RESOURCE,
315
- 'leadgen-backfill-script': SCRIPT_RESOURCE
316
- })
317
-
318
- expect(Object.keys(model.resources)).toHaveLength(4)
319
- })
320
-
321
- it('throws when a resource entry id does not match its map key', () => {
322
- expect(() =>
323
- resolveWithResources({
324
- 'LGN-01-company-scrape': WORKFLOW_RESOURCE,
325
- 'wrong-key': {
326
- ...WORKFLOW_RESOURCE,
327
- id: 'LGN-01-company-scrape'
328
- }
329
- })
330
- ).toThrow()
331
- })
332
-
333
- it('throws when systemPath references an unknown system', () => {
334
- expect(() =>
335
- resolveWithResources({
336
- 'LGN-01-company-scrape': {
337
- ...WORKFLOW_RESOURCE,
338
- systemPath: 'sys.missing'
339
- }
340
- })
341
- ).toThrow(/unknown system path \\"sys\.missing\\"/)
342
- })
343
-
344
- it('reports a dangling resource systemPath on the resource systemPath issue path', () => {
345
- let error: unknown
346
-
347
- try {
348
- resolveWithResources({
349
- 'LGN-01-company-scrape': {
350
- ...WORKFLOW_RESOURCE,
351
- systemPath: 'sys.missing'
352
- }
353
- })
354
- } catch (caught) {
355
- error = caught
356
- }
357
-
358
- expect(error).toBeInstanceOf(ZodError)
359
- if (!(error instanceof ZodError)) {
360
- throw new Error('Expected resolveOrganizationModel to throw a ZodError')
361
- }
362
-
363
- expect(error.issues).toEqual(
364
- expect.arrayContaining([
365
- expect.objectContaining({
366
- path: ['resources', 'LGN-01-company-scrape', 'systemPath']
367
- })
368
- ])
369
- )
370
- })
371
-
372
- it('throws when ownerRoleId references an unknown role', () => {
373
- expect(() =>
374
- resolveWithResources({
375
- 'LGN-01-company-scrape': {
376
- ...WORKFLOW_RESOURCE,
377
- ownerRoleId: 'role.missing'
378
- }
379
- })
380
- ).toThrow(/unknown ownerRoleId \\"role\.missing\\"/)
381
- })
382
-
383
- it('throws when agent actsAsRoleId references an unknown role', () => {
384
- expect(() =>
385
- resolveWithResources({
386
- 'command-center-assistant': {
387
- ...AGENT_RESOURCE,
388
- actsAsRoleId: 'role.missing'
389
- }
390
- })
391
- ).toThrow(/unknown actsAsRoleId \\"role\.missing\\"/)
392
- })
393
- })
394
-
395
- describe('descriptor helper contract', () => {
396
- it('preserves typed descriptor exports through defineResource and defineResources', () => {
397
- const workflow = defineResource(WORKFLOW_RESOURCE)
398
- const resources = defineResources({
399
- companyScrape: WORKFLOW_RESOURCE,
400
- commandCenterAssistant: AGENT_RESOURCE
401
- })
402
-
403
- expect(workflow.id).toBe('LGN-01-company-scrape')
404
- expect(resources.commandCenterAssistant.agentKind).toBe('platform')
405
- })
406
-
407
- it('derives runtime resourceId and type from the descriptor', () => {
408
- const bound = bindResourceDescriptor({
409
- resource: WORKFLOW_RESOURCE,
410
- name: 'Company Scrape',
411
- description: 'Scrapes company data for lead generation.',
412
- version: '1.0.0',
413
- status: 'prod'
414
- })
415
-
416
- expect(bound.resourceId).toBe('LGN-01-company-scrape')
417
- expect(bound.type).toBe('workflow')
418
- expect(bound.resource).toBe(WORKFLOW_RESOURCE)
419
- })
420
- })
290
+ expect(EventIdSchema.parse('crm.deal:won')).toBe('crm.deal:won')
291
+ expect(EventIdSchema.parse('LGN-01-company-scrape:processed')).toBe('LGN-01-company-scrape:processed')
292
+ expect(() => EventIdSchema.parse('crm.deal.won')).toThrow()
293
+ })
294
+ })
295
+
296
+ describe('ResourcesDomainSchema', () => {
297
+ it('defaults resources to an empty record when omitted', () => {
298
+ const result = ResourcesDomainSchema.safeParse({})
299
+
300
+ expect(result.success).toBe(true)
301
+ if (result.success) {
302
+ expect(result.data).toEqual(DEFAULT_ORGANIZATION_MODEL_RESOURCES)
303
+ }
304
+ })
305
+
306
+ it.each(['workflow', 'agent', 'integration', 'script'] as const)('accepts kind "%s"', (kind) => {
307
+ expect(ResourceKindSchema.safeParse(kind).success).toBe(true)
308
+ })
309
+ })
310
+
311
+ describe('resolveOrganizationModel - resources domain integration', () => {
312
+ it('accepts valid resources with system and role references', () => {
313
+ const model = resolveWithResources({
314
+ 'LGN-01-company-scrape': WORKFLOW_RESOURCE,
315
+ 'command-center-assistant': AGENT_RESOURCE,
316
+ 'attio-crm': INTEGRATION_RESOURCE,
317
+ 'leadgen-backfill-script': SCRIPT_RESOURCE
318
+ })
319
+
320
+ expect(Object.keys(model.resources)).toHaveLength(4)
321
+ })
322
+
323
+ it('throws when a resource entry id does not match its map key', () => {
324
+ expect(() =>
325
+ resolveWithResources({
326
+ 'LGN-01-company-scrape': WORKFLOW_RESOURCE,
327
+ 'wrong-key': {
328
+ ...WORKFLOW_RESOURCE,
329
+ id: 'LGN-01-company-scrape'
330
+ }
331
+ })
332
+ ).toThrow()
333
+ })
334
+
335
+ it('throws when systemPath references an unknown system', () => {
336
+ expect(() =>
337
+ resolveWithResources({
338
+ 'LGN-01-company-scrape': {
339
+ ...WORKFLOW_RESOURCE,
340
+ systemPath: 'sys.missing'
341
+ }
342
+ })
343
+ ).toThrow(/unknown system path \\"sys\.missing\\"/)
344
+ })
345
+
346
+ it('reports a dangling resource systemPath on the resource systemPath issue path', () => {
347
+ let error: unknown
348
+
349
+ try {
350
+ resolveWithResources({
351
+ 'LGN-01-company-scrape': {
352
+ ...WORKFLOW_RESOURCE,
353
+ systemPath: 'sys.missing'
354
+ }
355
+ })
356
+ } catch (caught) {
357
+ error = caught
358
+ }
359
+
360
+ expect(error).toBeInstanceOf(ZodError)
361
+ if (!(error instanceof ZodError)) {
362
+ throw new Error('Expected resolveOrganizationModel to throw a ZodError')
363
+ }
364
+
365
+ expect(error.issues).toEqual(
366
+ expect.arrayContaining([
367
+ expect.objectContaining({
368
+ path: ['resources', 'LGN-01-company-scrape', 'systemPath']
369
+ })
370
+ ])
371
+ )
372
+ })
373
+
374
+ it('throws when ownerRoleId references an unknown role', () => {
375
+ expect(() =>
376
+ resolveWithResources({
377
+ 'LGN-01-company-scrape': {
378
+ ...WORKFLOW_RESOURCE,
379
+ ownerRoleId: 'role.missing'
380
+ }
381
+ })
382
+ ).toThrow(/unknown ownerRoleId \\"role\.missing\\"/)
383
+ })
384
+
385
+ it('throws when agent actsAsRoleId references an unknown role', () => {
386
+ expect(() =>
387
+ resolveWithResources({
388
+ 'command-center-assistant': {
389
+ ...AGENT_RESOURCE,
390
+ actsAsRoleId: 'role.missing'
391
+ }
392
+ })
393
+ ).toThrow(/unknown actsAsRoleId \\"role\.missing\\"/)
394
+ })
395
+ })
396
+
397
+ describe('descriptor helper contract', () => {
398
+ it('preserves typed descriptor exports through defineResource and defineResources', () => {
399
+ const workflow = defineResource(WORKFLOW_RESOURCE)
400
+ const resources = defineResources({
401
+ companyScrape: WORKFLOW_RESOURCE,
402
+ commandCenterAssistant: AGENT_RESOURCE
403
+ })
404
+
405
+ expect(workflow.id).toBe('LGN-01-company-scrape')
406
+ expect(resources.commandCenterAssistant.agentKind).toBe('platform')
407
+ })
408
+
409
+ it('derives runtime resourceId and type from the descriptor', () => {
410
+ const bound = bindResourceDescriptor({
411
+ resource: WORKFLOW_RESOURCE,
412
+ name: 'Company Scrape',
413
+ description: 'Scrapes company data for lead generation.',
414
+ version: '1.0.0',
415
+ status: 'prod'
416
+ })
417
+
418
+ expect(bound.resourceId).toBe('LGN-01-company-scrape')
419
+ expect(bound.type).toBe('workflow')
420
+ expect(bound.resource).toBe(WORKFLOW_RESOURCE)
421
+ })
422
+ })
423
+
424
+ describe('ContractRefSchema — ref string shape', () => {
425
+ it('accepts valid package/subpath#ExportName refs', () => {
426
+ expect(ContractRefSchema.safeParse('@repo/elevasis-core/contracts/apollo-import#inputSchema').success).toBe(true)
427
+ expect(
428
+ ContractRefSchema.safeParse('@repo/elevasis-core/contracts/dtc-subscription-score#outputSchema').success
429
+ ).toBe(true)
430
+ expect(ContractRefSchema.safeParse('my-package/sub/path#MySchema').success).toBe(true)
431
+ expect(ContractRefSchema.safeParse('pkg#schema').success).toBe(true)
432
+ })
433
+
434
+ it('rejects refs without a #ExportName suffix', () => {
435
+ expect(ContractRefSchema.safeParse('@repo/elevasis-core/contracts/apollo-import').success).toBe(false)
436
+ expect(ContractRefSchema.safeParse('pkg/sub').success).toBe(false)
437
+ })
438
+
439
+ it('rejects refs with an empty export name after #', () => {
440
+ expect(ContractRefSchema.safeParse('@repo/elevasis-core/contracts/apollo-import#').success).toBe(false)
441
+ })
442
+
443
+ it('rejects empty strings', () => {
444
+ expect(ContractRefSchema.safeParse('').success).toBe(false)
445
+ })
446
+ })
447
+
448
+ describe('parseContractRef — browser-safe parser', () => {
449
+ it('parses a valid ref into moduleSpecifier and exportName', () => {
450
+ const result = parseContractRef('@repo/elevasis-core/contracts/apollo-import#inputSchema')
451
+ expect(result.moduleSpecifier).toBe('@repo/elevasis-core/contracts/apollo-import')
452
+ expect(result.exportName).toBe('inputSchema')
453
+ })
454
+
455
+ it('uses lastIndexOf so a # in the module specifier (unusual but valid) is handled correctly', () => {
456
+ const result = parseContractRef('pkg/sub#Export#actualExport')
457
+ expect(result.moduleSpecifier).toBe('pkg/sub#Export')
458
+ expect(result.exportName).toBe('actualExport')
459
+ })
460
+
461
+ it('throws on a ref without #', () => {
462
+ expect(() => parseContractRef('pkg/no-hash')).toThrow(/missing the required/)
463
+ })
464
+
465
+ it('throws on a ref with empty export name', () => {
466
+ expect(() => parseContractRef('pkg/sub#')).toThrow(/empty export name/)
467
+ })
468
+ })
469
+
470
+ describe('ResourceOntologyBindingSchema — contract field', () => {
471
+ it('accepts a binding without a contract field (backward compat)', () => {
472
+ expect(
473
+ ResourceOntologyBindingSchema.safeParse({
474
+ actions: ['sys.lead-gen:action/company.scrape']
475
+ }).success
476
+ ).toBe(true)
477
+ })
478
+
479
+ it('accepts a binding with a valid contract.input ref', () => {
480
+ expect(
481
+ ResourceOntologyBindingSchema.safeParse({
482
+ contract: {
483
+ input: '@repo/elevasis-core/contracts/apollo-import#inputSchema'
484
+ }
485
+ }).success
486
+ ).toBe(true)
487
+ })
488
+
489
+ it('accepts a binding with both contract.input and contract.output refs', () => {
490
+ expect(
491
+ ResourceOntologyBindingSchema.safeParse({
492
+ contract: {
493
+ input: '@repo/elevasis-core/contracts/dtc-subscription-score#inputSchema',
494
+ output: '@repo/elevasis-core/contracts/dtc-subscription-score#outputSchema'
495
+ }
496
+ }).success
497
+ ).toBe(true)
498
+ })
499
+
500
+ it('accepts a binding with an empty contract object (both sides optional)', () => {
501
+ expect(
502
+ ResourceOntologyBindingSchema.safeParse({
503
+ contract: {}
504
+ }).success
505
+ ).toBe(true)
506
+ })
507
+
508
+ it('rejects a malformed contract.input ref (missing #ExportName)', () => {
509
+ expect(
510
+ ResourceOntologyBindingSchema.safeParse({
511
+ contract: {
512
+ input: '@repo/elevasis-core/contracts/apollo-import'
513
+ }
514
+ }).success
515
+ ).toBe(false)
516
+ })
517
+
518
+ it('rejects a malformed contract.output ref (missing #ExportName)', () => {
519
+ expect(
520
+ ResourceOntologyBindingSchema.safeParse({
521
+ contract: {
522
+ output: 'not-a-valid-ref'
523
+ }
524
+ }).success
525
+ ).toBe(false)
526
+ })
527
+ })
528
+
529
+ describe('resolveOrganizationModel — contract ref Tier-1 shape validation', () => {
530
+ it('accepts a resource with a valid contract binding', () => {
531
+ const model = resolveWithResources({
532
+ 'LGN-01-company-scrape': {
533
+ ...WORKFLOW_RESOURCE,
534
+ ontology: {
535
+ contract: {
536
+ input: '@repo/elevasis-core/contracts/apollo-import#inputSchema'
537
+ }
538
+ }
539
+ }
540
+ })
541
+ expect(model.resources['LGN-01-company-scrape']?.ontology?.contract?.input).toBe(
542
+ '@repo/elevasis-core/contracts/apollo-import#inputSchema'
543
+ )
544
+ })
545
+
546
+ it('rejects a resource with a malformed contract.input ref', () => {
547
+ expect(() =>
548
+ resolveWithResources({
549
+ 'LGN-01-company-scrape': {
550
+ ...WORKFLOW_RESOURCE,
551
+ ontology: {
552
+ contract: {
553
+ input: 'bad-ref-no-hash'
554
+ }
555
+ }
556
+ }
557
+ })
558
+ ).toThrow()
559
+ })
560
+
561
+ it('leaves resources without contract binding unchanged (additive + optional)', () => {
562
+ const model = resolveWithResources({
563
+ 'LGN-01-company-scrape': WORKFLOW_RESOURCE
564
+ })
565
+ expect(model.resources['LGN-01-company-scrape']?.ontology).toBeUndefined()
566
+ })
567
+ })