@elevasis/core 0.22.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. package/dist/index.d.ts +3214 -2501
  2. package/dist/index.js +3112 -1222
  3. package/dist/knowledge/index.d.ts +1108 -1264
  4. package/dist/knowledge/index.js +112 -9
  5. package/dist/organization-model/index.d.ts +3214 -2501
  6. package/dist/organization-model/index.js +3112 -1222
  7. package/dist/test-utils/index.d.ts +985 -1103
  8. package/dist/test-utils/index.js +2464 -1165
  9. package/package.json +5 -5
  10. package/src/README.md +14 -14
  11. package/src/__tests__/publish.test.ts +24 -24
  12. package/src/__tests__/template-core-compatibility.test.ts +9 -80
  13. package/src/_gen/__tests__/__snapshots__/contracts.md.snap +2389 -2121
  14. package/src/_gen/__tests__/scaffold-contracts.test.ts +30 -30
  15. package/src/auth/multi-tenancy/credentials/__tests__/encryption.test.ts +217 -217
  16. package/src/auth/multi-tenancy/credentials/server/encryption.ts +69 -69
  17. package/src/auth/multi-tenancy/credentials/server/kek-loader.ts +37 -37
  18. package/src/auth/multi-tenancy/index.ts +26 -26
  19. package/src/auth/multi-tenancy/invitations/api-schemas.ts +104 -104
  20. package/src/auth/multi-tenancy/memberships/api-schemas.ts +143 -143
  21. package/src/auth/multi-tenancy/memberships/index.ts +26 -26
  22. package/src/auth/multi-tenancy/memberships/membership.ts +130 -130
  23. package/src/auth/multi-tenancy/organizations/__tests__/api-schemas.test.ts +194 -194
  24. package/src/auth/multi-tenancy/organizations/api-schemas.ts +136 -136
  25. package/src/auth/multi-tenancy/permissions.test.ts +42 -42
  26. package/src/auth/multi-tenancy/permissions.ts +123 -123
  27. package/src/auth/multi-tenancy/role-management/api-schemas.ts +78 -78
  28. package/src/auth/multi-tenancy/role-management/index.ts +16 -16
  29. package/src/auth/multi-tenancy/theme-presets.ts +45 -45
  30. package/src/auth/multi-tenancy/types.ts +57 -57
  31. package/src/auth/multi-tenancy/users/api-schemas.ts +165 -165
  32. package/src/business/README.md +2 -2
  33. package/src/business/acquisition/activity-events.test.ts +250 -250
  34. package/src/business/acquisition/activity-events.ts +93 -93
  35. package/src/business/acquisition/api-schemas.test.ts +1883 -1843
  36. package/src/business/acquisition/api-schemas.ts +1493 -1500
  37. package/src/business/acquisition/build-templates.test.ts +240 -240
  38. package/src/business/acquisition/build-templates.ts +83 -41
  39. package/src/business/acquisition/crm-next-action.test.ts +262 -262
  40. package/src/business/acquisition/crm-next-action.ts +220 -220
  41. package/src/business/acquisition/crm-priority.test.ts +216 -216
  42. package/src/business/acquisition/crm-priority.ts +349 -349
  43. package/src/business/acquisition/crm-state-actions.test.ts +153 -151
  44. package/src/business/acquisition/deal-ownership.test.ts +351 -351
  45. package/src/business/acquisition/deal-ownership.ts +120 -120
  46. package/src/business/acquisition/derive-actions.test.ts +129 -104
  47. package/src/business/acquisition/derive-actions.ts +74 -84
  48. package/src/business/acquisition/index.ts +171 -170
  49. package/src/business/acquisition/ontology-validation.ts +309 -0
  50. package/src/business/acquisition/stateful.ts +30 -30
  51. package/src/business/acquisition/types.ts +396 -392
  52. package/src/business/clients/api-schemas.test.ts +115 -115
  53. package/src/business/clients/api-schemas.ts +158 -158
  54. package/src/business/clients/index.ts +1 -1
  55. package/src/business/crm/api-schemas.ts +40 -40
  56. package/src/business/crm/index.ts +1 -1
  57. package/src/business/deals/api-schemas.ts +87 -87
  58. package/src/business/deals/index.ts +1 -1
  59. package/src/business/index.ts +5 -5
  60. package/src/business/projects/types.ts +144 -144
  61. package/src/commands/queue/types/task.ts +15 -15
  62. package/src/execution/core/runner-types.ts +61 -61
  63. package/src/execution/core/sse-executions.ts +7 -7
  64. package/src/execution/engine/__tests__/fixtures/test-agents.ts +10 -10
  65. package/src/execution/engine/agent/core/__tests__/agent.test.ts +16 -16
  66. package/src/execution/engine/agent/core/__tests__/error-passthrough.test.ts +4 -4
  67. package/src/execution/engine/agent/core/types.ts +25 -25
  68. package/src/execution/engine/agent/index.ts +6 -6
  69. package/src/execution/engine/agent/reasoning/__tests__/request-builder.test.ts +24 -24
  70. package/src/execution/engine/index.ts +443 -443
  71. package/src/execution/engine/tools/integration/server/adapters/apify/__tests__/apify-run-actor.integration.test.ts +298 -298
  72. package/src/execution/engine/tools/integration/server/adapters/apify/apify-adapter.test.ts +55 -55
  73. package/src/execution/engine/tools/integration/server/adapters/apify/apify-adapter.ts +107 -107
  74. package/src/execution/engine/tools/integration/server/adapters/apollo/apollo-adapter.test.ts +48 -48
  75. package/src/execution/engine/tools/integration/server/adapters/apollo/apollo-adapter.ts +99 -99
  76. package/src/execution/engine/tools/integration/server/adapters/apollo/index.ts +1 -1
  77. package/src/execution/engine/tools/integration/server/adapters/attio/__tests__/attio-crud.integration.test.ts +363 -363
  78. package/src/execution/engine/tools/integration/server/adapters/attio/fetch/get-record/index.test.ts +162 -162
  79. package/src/execution/engine/tools/integration/server/adapters/attio/fetch/list-records/index.test.ts +316 -316
  80. package/src/execution/engine/tools/integration/server/adapters/clickup/clickup-adapter.test.ts +18 -18
  81. package/src/execution/engine/tools/integration/server/adapters/clickup/clickup-adapter.ts +194 -194
  82. package/src/execution/engine/tools/integration/server/adapters/clickup/index.ts +7 -7
  83. package/src/execution/engine/tools/integration/server/adapters/gmail/gmail-adapter.ts +204 -204
  84. package/src/execution/engine/tools/integration/server/adapters/gmail/gmail-tools.ts +105 -105
  85. package/src/execution/engine/tools/integration/server/adapters/google-calendar/google-calendar-adapter.ts +428 -428
  86. package/src/execution/engine/tools/integration/server/adapters/google-calendar/index.ts +2 -2
  87. package/src/execution/engine/tools/integration/server/adapters/google-sheets/__tests__/google-sheets.integration.test.ts +261 -261
  88. package/src/execution/engine/tools/integration/server/adapters/instantly/instantly-tools.ts +1474 -1474
  89. package/src/execution/engine/tools/integration/server/adapters/millionverifier/millionverifier-tools.ts +103 -103
  90. package/src/execution/engine/tools/integration/server/adapters/resend/fetch/send-email/index.test.ts +88 -88
  91. package/src/execution/engine/tools/integration/server/adapters/resend/fetch/send-email/index.ts +141 -141
  92. package/src/execution/engine/tools/integration/server/adapters/resend/fetch/utils/types.ts +76 -76
  93. package/src/execution/engine/tools/integration/server/adapters/signature-api/signature-api-tools.ts +182 -182
  94. package/src/execution/engine/tools/integration/server/adapters/stripe/stripe-tools.ts +310 -310
  95. package/src/execution/engine/tools/integration/service.test.ts +239 -239
  96. package/src/execution/engine/tools/integration/service.ts +172 -172
  97. package/src/execution/engine/tools/integration/tool.ts +255 -255
  98. package/src/execution/engine/tools/lead-service-types.ts +1005 -1005
  99. package/src/execution/engine/tools/messages.ts +43 -43
  100. package/src/execution/engine/tools/platform/acquisition/company-tools.ts +7 -7
  101. package/src/execution/engine/tools/platform/acquisition/contact-tools.ts +6 -6
  102. package/src/execution/engine/tools/platform/acquisition/list-tools.ts +6 -6
  103. package/src/execution/engine/tools/platform/acquisition/types.ts +280 -280
  104. package/src/execution/engine/tools/platform/email/types.ts +97 -97
  105. package/src/execution/engine/tools/registry.ts +704 -704
  106. package/src/execution/engine/tools/tool-maps.ts +831 -831
  107. package/src/execution/engine/tools/types.ts +234 -234
  108. package/src/execution/engine/workflow/types.ts +202 -202
  109. package/src/execution/external/__tests__/api-schemas.test.ts +127 -127
  110. package/src/execution/external/api-schemas.ts +40 -40
  111. package/src/execution/external/index.ts +1 -1
  112. package/src/index.ts +18 -18
  113. package/src/integrations/credentials/__tests__/api-schemas.test.ts +420 -420
  114. package/src/integrations/credentials/api-schemas.ts +146 -146
  115. package/src/integrations/credentials/schemas.ts +200 -200
  116. package/src/integrations/oauth/__tests__/provider-registry.test.ts +7 -7
  117. package/src/integrations/oauth/provider-registry.ts +74 -74
  118. package/src/integrations/oauth/server/credentials.ts +43 -43
  119. package/src/integrations/webhook-endpoints/__tests__/api-schemas.test.ts +327 -327
  120. package/src/integrations/webhook-endpoints/api-schemas.ts +103 -103
  121. package/src/integrations/webhook-endpoints/types.ts +58 -58
  122. package/src/knowledge/README.md +33 -32
  123. package/src/knowledge/__tests__/queries.test.ts +633 -541
  124. package/src/knowledge/format.ts +100 -99
  125. package/src/knowledge/index.ts +5 -5
  126. package/src/knowledge/published.ts +5 -5
  127. package/src/knowledge/queries.ts +274 -222
  128. package/src/operations/activities/api-schemas.ts +80 -80
  129. package/src/operations/activities/types.ts +64 -64
  130. package/src/organization-model/README.md +149 -109
  131. package/src/organization-model/__tests__/content-kinds-registry.test.ts +210 -0
  132. package/src/organization-model/__tests__/defaults.test.ts +168 -194
  133. package/src/organization-model/__tests__/domains/actions.test.ts +78 -0
  134. package/src/organization-model/__tests__/domains/customers.test.ts +48 -44
  135. package/src/organization-model/__tests__/domains/entities.test.ts +56 -0
  136. package/src/organization-model/__tests__/domains/goals.test.ts +110 -96
  137. package/src/organization-model/__tests__/domains/identity.test.ts +4 -3
  138. package/src/organization-model/__tests__/domains/navigation.test.ts +222 -166
  139. package/src/organization-model/__tests__/domains/offerings.test.ts +83 -88
  140. package/src/organization-model/__tests__/domains/policies.test.ts +323 -0
  141. package/src/organization-model/__tests__/domains/resource-mappings.test.ts +30 -30
  142. package/src/organization-model/__tests__/domains/resources.test.ts +396 -175
  143. package/src/organization-model/__tests__/domains/roles.test.ts +463 -402
  144. package/src/organization-model/__tests__/domains/statuses.test.ts +13 -10
  145. package/src/organization-model/__tests__/domains/systems.test.ts +209 -193
  146. package/src/organization-model/__tests__/flatten-additive-merge.test.ts +362 -0
  147. package/src/organization-model/__tests__/foundation.test.ts +47 -75
  148. package/src/organization-model/__tests__/get-resources-for-system.test.ts +144 -0
  149. package/src/organization-model/__tests__/graph.test.ts +1336 -149
  150. package/src/organization-model/__tests__/icons.test.ts +10 -1
  151. package/src/organization-model/__tests__/knowledge.test.ts +418 -61
  152. package/src/organization-model/__tests__/lookup-helpers.test.ts +438 -0
  153. package/src/organization-model/__tests__/migration-helpers.test.ts +591 -0
  154. package/src/organization-model/__tests__/prospecting-ssot.test.ts +103 -94
  155. package/src/organization-model/__tests__/recursive-system-schema.test.ts +549 -0
  156. package/src/organization-model/__tests__/resolve.test.ts +303 -42
  157. package/src/organization-model/__tests__/schema.test.ts +863 -153
  158. package/src/organization-model/__tests__/surface-projection.test.ts +284 -174
  159. package/src/organization-model/catalogs/lead-gen.ts +144 -0
  160. package/src/organization-model/content-kinds/config.ts +36 -0
  161. package/src/organization-model/content-kinds/index.ts +78 -0
  162. package/src/organization-model/content-kinds/pipeline.ts +68 -0
  163. package/src/organization-model/content-kinds/registry.ts +44 -0
  164. package/src/organization-model/content-kinds/status.ts +71 -0
  165. package/src/organization-model/content-kinds/template.ts +83 -0
  166. package/src/organization-model/content-kinds/types.ts +117 -0
  167. package/src/organization-model/contracts.ts +27 -17
  168. package/src/organization-model/defaults.ts +489 -107
  169. package/src/organization-model/domains/actions.ts +333 -0
  170. package/src/organization-model/domains/customers.ts +10 -7
  171. package/src/organization-model/domains/entities.ts +144 -0
  172. package/src/organization-model/domains/goals.ts +9 -6
  173. package/src/organization-model/domains/knowledge.ts +128 -54
  174. package/src/organization-model/domains/navigation.ts +139 -416
  175. package/src/organization-model/domains/offerings.ts +15 -10
  176. package/src/organization-model/domains/policies.ts +102 -0
  177. package/src/organization-model/domains/projects.ts +6 -40
  178. package/src/organization-model/domains/prospecting.ts +395 -514
  179. package/src/organization-model/domains/resources.ts +173 -81
  180. package/src/organization-model/domains/roles.ts +96 -93
  181. package/src/organization-model/domains/sales.test.ts +218 -218
  182. package/src/organization-model/domains/sales.ts +380 -589
  183. package/src/organization-model/domains/shared.ts +8 -8
  184. package/src/organization-model/domains/statuses.ts +298 -89
  185. package/src/organization-model/domains/systems.ts +240 -38
  186. package/src/organization-model/foundation.ts +35 -48
  187. package/src/organization-model/graph/build.ts +1035 -279
  188. package/src/organization-model/graph/index.ts +4 -4
  189. package/src/organization-model/graph/link.ts +10 -10
  190. package/src/organization-model/graph/schema.ts +77 -56
  191. package/src/organization-model/graph/types.ts +75 -56
  192. package/src/organization-model/helpers.ts +312 -59
  193. package/src/organization-model/icons.ts +78 -66
  194. package/src/organization-model/index.ts +129 -16
  195. package/src/organization-model/migration-helpers.ts +252 -0
  196. package/src/organization-model/ontology.ts +661 -0
  197. package/src/organization-model/organization-graph.mdx +110 -89
  198. package/src/organization-model/organization-model.mdx +226 -171
  199. package/src/organization-model/published.ts +295 -139
  200. package/src/organization-model/resolve.ts +139 -21
  201. package/src/organization-model/schema.ts +841 -301
  202. package/src/organization-model/surface-projection.ts +212 -218
  203. package/src/organization-model/types.ts +181 -90
  204. package/src/platform/api/types.ts +38 -38
  205. package/src/platform/constants/versions.ts +3 -3
  206. package/src/platform/index.ts +23 -23
  207. package/src/platform/registry/__tests__/command-view.test.ts +5 -7
  208. package/src/platform/registry/__tests__/resource-link.test.ts +35 -30
  209. package/src/platform/registry/__tests__/resource-registry.integration.test.ts +17 -32
  210. package/src/platform/registry/__tests__/resource-registry.nested-systems.test.ts +245 -0
  211. package/src/platform/registry/__tests__/resource-registry.test.ts +2053 -2051
  212. package/src/platform/registry/__tests__/validation.test.ts +1347 -1343
  213. package/src/platform/registry/command-view.ts +10 -10
  214. package/src/platform/registry/index.ts +103 -103
  215. package/src/platform/registry/resource-link.ts +32 -32
  216. package/src/platform/registry/resource-registry.ts +890 -878
  217. package/src/platform/registry/serialization.ts +295 -295
  218. package/src/platform/registry/serialized-types.ts +166 -166
  219. package/src/platform/registry/stats-types.ts +68 -68
  220. package/src/platform/registry/types.ts +425 -425
  221. package/src/platform/registry/validation.ts +745 -743
  222. package/src/platform/utils/__tests__/validation.test.ts +1084 -1084
  223. package/src/platform/utils/validation.ts +425 -425
  224. package/src/projects/api-schemas.test.ts +39 -39
  225. package/src/projects/api-schemas.ts +291 -291
  226. package/src/reference/_generated/contracts.md +2389 -2121
  227. package/src/reference/glossary.md +76 -76
  228. package/src/scaffold-registry/__tests__/index.test.ts +206 -206
  229. package/src/scaffold-registry/__tests__/schema.test.ts +166 -166
  230. package/src/scaffold-registry/index.ts +392 -392
  231. package/src/scaffold-registry/schema.ts +243 -243
  232. package/src/server.ts +289 -289
  233. package/src/supabase/database.types.ts +3153 -3093
  234. package/src/test-utils/README.md +37 -37
  235. package/src/test-utils/entities.ts +108 -108
  236. package/src/test-utils/fixtures/memberships.ts +82 -82
  237. package/src/test-utils/index.ts +12 -12
  238. package/src/test-utils/organization-model.ts +65 -65
  239. package/src/test-utils/published.ts +6 -6
  240. package/src/test-utils/rls/RLSTestContext.ts +588 -588
  241. package/src/test-utils/test-utils.test.ts +44 -49
  242. package/src/organization-model/__tests__/domains/operations.test.ts +0 -203
  243. package/src/organization-model/domains/features.ts +0 -31
  244. package/src/organization-model/domains/operations.ts +0 -85
