@elevasis/core 0.22.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2330 -2391
- package/dist/index.js +2322 -1147
- package/dist/knowledge/index.d.ts +702 -1136
- package/dist/knowledge/index.js +9 -9
- package/dist/organization-model/index.d.ts +2330 -2391
- package/dist/organization-model/index.js +2322 -1147
- package/dist/test-utils/index.d.ts +703 -1106
- package/dist/test-utils/index.js +1735 -1089
- package/package.json +1 -1
- package/src/__tests__/template-core-compatibility.test.ts +11 -79
- package/src/_gen/__tests__/__snapshots__/contracts.md.snap +360 -98
- package/src/business/acquisition/api-schemas.test.ts +2 -2
- package/src/business/acquisition/api-schemas.ts +7 -9
- package/src/business/acquisition/build-templates.test.ts +4 -4
- package/src/business/acquisition/build-templates.ts +72 -30
- package/src/business/acquisition/crm-state-actions.test.ts +13 -11
- package/src/business/acquisition/types.ts +7 -3
- package/src/execution/engine/agent/core/types.ts +1 -1
- package/src/execution/engine/workflow/types.ts +2 -2
- package/src/knowledge/README.md +8 -7
- package/src/knowledge/__tests__/queries.test.ts +74 -73
- package/src/knowledge/format.ts +10 -9
- package/src/knowledge/index.ts +1 -1
- package/src/knowledge/published.ts +1 -1
- package/src/knowledge/queries.ts +26 -25
- package/src/organization-model/README.md +66 -26
- package/src/organization-model/__tests__/content-kinds-registry.test.ts +210 -0
- package/src/organization-model/__tests__/defaults.test.ts +72 -98
- package/src/organization-model/__tests__/domains/actions.test.ts +56 -0
- package/src/organization-model/__tests__/domains/customers.test.ts +299 -295
- package/src/organization-model/__tests__/domains/entities.test.ts +56 -0
- package/src/organization-model/__tests__/domains/goals.test.ts +493 -479
- package/src/organization-model/__tests__/domains/identity.test.ts +280 -279
- package/src/organization-model/__tests__/domains/navigation.test.ts +268 -212
- package/src/organization-model/__tests__/domains/offerings.test.ts +414 -419
- package/src/organization-model/__tests__/domains/policies.test.ts +323 -0
- package/src/organization-model/__tests__/domains/resource-mappings.test.ts +271 -271
- package/src/organization-model/__tests__/domains/resources.test.ts +159 -37
- package/src/organization-model/__tests__/domains/roles.test.ts +147 -86
- package/src/organization-model/__tests__/domains/statuses.test.ts +246 -243
- package/src/organization-model/__tests__/domains/systems.test.ts +67 -51
- package/src/organization-model/__tests__/flatten-additive-merge.test.ts +361 -0
- package/src/organization-model/__tests__/foundation.test.ts +74 -102
- package/src/organization-model/__tests__/get-resources-for-system.test.ts +144 -0
- package/src/organization-model/__tests__/graph.test.ts +899 -71
- package/src/organization-model/__tests__/knowledge.test.ts +173 -52
- package/src/organization-model/__tests__/lookup-helpers.test.ts +438 -0
- package/src/organization-model/__tests__/migration-helpers.test.ts +591 -0
- package/src/organization-model/__tests__/prospecting-ssot.test.ts +36 -27
- package/src/organization-model/__tests__/recursive-system-schema.test.ts +520 -0
- package/src/organization-model/__tests__/resolve.test.ts +174 -23
- package/src/organization-model/__tests__/schema.test.ts +291 -114
- package/src/organization-model/__tests__/surface-projection.test.ts +207 -97
- package/src/organization-model/catalogs/lead-gen.ts +144 -0
- package/src/organization-model/content-kinds/config.ts +36 -0
- package/src/organization-model/content-kinds/index.ts +74 -0
- package/src/organization-model/content-kinds/pipeline.ts +68 -0
- package/src/organization-model/content-kinds/registry.ts +44 -0
- package/src/organization-model/content-kinds/status.ts +71 -0
- package/src/organization-model/content-kinds/template.ts +83 -0
- package/src/organization-model/content-kinds/types.ts +117 -0
- package/src/organization-model/contracts.ts +13 -3
- package/src/organization-model/defaults.ts +488 -96
- package/src/organization-model/domains/actions.ts +239 -0
- package/src/organization-model/domains/customers.ts +78 -75
- package/src/organization-model/domains/entities.ts +144 -0
- package/src/organization-model/domains/goals.ts +83 -80
- package/src/organization-model/domains/knowledge.ts +74 -16
- package/src/organization-model/domains/navigation.ts +107 -384
- package/src/organization-model/domains/offerings.ts +71 -66
- package/src/organization-model/domains/policies.ts +102 -0
- package/src/organization-model/domains/projects.ts +14 -48
- package/src/organization-model/domains/prospecting.ts +62 -181
- package/src/organization-model/domains/resources.ts +81 -24
- package/src/organization-model/domains/roles.ts +13 -10
- package/src/organization-model/domains/sales.ts +10 -219
- package/src/organization-model/domains/shared.ts +57 -57
- package/src/organization-model/domains/statuses.ts +339 -130
- package/src/organization-model/domains/systems.ts +186 -29
- package/src/organization-model/foundation.ts +54 -67
- package/src/organization-model/graph/build.ts +682 -54
- package/src/organization-model/graph/link.ts +1 -1
- package/src/organization-model/graph/schema.ts +24 -9
- package/src/organization-model/graph/types.ts +20 -7
- package/src/organization-model/helpers.ts +231 -26
- package/src/organization-model/index.ts +116 -5
- package/src/organization-model/migration-helpers.ts +249 -0
- package/src/organization-model/organization-graph.mdx +16 -15
- package/src/organization-model/organization-model.mdx +89 -41
- package/src/organization-model/published.ts +120 -18
- package/src/organization-model/resolve.ts +117 -54
- package/src/organization-model/schema.ts +561 -140
- package/src/organization-model/surface-projection.ts +116 -122
- package/src/organization-model/types.ts +102 -21
- package/src/platform/constants/versions.ts +1 -1
- package/src/platform/registry/__tests__/command-view.test.ts +6 -8
- package/src/platform/registry/__tests__/resource-link.test.ts +13 -8
- package/src/platform/registry/__tests__/resource-registry.integration.test.ts +16 -31
- package/src/platform/registry/__tests__/resource-registry.nested-systems.test.ts +245 -0
- package/src/platform/registry/__tests__/resource-registry.test.ts +9 -7
- package/src/platform/registry/__tests__/validation.test.ts +15 -11
- package/src/platform/registry/resource-registry.ts +20 -8
- package/src/platform/registry/serialization.ts +7 -7
- package/src/platform/registry/types.ts +3 -3
- package/src/platform/registry/validation.ts +17 -15
- package/src/reference/_generated/contracts.md +362 -99
- package/src/reference/glossary.md +18 -18
- package/src/supabase/database.types.ts +60 -0
- package/src/test-utils/test-utils.test.ts +1 -6
- package/src/organization-model/__tests__/domains/operations.test.ts +0 -203
- package/src/organization-model/domains/features.ts +0 -31
- package/src/organization-model/domains/operations.ts +0 -85
|
@@ -13,6 +13,7 @@ describe('RoleSchema - positive parse', () => {
|
|
|
13
13
|
it('accepts a fully-populated role', () => {
|
|
14
14
|
const result = RoleSchema.safeParse({
|
|
15
15
|
id: 'role-ceo',
|
|
16
|
+
order: 10,
|
|
16
17
|
title: 'CEO',
|
|
17
18
|
responsibilities: ['Set company direction', 'Hire and develop leadership team'],
|
|
18
19
|
reportsToId: undefined,
|
|
@@ -23,8 +24,8 @@ describe('RoleSchema - positive parse', () => {
|
|
|
23
24
|
expect(result.success).toBe(true)
|
|
24
25
|
})
|
|
25
26
|
|
|
26
|
-
it('accepts a minimal role - only id and title required', () => {
|
|
27
|
-
const result = RoleSchema.safeParse({ id: 'role-minimal', title: 'Head of Sales' })
|
|
27
|
+
it('accepts a minimal role - only id, order, and title required', () => {
|
|
28
|
+
const result = RoleSchema.safeParse({ id: 'role-minimal', order: 10, title: 'Head of Sales' })
|
|
28
29
|
|
|
29
30
|
expect(result.success).toBe(true)
|
|
30
31
|
if (result.success) {
|
|
@@ -39,23 +40,33 @@ describe('RoleSchema - positive parse', () => {
|
|
|
39
40
|
|
|
40
41
|
it('accepts human, agent, team, and multi-holder variants', () => {
|
|
41
42
|
expect(
|
|
42
|
-
RoleSchema.safeParse({
|
|
43
|
-
|
|
43
|
+
RoleSchema.safeParse({
|
|
44
|
+
id: 'role-human',
|
|
45
|
+
order: 10,
|
|
46
|
+
title: 'Human',
|
|
47
|
+
heldBy: { kind: 'human', userId: 'user.alice' }
|
|
48
|
+
}).success
|
|
44
49
|
).toBe(true)
|
|
45
50
|
expect(
|
|
46
51
|
RoleSchema.safeParse({
|
|
47
52
|
id: 'role-agent',
|
|
53
|
+
order: 10,
|
|
48
54
|
title: 'Agent',
|
|
49
55
|
heldBy: { kind: 'agent', agentId: 'command-center-assistant' }
|
|
50
56
|
}).success
|
|
51
57
|
).toBe(true)
|
|
52
58
|
expect(
|
|
53
|
-
RoleSchema.safeParse({
|
|
54
|
-
|
|
59
|
+
RoleSchema.safeParse({
|
|
60
|
+
id: 'role-team',
|
|
61
|
+
order: 10,
|
|
62
|
+
title: 'Team',
|
|
63
|
+
heldBy: { kind: 'team', memberIds: ['user.alice'] }
|
|
64
|
+
}).success
|
|
55
65
|
).toBe(true)
|
|
56
66
|
expect(
|
|
57
67
|
RoleSchema.safeParse({
|
|
58
68
|
id: 'role-multi',
|
|
69
|
+
order: 10,
|
|
59
70
|
title: 'Multi',
|
|
60
71
|
heldBy: [
|
|
61
72
|
{ kind: 'human', userId: 'user.alice' },
|
|
@@ -68,6 +79,7 @@ describe('RoleSchema - positive parse', () => {
|
|
|
68
79
|
it('trims whitespace from id and title', () => {
|
|
69
80
|
const result = RoleSchema.safeParse({
|
|
70
81
|
id: ' role-trim ',
|
|
82
|
+
order: 10,
|
|
71
83
|
title: ' Trimmed Title '
|
|
72
84
|
})
|
|
73
85
|
|
|
@@ -81,7 +93,7 @@ describe('RoleSchema - positive parse', () => {
|
|
|
81
93
|
|
|
82
94
|
describe('RoleSchema - default values', () => {
|
|
83
95
|
it('responsibilities defaults to empty array when omitted', () => {
|
|
84
|
-
const result = RoleSchema.safeParse({ id: 'role-defaults', title: 'Engineer' })
|
|
96
|
+
const result = RoleSchema.safeParse({ id: 'role-defaults', order: 10, title: 'Engineer' })
|
|
85
97
|
|
|
86
98
|
expect(result.success).toBe(true)
|
|
87
99
|
if (result.success) {
|
|
@@ -90,7 +102,7 @@ describe('RoleSchema - default values', () => {
|
|
|
90
102
|
})
|
|
91
103
|
|
|
92
104
|
it('reportsToId, heldBy, and responsibleFor are optional', () => {
|
|
93
|
-
const result = RoleSchema.safeParse({ id: 'role-defaults', title: 'Engineer' })
|
|
105
|
+
const result = RoleSchema.safeParse({ id: 'role-defaults', order: 10, title: 'Engineer' })
|
|
94
106
|
|
|
95
107
|
expect(result.success).toBe(true)
|
|
96
108
|
if (result.success) {
|
|
@@ -104,16 +116,17 @@ describe('RoleSchema - default values', () => {
|
|
|
104
116
|
describe('RoleSchema - negative parse', () => {
|
|
105
117
|
it('rejects missing or invalid required fields', () => {
|
|
106
118
|
expect(RoleSchema.safeParse({ title: 'No ID Role' }).success).toBe(false)
|
|
107
|
-
expect(RoleSchema.safeParse({ id: '', title: 'Empty ID' }).success).toBe(false)
|
|
108
|
-
expect(RoleSchema.safeParse({ id: ' ', title: 'Whitespace ID' }).success).toBe(false)
|
|
109
|
-
expect(RoleSchema.safeParse({ id: 'role-no-title' }).success).toBe(false)
|
|
110
|
-
expect(RoleSchema.safeParse({ id: 'role-empty-title', title: '' }).success).toBe(false)
|
|
111
|
-
expect(RoleSchema.safeParse({ id: 'role-whitespace-title', title: ' ' }).success).toBe(false)
|
|
119
|
+
expect(RoleSchema.safeParse({ id: '', order: 10, title: 'Empty ID' }).success).toBe(false)
|
|
120
|
+
expect(RoleSchema.safeParse({ id: ' ', order: 10, title: 'Whitespace ID' }).success).toBe(false)
|
|
121
|
+
expect(RoleSchema.safeParse({ id: 'role-no-title', order: 10 }).success).toBe(false)
|
|
122
|
+
expect(RoleSchema.safeParse({ id: 'role-empty-title', order: 10, title: '' }).success).toBe(false)
|
|
123
|
+
expect(RoleSchema.safeParse({ id: 'role-whitespace-title', order: 10, title: ' ' }).success).toBe(false)
|
|
112
124
|
})
|
|
113
125
|
|
|
114
126
|
it('rejects responsibilities as a non-array value', () => {
|
|
115
127
|
const result = RoleSchema.safeParse({
|
|
116
128
|
id: 'role-bad-resp',
|
|
129
|
+
order: 10,
|
|
117
130
|
title: 'Bad Role',
|
|
118
131
|
responsibilities: 'single string'
|
|
119
132
|
})
|
|
@@ -122,14 +135,20 @@ describe('RoleSchema - negative parse', () => {
|
|
|
122
135
|
})
|
|
123
136
|
|
|
124
137
|
it('rejects legacy string heldBy values and invalid holders', () => {
|
|
125
|
-
expect(RoleSchema.safeParse({ id: 'role-legacy-holder', title: 'Legacy Holder', heldBy: 'Alice' }).success).toBe(
|
|
126
|
-
false
|
|
127
|
-
)
|
|
128
138
|
expect(
|
|
129
|
-
RoleSchema.safeParse({ id: 'role-
|
|
130
|
-
|
|
139
|
+
RoleSchema.safeParse({ id: 'role-legacy-holder', order: 10, title: 'Legacy Holder', heldBy: 'Alice' }).success
|
|
140
|
+
).toBe(false)
|
|
141
|
+
expect(
|
|
142
|
+
RoleSchema.safeParse({
|
|
143
|
+
id: 'role-empty-team',
|
|
144
|
+
order: 10,
|
|
145
|
+
title: 'Empty Team',
|
|
146
|
+
heldBy: { kind: 'team', memberIds: [] }
|
|
147
|
+
}).success
|
|
148
|
+
).toBe(false)
|
|
149
|
+
expect(
|
|
150
|
+
RoleSchema.safeParse({ id: 'role-empty-holders', order: 10, title: 'Empty Holders', heldBy: [] }).success
|
|
131
151
|
).toBe(false)
|
|
132
|
-
expect(RoleSchema.safeParse({ id: 'role-empty-holders', title: 'Empty Holders', heldBy: [] }).success).toBe(false)
|
|
133
152
|
})
|
|
134
153
|
})
|
|
135
154
|
|
|
@@ -149,6 +168,7 @@ describe('RoleSchema - plain-language field names (no EOS jargon)', () => {
|
|
|
149
168
|
it('parsed role has the plain-language keys title / responsibilities / reportsToId / heldBy / responsibleFor', () => {
|
|
150
169
|
const result = RoleSchema.safeParse({
|
|
151
170
|
id: 'role-plain',
|
|
171
|
+
order: 10,
|
|
152
172
|
title: 'Product Lead',
|
|
153
173
|
responsibilities: ['Own roadmap'],
|
|
154
174
|
reportsToId: 'role-ceo',
|
|
@@ -173,35 +193,37 @@ describe('RoleSchema - plain-language field names (no EOS jargon)', () => {
|
|
|
173
193
|
})
|
|
174
194
|
|
|
175
195
|
describe('RolesDomainSchema - structural', () => {
|
|
176
|
-
it('accepts an empty roles
|
|
177
|
-
expect(RolesDomainSchema.safeParse({
|
|
196
|
+
it('accepts an empty roles record', () => {
|
|
197
|
+
expect(RolesDomainSchema.safeParse({}).success).toBe(true)
|
|
178
198
|
})
|
|
179
199
|
|
|
180
|
-
it('defaults roles to empty
|
|
200
|
+
it('defaults roles to empty record when omitted', () => {
|
|
181
201
|
const result = RolesDomainSchema.safeParse({})
|
|
182
202
|
|
|
183
203
|
expect(result.success).toBe(true)
|
|
184
204
|
if (result.success) {
|
|
185
|
-
expect(result.data
|
|
205
|
+
expect(result.data).toEqual({})
|
|
186
206
|
}
|
|
187
207
|
})
|
|
188
208
|
|
|
189
209
|
it('accepts multiple valid roles', () => {
|
|
190
210
|
const result = RolesDomainSchema.safeParse({
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
{ id: 'role-b', title: 'COO', reportsToId: 'role-a' }
|
|
194
|
-
]
|
|
211
|
+
'role-a': { id: 'role-a', order: 10, title: 'CEO' },
|
|
212
|
+
'role-b': { id: 'role-b', order: 20, title: 'COO', reportsToId: 'role-a' }
|
|
195
213
|
})
|
|
196
214
|
|
|
197
215
|
expect(result.success).toBe(true)
|
|
198
216
|
if (result.success) {
|
|
199
|
-
expect(result.data
|
|
217
|
+
expect(Object.keys(result.data)).toHaveLength(2)
|
|
200
218
|
}
|
|
201
219
|
})
|
|
202
220
|
|
|
203
|
-
it('rejects
|
|
204
|
-
expect(
|
|
221
|
+
it('rejects a record where entry id does not match map key', () => {
|
|
222
|
+
expect(
|
|
223
|
+
RolesDomainSchema.safeParse({
|
|
224
|
+
'role-a': { id: 'role-b', order: 10, title: 'Mismatched' }
|
|
225
|
+
}).success
|
|
226
|
+
).toBe(false)
|
|
205
227
|
})
|
|
206
228
|
|
|
207
229
|
it('DEFAULT_ORGANIZATION_MODEL_ROLES constant matches schema parse of empty object', () => {
|
|
@@ -219,10 +241,8 @@ describe('resolveOrganizationModel - roles cross-ref (reportsToId)', () => {
|
|
|
219
241
|
expect(() =>
|
|
220
242
|
resolveOrganizationModel({
|
|
221
243
|
roles: {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
{ id: 'role-coo', title: 'COO', reportsToId: 'role-ceo' }
|
|
225
|
-
]
|
|
244
|
+
'role-ceo': { id: 'role-ceo', order: 10, title: 'CEO' },
|
|
245
|
+
'role-coo': { id: 'role-coo', order: 20, title: 'COO', reportsToId: 'role-ceo' }
|
|
226
246
|
}
|
|
227
247
|
})
|
|
228
248
|
).not.toThrow()
|
|
@@ -232,7 +252,7 @@ describe('resolveOrganizationModel - roles cross-ref (reportsToId)', () => {
|
|
|
232
252
|
expect(() =>
|
|
233
253
|
resolveOrganizationModel({
|
|
234
254
|
roles: {
|
|
235
|
-
|
|
255
|
+
'role-orphan': { id: 'role-orphan', order: 10, title: 'Orphan Role', reportsToId: 'nonexistent-role' }
|
|
236
256
|
}
|
|
237
257
|
})
|
|
238
258
|
).toThrow()
|
|
@@ -242,27 +262,50 @@ describe('resolveOrganizationModel - roles cross-ref (reportsToId)', () => {
|
|
|
242
262
|
expect(() =>
|
|
243
263
|
resolveOrganizationModel({
|
|
244
264
|
roles: {
|
|
245
|
-
|
|
265
|
+
'role-bad-ref': { id: 'role-bad-ref', order: 10, title: 'Bad Ref Role', reportsToId: 'ghost-role' }
|
|
246
266
|
}
|
|
247
267
|
})
|
|
248
268
|
).toThrow(/ghost-role/)
|
|
249
269
|
})
|
|
250
270
|
|
|
251
|
-
it('passes when reportsToId is absent or roles
|
|
271
|
+
it('passes when reportsToId is absent or roles record is empty', () => {
|
|
252
272
|
expect(() =>
|
|
253
273
|
resolveOrganizationModel({
|
|
254
274
|
roles: {
|
|
255
|
-
|
|
275
|
+
'role-top': { id: 'role-top', order: 10, title: 'Top Level Role' }
|
|
256
276
|
}
|
|
257
277
|
})
|
|
258
278
|
).not.toThrow()
|
|
259
|
-
expect(() => resolveOrganizationModel({ roles: {
|
|
279
|
+
expect(() => resolveOrganizationModel({ roles: {} })).not.toThrow()
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
it('throws when reportsToId points to the same role', () => {
|
|
283
|
+
expect(() =>
|
|
284
|
+
resolveOrganizationModel({
|
|
285
|
+
roles: {
|
|
286
|
+
'role-loop': { id: 'role-loop', order: 10, title: 'Loop Role', reportsToId: 'role-loop' }
|
|
287
|
+
}
|
|
288
|
+
})
|
|
289
|
+
).toThrow(/reportsToId cycle/)
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
it('throws when reportsToId creates an indirect cycle', () => {
|
|
293
|
+
expect(() =>
|
|
294
|
+
resolveOrganizationModel({
|
|
295
|
+
roles: {
|
|
296
|
+
'role-a': { id: 'role-a', order: 10, title: 'Role A', reportsToId: 'role-c' },
|
|
297
|
+
'role-b': { id: 'role-b', order: 20, title: 'Role B', reportsToId: 'role-a' },
|
|
298
|
+
'role-c': { id: 'role-c', order: 30, title: 'Role C', reportsToId: 'role-b' }
|
|
299
|
+
}
|
|
300
|
+
})
|
|
301
|
+
).toThrow(/reportsToId cycle/)
|
|
260
302
|
})
|
|
261
303
|
})
|
|
262
304
|
|
|
263
305
|
describe('resolveOrganizationModel - roles cross-ref (responsibleFor and heldBy)', () => {
|
|
264
306
|
const validSystem = {
|
|
265
307
|
id: 'sys.platform',
|
|
308
|
+
order: 10,
|
|
266
309
|
title: 'Platform',
|
|
267
310
|
description: 'Owns platform operations.',
|
|
268
311
|
kind: 'platform' as const,
|
|
@@ -271,19 +314,25 @@ describe('resolveOrganizationModel - roles cross-ref (responsibleFor and heldBy)
|
|
|
271
314
|
|
|
272
315
|
const validAgentResource = {
|
|
273
316
|
id: 'command-center-assistant',
|
|
317
|
+
order: 10,
|
|
274
318
|
kind: 'agent' as const,
|
|
275
|
-
|
|
319
|
+
systemPath: 'sys.platform',
|
|
276
320
|
status: 'active' as const,
|
|
277
|
-
agentKind: '
|
|
321
|
+
agentKind: 'platform' as const,
|
|
278
322
|
sessionCapable: true
|
|
279
323
|
}
|
|
280
324
|
|
|
281
325
|
it('passes when responsibleFor references a declared system id', () => {
|
|
282
326
|
expect(() =>
|
|
283
327
|
resolveOrganizationModel({
|
|
284
|
-
systems: {
|
|
328
|
+
systems: { 'sys.platform': validSystem },
|
|
285
329
|
roles: {
|
|
286
|
-
|
|
330
|
+
'role.platform-owner': {
|
|
331
|
+
id: 'role.platform-owner',
|
|
332
|
+
order: 10,
|
|
333
|
+
title: 'Platform Owner',
|
|
334
|
+
responsibleFor: ['sys.platform']
|
|
335
|
+
}
|
|
287
336
|
}
|
|
288
337
|
})
|
|
289
338
|
).not.toThrow()
|
|
@@ -293,7 +342,12 @@ describe('resolveOrganizationModel - roles cross-ref (responsibleFor and heldBy)
|
|
|
293
342
|
expect(() =>
|
|
294
343
|
resolveOrganizationModel({
|
|
295
344
|
roles: {
|
|
296
|
-
|
|
345
|
+
'role.platform-owner': {
|
|
346
|
+
id: 'role.platform-owner',
|
|
347
|
+
order: 10,
|
|
348
|
+
title: 'Platform Owner',
|
|
349
|
+
responsibleFor: ['sys.missing']
|
|
350
|
+
}
|
|
297
351
|
}
|
|
298
352
|
})
|
|
299
353
|
).toThrow(/unknown responsibleFor system/)
|
|
@@ -302,16 +356,17 @@ describe('resolveOrganizationModel - roles cross-ref (responsibleFor and heldBy)
|
|
|
302
356
|
it('passes when an agent holder references a declared agent resource', () => {
|
|
303
357
|
expect(() =>
|
|
304
358
|
resolveOrganizationModel({
|
|
305
|
-
systems: {
|
|
306
|
-
resources: {
|
|
359
|
+
systems: { 'sys.platform': validSystem },
|
|
360
|
+
resources: {
|
|
361
|
+
'command-center-assistant': validAgentResource
|
|
362
|
+
},
|
|
307
363
|
roles: {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
]
|
|
364
|
+
'role.platform-assistant': {
|
|
365
|
+
id: 'role.platform-assistant',
|
|
366
|
+
order: 10,
|
|
367
|
+
title: 'Platform Assistant',
|
|
368
|
+
heldBy: { kind: 'agent', agentId: 'command-center-assistant' }
|
|
369
|
+
}
|
|
315
370
|
}
|
|
316
371
|
})
|
|
317
372
|
).not.toThrow()
|
|
@@ -321,13 +376,12 @@ describe('resolveOrganizationModel - roles cross-ref (responsibleFor and heldBy)
|
|
|
321
376
|
expect(() =>
|
|
322
377
|
resolveOrganizationModel({
|
|
323
378
|
roles: {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
]
|
|
379
|
+
'role.platform-assistant': {
|
|
380
|
+
id: 'role.platform-assistant',
|
|
381
|
+
order: 10,
|
|
382
|
+
title: 'Platform Assistant',
|
|
383
|
+
heldBy: { kind: 'agent', agentId: 'missing-agent' }
|
|
384
|
+
}
|
|
331
385
|
}
|
|
332
386
|
})
|
|
333
387
|
).toThrow(/unknown agent holder resource/)
|
|
@@ -336,25 +390,23 @@ describe('resolveOrganizationModel - roles cross-ref (responsibleFor and heldBy)
|
|
|
336
390
|
it('throws when an agent holder references a non-agent resource', () => {
|
|
337
391
|
expect(() =>
|
|
338
392
|
resolveOrganizationModel({
|
|
339
|
-
systems: {
|
|
393
|
+
systems: { 'sys.platform': validSystem },
|
|
340
394
|
resources: {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
]
|
|
395
|
+
'LGN-01-company-scrape': {
|
|
396
|
+
id: 'LGN-01-company-scrape',
|
|
397
|
+
order: 10,
|
|
398
|
+
kind: 'workflow' as const,
|
|
399
|
+
systemPath: 'sys.platform',
|
|
400
|
+
status: 'active' as const
|
|
401
|
+
}
|
|
349
402
|
},
|
|
350
403
|
roles: {
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
]
|
|
404
|
+
'role.platform-assistant': {
|
|
405
|
+
id: 'role.platform-assistant',
|
|
406
|
+
order: 10,
|
|
407
|
+
title: 'Platform Assistant',
|
|
408
|
+
heldBy: { kind: 'agent', agentId: 'LGN-01-company-scrape' }
|
|
409
|
+
}
|
|
358
410
|
}
|
|
359
411
|
})
|
|
360
412
|
).toThrow(/must reference an agent resource/)
|
|
@@ -363,40 +415,49 @@ describe('resolveOrganizationModel - roles cross-ref (responsibleFor and heldBy)
|
|
|
363
415
|
|
|
364
416
|
describe('resolveOrganizationModel - roles domain integration', () => {
|
|
365
417
|
it('merges partial roles override and preserves empty roles default', () => {
|
|
366
|
-
const model = resolveOrganizationModel({ roles: {
|
|
367
|
-
expect(model.roles
|
|
418
|
+
const model = resolveOrganizationModel({ roles: {} })
|
|
419
|
+
expect(Object.keys(model.roles)).toHaveLength(0)
|
|
368
420
|
})
|
|
369
421
|
|
|
370
422
|
it('omitting roles key entirely resolves to default empty roles', () => {
|
|
371
423
|
const model = resolveOrganizationModel({})
|
|
372
424
|
expect(model.roles).toBeDefined()
|
|
373
|
-
expect(model.roles
|
|
425
|
+
expect(Object.keys(model.roles)).toHaveLength(0)
|
|
374
426
|
})
|
|
375
427
|
|
|
376
428
|
it('does not bleed roles changes into other top-level domains', () => {
|
|
377
429
|
const model = resolveOrganizationModel({
|
|
378
430
|
roles: {
|
|
379
|
-
|
|
431
|
+
'role-ceo': { id: 'role-ceo', order: 10, title: 'CEO' }
|
|
380
432
|
}
|
|
381
433
|
})
|
|
382
434
|
|
|
383
435
|
expect(model.identity).toBeDefined()
|
|
384
436
|
expect(model.customers).toBeDefined()
|
|
385
437
|
expect(model.offerings).toBeDefined()
|
|
386
|
-
expect(model.
|
|
438
|
+
expect(model.systems).toBeDefined()
|
|
439
|
+
// Phase 4 (D8): model.navigation removed from top-level OM.
|
|
387
440
|
expect(model.navigation).toBeDefined()
|
|
441
|
+
expect(model.knowledge).toBeDefined()
|
|
388
442
|
})
|
|
389
443
|
|
|
390
444
|
it('resolved model includes roles domain alongside other new domains', () => {
|
|
391
445
|
const model = resolveOrganizationModel({
|
|
392
|
-
customers: {
|
|
446
|
+
customers: {
|
|
447
|
+
'seg-a': { id: 'seg-a', order: 10, name: 'Segment A' }
|
|
448
|
+
},
|
|
393
449
|
roles: {
|
|
394
|
-
|
|
450
|
+
'role-ceo': {
|
|
451
|
+
id: 'role-ceo',
|
|
452
|
+
order: 10,
|
|
453
|
+
title: 'CEO',
|
|
454
|
+
heldBy: { kind: 'human', userId: 'user.alice' }
|
|
455
|
+
}
|
|
395
456
|
}
|
|
396
457
|
})
|
|
397
458
|
|
|
398
|
-
expect(model.customers
|
|
399
|
-
expect(model.roles
|
|
400
|
-
expect(model.roles
|
|
459
|
+
expect(Object.keys(model.customers)).toHaveLength(1)
|
|
460
|
+
expect(Object.keys(model.roles)).toHaveLength(1)
|
|
461
|
+
expect(model.roles['role-ceo'].heldBy).toEqual({ kind: 'human', userId: 'user.alice' })
|
|
401
462
|
})
|
|
402
463
|
})
|