@@ -15,19 +15,20 @@ describe('ProductSchema — positive parse', () => {
15
15
  it('accepts a fully-populated product', () => {
16
16
  const result = ProductSchema.safeParse({
17
17
  id: 'product-starter-plan',
18
+ order: 10,
18
19
  name: 'Starter Plan',
19
20
  description: 'Full-service automation for small teams.',
20
21
  pricingModel: 'subscription',
21
22
  price: 299,
22
23
  currency: 'USD',
23
24
  targetSegmentIds: ['seg-smb'],
24
- deliveryFeatureId: 'crm'
25
+ deliveryFeatureId: 'sales.crm'
25
26
  })
26
27
  expect(result.success).toBe(true)
27
28
  })
28
29
 
29
- it('accepts a minimal product — only id required', () => {
30
- const result = ProductSchema.safeParse({ id: 'product-minimal' })
30
+ it('accepts a minimal product — only id and order required', () => {
31
+ const result = ProductSchema.safeParse({ id: 'product-minimal', order: 10 })
31
32
  expect(result.success).toBe(true)
32
33
  if (result.success) {
33
34
  expect(result.data.id).toBe('product-minimal')
@@ -44,6 +45,7 @@ describe('ProductSchema — positive parse', () => {
44
45
  it('trims whitespace from id and name', () => {
45
46
  const result = ProductSchema.safeParse({
46
47
  id: ' product-trim ',
48
+ order: 10,
47
49
  name: ' Trimmed Name '
48
50
  })
49
51
  expect(result.success).toBe(true)
@@ -56,6 +58,7 @@ describe('ProductSchema — positive parse', () => {
56
58
  it('accepts price of 0 (free tier)', () => {
57
59
  const result = ProductSchema.safeParse({
58
60
  id: 'product-free',
61
+ order: 10,
59
62
  pricingModel: 'subscription',
60
63
  price: 0
61
64
  })
@@ -68,7 +71,7 @@ describe('ProductSchema — positive parse', () => {
68
71
  it('accepts all four pricing model values', () => {
69
72
  const models = ['one-time', 'subscription', 'usage-based', 'custom'] as const
70
73
  for (const pricingModel of models) {
71
- const result = ProductSchema.safeParse({ id: `product-${pricingModel}`, pricingModel })
74
+ const result = ProductSchema.safeParse({ id: `product-${pricingModel}`, order: 10, pricingModel })
72
75
  expect(result.success).toBe(true)
73
76
  }
74
77
  })
@@ -80,7 +83,7 @@ describe('ProductSchema — positive parse', () => {
80
83
 
81
84
  describe('ProductSchema — default values', () => {
82
85
  it('pricingModel defaults to "custom"', () => {
83
- const result = ProductSchema.safeParse({ id: 'product-defaults' })
86
+ const result = ProductSchema.safeParse({ id: 'product-defaults', order: 10 })
84
87
  expect(result.success).toBe(true)
85
88
  if (result.success) {
86
89
  expect(result.data.pricingModel).toBe('custom')
@@ -88,7 +91,7 @@ describe('ProductSchema — default values', () => {
88
91
  })
89
92
 
90
93
  it('price defaults to 0', () => {
91
- const result = ProductSchema.safeParse({ id: 'product-defaults' })
94
+ const result = ProductSchema.safeParse({ id: 'product-defaults', order: 10 })
92
95
  expect(result.success).toBe(true)
93
96
  if (result.success) {
94
97
  expect(result.data.price).toBe(0)
@@ -96,7 +99,7 @@ describe('ProductSchema — default values', () => {
96
99
  })
97
100
 
98
101
  it('currency defaults to "USD"', () => {
99
- const result = ProductSchema.safeParse({ id: 'product-defaults' })
102
+ const result = ProductSchema.safeParse({ id: 'product-defaults', order: 10 })
100
103
  expect(result.success).toBe(true)
101
104
  if (result.success) {
102
105
  expect(result.data.currency).toBe('USD')
@@ -104,7 +107,7 @@ describe('ProductSchema — default values', () => {
104
107
  })
105
108
 
106
109
  it('targetSegmentIds defaults to empty array', () => {
107
- const result = ProductSchema.safeParse({ id: 'product-defaults' })
110
+ const result = ProductSchema.safeParse({ id: 'product-defaults', order: 10 })
108
111
  expect(result.success).toBe(true)
109
112
  if (result.success) {
110
113
  expect(result.data.targetSegmentIds).toEqual([])
@@ -112,7 +115,7 @@ describe('ProductSchema — default values', () => {
112
115
  })
113
116
 
114
117
  it('deliveryFeatureId defaults to undefined (field is optional)', () => {
115
- const result = ProductSchema.safeParse({ id: 'product-defaults' })
118
+ const result = ProductSchema.safeParse({ id: 'product-defaults', order: 10 })
116
119
  expect(result.success).toBe(true)
117
120
  if (result.success) {
118
121
  expect(result.data.deliveryFeatureId).toBeUndefined()
@@ -126,37 +129,37 @@ describe('ProductSchema — default values', () => {
126
129
 
127
130
  describe('ProductSchema — negative parse', () => {
128
131
  it('rejects missing id', () => {
129
- const result = ProductSchema.safeParse({ name: 'No ID Product' })
132
+ const result = ProductSchema.safeParse({ order: 10, name: 'No ID Product' })
130
133
  expect(result.success).toBe(false)
131
134
  })
132
135
 
133
136
  it('rejects empty string id', () => {
134
- const result = ProductSchema.safeParse({ id: '' })
137
+ const result = ProductSchema.safeParse({ id: '', order: 10 })
135
138
  expect(result.success).toBe(false)
136
139
  })
137
140
 
138
141
  it('rejects whitespace-only id (trims to empty string)', () => {
139
- const result = ProductSchema.safeParse({ id: ' ' })
142
+ const result = ProductSchema.safeParse({ id: ' ', order: 10 })
140
143
  expect(result.success).toBe(false)
141
144
  })
142
145
 
143
146
  it('rejects an unknown pricingModel value', () => {
144
- const result = ProductSchema.safeParse({ id: 'product-bad-model', pricingModel: 'freemium' })
147
+ const result = ProductSchema.safeParse({ id: 'product-bad-model', order: 10, pricingModel: 'freemium' })
145
148
  expect(result.success).toBe(false)
146
149
  })
147
150
 
148
151
  it('rejects price below 0', () => {
149
- const result = ProductSchema.safeParse({ id: 'product-negative-price', price: -1 })
152
+ const result = ProductSchema.safeParse({ id: 'product-negative-price', order: 10, price: -1 })
150
153
  expect(result.success).toBe(false)
151
154
  })
152
155
 
153
156
  it('rejects price as a string', () => {
154
- const result = ProductSchema.safeParse({ id: 'product-string-price', price: '299' })
157
+ const result = ProductSchema.safeParse({ id: 'product-string-price', order: 10, price: '299' })
155
158
  expect(result.success).toBe(false)
156
159
  })
157
160
 
158
161
  it('rejects targetSegmentIds as a non-array value', () => {
159
- const result = ProductSchema.safeParse({ id: 'product-bad-segments', targetSegmentIds: 'seg-a' })
162
+ const result = ProductSchema.safeParse({ id: 'product-bad-segments', order: 10, targetSegmentIds: 'seg-a' })
160
163
  expect(result.success).toBe(false)
161
164
  })
162
165
  })
@@ -189,34 +192,34 @@ describe('PricingModelSchema — enum', () => {
189
192
  // ---------------------------------------------------------------------------
190
193
 
191
194
  describe('OfferingsDomainSchema — structural', () => {
192
- it('accepts an empty products array', () => {
193
- const result = OfferingsDomainSchema.safeParse({ products: [] })
195
+ it('accepts an empty products record', () => {
196
+ const result = OfferingsDomainSchema.safeParse({})
194
197
  expect(result.success).toBe(true)
195
198
  })
196
199
 
197
- it('defaults products to empty array when key is omitted', () => {
200
+ it('defaults products to empty record when omitted', () => {
198
201
  const result = OfferingsDomainSchema.safeParse({})
199
202
  expect(result.success).toBe(true)
200
203
  if (result.success) {
201
- expect(result.data.products).toEqual([])
204
+ expect(result.data).toEqual({})
202
205
  }
203
206
  })
204
207
 
205
208
  it('accepts multiple valid products', () => {
206
209
  const result = OfferingsDomainSchema.safeParse({
207
- products: [
208
- { id: 'product-a', name: 'Product A', pricingModel: 'subscription' },
209
- { id: 'product-b', name: 'Product B', pricingModel: 'one-time', price: 999 }
210
- ]
210
+ 'product-a': { id: 'product-a', order: 10, name: 'Product A', pricingModel: 'subscription' },
211
+ 'product-b': { id: 'product-b', order: 20, name: 'Product B', pricingModel: 'one-time', price: 999 }
211
212
  })
212
213
  expect(result.success).toBe(true)
213
214
  if (result.success) {
214
- expect(result.data.products).toHaveLength(2)
215
+ expect(Object.keys(result.data)).toHaveLength(2)
215
216
  }
216
217
  })
217
218
 
218
- it('rejects products as a non-array value', () => {
219
- const result = OfferingsDomainSchema.safeParse({ products: 'not an array' })
219
+ it('rejects a record where entry id does not match map key', () => {
220
+ const result = OfferingsDomainSchema.safeParse({
221
+ 'product-a': { id: 'product-b', order: 10, name: 'Mismatched' }
222
+ })
220
223
  expect(result.success).toBe(false)
221
224
  })
222
225
 
@@ -238,17 +241,16 @@ describe('resolveOrganizationModel — offerings cross-ref (targetSegmentIds)',
238
241
  expect(() =>
239
242
  resolveOrganizationModel({
240
243
  customers: {
241
- segments: [{ id: 'seg-agencies', name: 'SMB Agencies' }]
244
+ 'seg-agencies': { id: 'seg-agencies', order: 10, name: 'SMB Agencies' }
242
245
  },
243
246
  offerings: {
244
- products: [
245
- {
246
- id: 'product-starter',
247
- name: 'Starter Plan',
248
- pricingModel: 'subscription',
249
- targetSegmentIds: ['seg-agencies']
250
- }
251
- ]
247
+ 'product-starter': {
248
+ id: 'product-starter',
249
+ order: 10,
250
+ name: 'Starter Plan',
251
+ pricingModel: 'subscription',
252
+ targetSegmentIds: ['seg-agencies']
253
+ }
252
254
  }
253
255
  })
254
256
  ).not.toThrow()
@@ -257,14 +259,13 @@ describe('resolveOrganizationModel — offerings cross-ref (targetSegmentIds)',
257
259
  it('throws when targetSegmentIds references a non-existent segment', () => {
258
260
  expect(() =>
259
261
  resolveOrganizationModel({
260
- customers: { segments: [] },
262
+ customers: {},
261
263
  offerings: {
262
- products: [
263
- {
264
- id: 'product-bad-ref',
265
- targetSegmentIds: ['nonexistent-segment']
266
- }
267
- ]
264
+ 'product-bad-ref': {
265
+ id: 'product-bad-ref',
266
+ order: 10,
267
+ targetSegmentIds: ['nonexistent-segment']
268
+ }
268
269
  }
269
270
  })
270
271
  ).toThrow()
@@ -274,14 +275,13 @@ describe('resolveOrganizationModel — offerings cross-ref (targetSegmentIds)',
274
275
  let errorMessage = ''
275
276
  try {
276
277
  resolveOrganizationModel({
277
- customers: { segments: [] },
278
+ customers: {},
278
279
  offerings: {
279
- products: [
280
- {
281
- id: 'product-path-check',
282
- targetSegmentIds: ['ghost-segment']
283
- }
284
- ]
280
+ 'product-path-check': {
281
+ id: 'product-path-check',
282
+ order: 10,
283
+ targetSegmentIds: ['ghost-segment']
284
+ }
285
285
  }
286
286
  })
287
287
  } catch (e) {
@@ -294,7 +294,7 @@ describe('resolveOrganizationModel — offerings cross-ref (targetSegmentIds)',
294
294
  expect(() =>
295
295
  resolveOrganizationModel({
296
296
  offerings: {
297
- products: [{ id: 'product-no-targets', targetSegmentIds: [] }]
297
+ 'product-no-targets': { id: 'product-no-targets', order: 10, targetSegmentIds: [] }
298
298
  }
299
299
  })
300
300
  ).not.toThrow()
@@ -304,16 +304,12 @@ describe('resolveOrganizationModel — offerings cross-ref (targetSegmentIds)',
304
304
  expect(() =>
305
305
  resolveOrganizationModel({
306
306
  customers: {
307
- segments: [
308
- { id: 'seg-a', name: 'Segment A' },
309
- { id: 'seg-b', name: 'Segment B' }
310
- ]
307
+ 'seg-a': { id: 'seg-a', order: 10, name: 'Segment A' },
308
+ 'seg-b': { id: 'seg-b', order: 20, name: 'Segment B' }
311
309
  },
312
310
  offerings: {
313
- products: [
314
- { id: 'product-1', targetSegmentIds: ['seg-a'] },
315
- { id: 'product-2', targetSegmentIds: ['seg-a', 'seg-b'] }
316
- ]
311
+ 'product-1': { id: 'product-1', order: 10, targetSegmentIds: ['seg-a'] },
312
+ 'product-2': { id: 'product-2', order: 20, targetSegmentIds: ['seg-a', 'seg-b'] }
317
313
  }
318
314
  })
319
315
  ).not.toThrow()
@@ -325,48 +321,45 @@ describe('resolveOrganizationModel — offerings cross-ref (targetSegmentIds)',
325
321
  // ---------------------------------------------------------------------------
326
322
 
327
323
  describe('resolveOrganizationModel — offerings cross-ref (deliveryFeatureId)', () => {
328
- it('passes when deliveryFeatureId references a declared feature', () => {
329
- // 'crm' is in DEFAULT_ORGANIZATION_MODEL.features
324
+ it('passes when deliveryFeatureId references a declared system', () => {
325
+ // 'sales.crm' is in DEFAULT_ORGANIZATION_MODEL.systems
330
326
  expect(() =>
331
327
  resolveOrganizationModel({
332
328
  offerings: {
333
- products: [
334
- {
335
- id: 'product-with-delivery',
336
- deliveryFeatureId: 'crm'
337
- }
338
- ]
329
+ 'product-with-delivery': {
330
+ id: 'product-with-delivery',
331
+ order: 10,
332
+ deliveryFeatureId: 'sales.crm'
333
+ }
339
334
  }
340
335
  })
341
336
  ).not.toThrow()
342
337
  })
343
338
 
344
- it('throws when deliveryFeatureId references a non-existent feature', () => {
339
+ it('throws when deliveryFeatureId references a non-existent system', () => {
345
340
  expect(() =>
346
341
  resolveOrganizationModel({
347
342
  offerings: {
348
- products: [
349
- {
350
- id: 'product-bad-delivery',
351
- deliveryFeatureId: 'nonexistent-feature'
352
- }
353
- ]
343
+ 'product-bad-delivery': {
344
+ id: 'product-bad-delivery',
345
+ order: 10,
346
+ deliveryFeatureId: 'nonexistent-feature'
347
+ }
354
348
  }
355
349
  })
356
350
  ).toThrow()
357
351
  })
358
352
 
359
- it('throws with a message referencing the unknown feature id', () => {
353
+ it('throws with a message referencing the unknown system id', () => {
360
354
  let errorMessage = ''
361
355
  try {
362
356
  resolveOrganizationModel({
363
357
  offerings: {
364
- products: [
365
- {
366
- id: 'product-delivery-path',
367
- deliveryFeatureId: 'ghost-feature'
368
- }
369
- ]
358
+ 'product-delivery-path': {
359
+ id: 'product-delivery-path',
360
+ order: 10,
361
+ deliveryFeatureId: 'ghost-feature'
362
+ }
370
363
  }
371
364
  })
372
365
  } catch (e) {
@@ -379,7 +372,7 @@ describe('resolveOrganizationModel — offerings cross-ref (deliveryFeatureId)',
379
372
  expect(() =>
380
373
  resolveOrganizationModel({
381
374
  offerings: {
382
- products: [{ id: 'product-no-delivery' }]
375
+ 'product-no-delivery': { id: 'product-no-delivery', order: 10 }
383
376
  }
384
377
  })
385
378
  ).not.toThrow()
@@ -392,28 +385,30 @@ describe('resolveOrganizationModel — offerings cross-ref (deliveryFeatureId)',
392
385
 
393
386
  describe('resolveOrganizationModel — offerings domain integration', () => {
394
387
  it('merges partial offerings override and preserves empty products default', () => {
395
- const model = resolveOrganizationModel({ offerings: { products: [] } })
396
- expect(model.offerings.products).toEqual([])
388
+ const model = resolveOrganizationModel({ offerings: {} })
389
+ expect(Object.keys(model.offerings)).toHaveLength(0)
397
390
  })
398
391
 
399
392
  it('omitting offerings key entirely resolves to default empty products', () => {
400
393
  const model = resolveOrganizationModel({})
401
394
  expect(model.offerings).toBeDefined()
402
- expect(model.offerings.products).toEqual([])
395
+ expect(Object.keys(model.offerings)).toHaveLength(0)
403
396
  })
404
397
 
405
398
  it('does not bleed offerings changes into other top-level domains', () => {
406
399
  const model = resolveOrganizationModel({
407
400
  customers: {
408
- segments: [{ id: 'seg-isolation' }]
401
+ 'seg-isolation': { id: 'seg-isolation', order: 10 }
409
402
  },
410
403
  offerings: {
411
- products: [{ id: 'product-isolation', targetSegmentIds: ['seg-isolation'] }]
404
+ 'product-isolation': { id: 'product-isolation', order: 10, targetSegmentIds: ['seg-isolation'] }
412
405
  }
413
406
  })
414
407
  expect(model.identity).toBeDefined()
415
408
  expect(model.customers).toBeDefined()
416
- expect(model.features).toBeDefined()
409
+ expect(model.systems).toBeDefined()
410
+ // Phase 4 (D8): model.navigation removed from top-level OM.
417
411
  expect(model.navigation).toBeDefined()
412
+ expect(model.knowledge).toBeDefined()
418
413
  })
419
414
  })