@elevasis/core 0.21.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.
Files changed (132) hide show
  1. package/dist/index.d.ts +2518 -2169
  2. package/dist/index.js +2495 -1095
  3. package/dist/knowledge/index.d.ts +706 -1044
  4. package/dist/knowledge/index.js +9 -9
  5. package/dist/organization-model/index.d.ts +2518 -2169
  6. package/dist/organization-model/index.js +2495 -1095
  7. package/dist/test-utils/index.d.ts +826 -1014
  8. package/dist/test-utils/index.js +1894 -1032
  9. package/package.json +3 -3
  10. package/src/__tests__/template-core-compatibility.test.ts +11 -79
  11. package/src/_gen/__tests__/__snapshots__/contracts.md.snap +852 -397
  12. package/src/auth/multi-tenancy/permissions.ts +20 -8
  13. package/src/business/README.md +2 -2
  14. package/src/business/acquisition/api-schemas.test.ts +175 -2
  15. package/src/business/acquisition/api-schemas.ts +132 -16
  16. package/src/business/acquisition/build-templates.test.ts +4 -4
  17. package/src/business/acquisition/build-templates.ts +72 -30
  18. package/src/business/acquisition/crm-state-actions.test.ts +13 -11
  19. package/src/business/acquisition/index.ts +12 -0
  20. package/src/business/acquisition/types.ts +7 -3
  21. package/src/business/clients/api-schemas.test.ts +115 -0
  22. package/src/business/clients/api-schemas.ts +158 -0
  23. package/src/business/clients/index.ts +1 -0
  24. package/src/business/deals/api-schemas.ts +8 -0
  25. package/src/business/index.ts +5 -2
  26. package/src/business/projects/types.ts +19 -0
  27. package/src/execution/engine/__tests__/fixtures/test-agents.ts +10 -8
  28. package/src/execution/engine/agent/core/__tests__/agent.test.ts +16 -12
  29. package/src/execution/engine/agent/core/__tests__/error-passthrough.test.ts +4 -3
  30. package/src/execution/engine/agent/core/types.ts +25 -15
  31. package/src/execution/engine/agent/index.ts +6 -4
  32. package/src/execution/engine/agent/reasoning/__tests__/request-builder.test.ts +24 -18
  33. package/src/execution/engine/index.ts +3 -0
  34. package/src/execution/engine/workflow/types.ts +9 -2
  35. package/src/knowledge/README.md +8 -7
  36. package/src/knowledge/__tests__/queries.test.ts +74 -73
  37. package/src/knowledge/format.ts +10 -9
  38. package/src/knowledge/index.ts +1 -1
  39. package/src/knowledge/published.ts +1 -1
  40. package/src/knowledge/queries.ts +26 -25
  41. package/src/organization-model/README.md +73 -26
  42. package/src/organization-model/__tests__/content-kinds-registry.test.ts +210 -0
  43. package/src/organization-model/__tests__/defaults.test.ts +76 -96
  44. package/src/organization-model/__tests__/domains/actions.test.ts +56 -0
  45. package/src/organization-model/__tests__/domains/customers.test.ts +299 -295
  46. package/src/organization-model/__tests__/domains/entities.test.ts +56 -0
  47. package/src/organization-model/__tests__/domains/goals.test.ts +493 -479
  48. package/src/organization-model/__tests__/domains/identity.test.ts +280 -279
  49. package/src/organization-model/__tests__/domains/navigation.test.ts +268 -212
  50. package/src/organization-model/__tests__/domains/offerings.test.ts +414 -419
  51. package/src/organization-model/__tests__/domains/policies.test.ts +323 -0
  52. package/src/organization-model/__tests__/domains/resource-mappings.test.ts +271 -271
  53. package/src/organization-model/__tests__/domains/resources.test.ts +310 -0
  54. package/src/organization-model/__tests__/domains/roles.test.ts +463 -347
  55. package/src/organization-model/__tests__/domains/statuses.test.ts +246 -243
  56. package/src/organization-model/__tests__/domains/systems.test.ts +209 -0
  57. package/src/organization-model/__tests__/flatten-additive-merge.test.ts +361 -0
  58. package/src/organization-model/__tests__/foundation.test.ts +74 -102
  59. package/src/organization-model/__tests__/get-resources-for-system.test.ts +144 -0
  60. package/src/organization-model/__tests__/graph.test.ts +899 -71
  61. package/src/organization-model/__tests__/knowledge.test.ts +209 -49
  62. package/src/organization-model/__tests__/lookup-helpers.test.ts +438 -0
  63. package/src/organization-model/__tests__/migration-helpers.test.ts +591 -0
  64. package/src/organization-model/__tests__/prospecting-ssot.test.ts +36 -27
  65. package/src/organization-model/__tests__/recursive-system-schema.test.ts +520 -0
  66. package/src/organization-model/__tests__/resolve.test.ts +174 -23
  67. package/src/organization-model/__tests__/schema.test.ts +291 -114
  68. package/src/organization-model/__tests__/surface-projection.test.ts +207 -97
  69. package/src/organization-model/catalogs/lead-gen.ts +144 -0
  70. package/src/organization-model/content-kinds/config.ts +36 -0
  71. package/src/organization-model/content-kinds/index.ts +74 -0
  72. package/src/organization-model/content-kinds/pipeline.ts +68 -0
  73. package/src/organization-model/content-kinds/registry.ts +44 -0
  74. package/src/organization-model/content-kinds/status.ts +71 -0
  75. package/src/organization-model/content-kinds/template.ts +83 -0
  76. package/src/organization-model/content-kinds/types.ts +117 -0
  77. package/src/organization-model/contracts.ts +13 -3
  78. package/src/organization-model/defaults.ts +499 -86
  79. package/src/organization-model/domains/actions.ts +239 -0
  80. package/src/organization-model/domains/customers.ts +78 -75
  81. package/src/organization-model/domains/entities.ts +144 -0
  82. package/src/organization-model/domains/goals.ts +83 -80
  83. package/src/organization-model/domains/knowledge.ts +76 -17
  84. package/src/organization-model/domains/navigation.ts +107 -384
  85. package/src/organization-model/domains/offerings.ts +71 -66
  86. package/src/organization-model/domains/policies.ts +102 -0
  87. package/src/organization-model/domains/projects.ts +14 -48
  88. package/src/organization-model/domains/prospecting.ts +62 -181
  89. package/src/organization-model/domains/resources.ts +145 -0
  90. package/src/organization-model/domains/roles.ts +96 -55
  91. package/src/organization-model/domains/sales.ts +10 -219
  92. package/src/organization-model/domains/shared.ts +57 -57
  93. package/src/organization-model/domains/statuses.ts +339 -130
  94. package/src/organization-model/domains/systems.ts +203 -0
  95. package/src/organization-model/foundation.ts +54 -67
  96. package/src/organization-model/graph/build.ts +682 -54
  97. package/src/organization-model/graph/link.ts +1 -1
  98. package/src/organization-model/graph/schema.ts +24 -9
  99. package/src/organization-model/graph/types.ts +20 -7
  100. package/src/organization-model/helpers.ts +231 -26
  101. package/src/organization-model/icons.ts +1 -0
  102. package/src/organization-model/index.ts +118 -5
  103. package/src/organization-model/migration-helpers.ts +249 -0
  104. package/src/organization-model/organization-graph.mdx +16 -15
  105. package/src/organization-model/organization-model.mdx +111 -44
  106. package/src/organization-model/published.ts +172 -19
  107. package/src/organization-model/resolve.ts +117 -54
  108. package/src/organization-model/schema.ts +654 -112
  109. package/src/organization-model/surface-projection.ts +116 -122
  110. package/src/organization-model/types.ts +146 -20
  111. package/src/platform/api/types.ts +38 -35
  112. package/src/platform/constants/versions.ts +1 -1
  113. package/src/platform/registry/__tests__/command-view.test.ts +6 -8
  114. package/src/platform/registry/__tests__/resource-link.test.ts +13 -8
  115. package/src/platform/registry/__tests__/resource-registry.integration.test.ts +16 -31
  116. package/src/platform/registry/__tests__/resource-registry.nested-systems.test.ts +245 -0
  117. package/src/platform/registry/__tests__/resource-registry.test.ts +2053 -2005
  118. package/src/platform/registry/__tests__/validation.test.ts +1347 -1086
  119. package/src/platform/registry/index.ts +14 -0
  120. package/src/platform/registry/resource-registry.ts +52 -2
  121. package/src/platform/registry/serialization.ts +241 -202
  122. package/src/platform/registry/serialized-types.ts +1 -0
  123. package/src/platform/registry/types.ts +411 -361
  124. package/src/platform/registry/validation.ts +745 -513
  125. package/src/projects/api-schemas.ts +290 -267
  126. package/src/reference/_generated/contracts.md +853 -397
  127. package/src/reference/glossary.md +23 -18
  128. package/src/supabase/database.types.ts +181 -0
  129. package/src/test-utils/test-utils.test.ts +1 -6
  130. package/src/organization-model/__tests__/domains/operations.test.ts +0 -203
  131. package/src/organization-model/domains/features.ts +0 -31
  132. package/src/organization-model/domains/operations.ts +0 -85
@@ -1,243 +1,246 @@
1
- import { describe, expect, it } from 'vitest'
2
- import type { QueueTaskStatus } from '../../../commands/queue/types/task'
3
- import type { TaskStatus } from '../../../business/projects/types'
4
- import {
5
- DEFAULT_ORGANIZATION_MODEL_STATUSES,
6
- StatusEntrySchema,
7
- StatusesDomainSchema,
8
- StatusSemanticClassSchema
9
- } from '../../domains/statuses'
10
-
11
- // ---------------------------------------------------------------------------
12
- // Group 1: StatusEntrySchema — positive parse
13
- // ---------------------------------------------------------------------------
14
-
15
- describe('StatusEntrySchema — positive parse', () => {
16
- it('accepts a fully-specified entry (id, label, semanticClass, category)', () => {
17
- const result = StatusEntrySchema.safeParse({
18
- id: 'delivery.task.planned',
19
- label: 'Planned',
20
- semanticClass: 'delivery.task',
21
- category: 'delivery'
22
- })
23
- expect(result.success).toBe(true)
24
- })
25
-
26
- it('accepts a minimal entry without category (category is optional)', () => {
27
- const result = StatusEntrySchema.safeParse({
28
- id: 'queue.pending',
29
- label: 'Pending',
30
- semanticClass: 'queue'
31
- })
32
- expect(result.success).toBe(true)
33
- if (result.success) {
34
- expect(result.data.category).toBeUndefined()
35
- }
36
- })
37
-
38
- it('trims whitespace from id and label', () => {
39
- const result = StatusEntrySchema.safeParse({
40
- id: ' trimmed-id ',
41
- label: ' Trimmed Label ',
42
- semanticClass: 'execution'
43
- })
44
- expect(result.success).toBe(true)
45
- if (result.success) {
46
- expect(result.data.id).toBe('trimmed-id')
47
- expect(result.data.label).toBe('Trimmed Label')
48
- }
49
- })
50
- })
51
-
52
- // ---------------------------------------------------------------------------
53
- // Group 2: StatusEntrySchema — negative parse
54
- // ---------------------------------------------------------------------------
55
-
56
- describe('StatusEntrySchema — negative parse', () => {
57
- it('rejects a missing id field', () => {
58
- const result = StatusEntrySchema.safeParse({
59
- label: 'No ID',
60
- semanticClass: 'queue'
61
- })
62
- expect(result.success).toBe(false)
63
- })
64
-
65
- it('rejects a missing label field', () => {
66
- const result = StatusEntrySchema.safeParse({
67
- id: 'queue.pending',
68
- semanticClass: 'queue'
69
- })
70
- expect(result.success).toBe(false)
71
- })
72
-
73
- it('rejects a missing semanticClass field', () => {
74
- const result = StatusEntrySchema.safeParse({
75
- id: 'queue.pending',
76
- label: 'Pending'
77
- })
78
- expect(result.success).toBe(false)
79
- })
80
-
81
- it('rejects an unknown semanticClass value', () => {
82
- const result = StatusEntrySchema.safeParse({
83
- id: 'some.entry',
84
- label: 'Some Entry',
85
- semanticClass: 'not-a-real-class'
86
- })
87
- expect(result.success).toBe(false)
88
- })
89
-
90
- it('rejects a non-string id (number)', () => {
91
- const result = StatusEntrySchema.safeParse({
92
- id: 42,
93
- label: 'Label',
94
- semanticClass: 'queue'
95
- })
96
- expect(result.success).toBe(false)
97
- })
98
-
99
- it('rejects an empty string label (min length 1 after trim)', () => {
100
- const result = StatusEntrySchema.safeParse({
101
- id: 'some.entry',
102
- label: ' ',
103
- semanticClass: 'queue'
104
- })
105
- expect(result.success).toBe(false)
106
- })
107
- })
108
-
109
- // ---------------------------------------------------------------------------
110
- // Group 3: StatusesDomainSchema — structural tests
111
- // ---------------------------------------------------------------------------
112
-
113
- describe('StatusesDomainSchema — structural tests', () => {
114
- it('accepts an entries-empty domain object', () => {
115
- const result = StatusesDomainSchema.safeParse({ entries: [] })
116
- expect(result.success).toBe(true)
117
- })
118
-
119
- it('applies an empty-array default when entries is omitted', () => {
120
- const result = StatusesDomainSchema.safeParse({})
121
- expect(result.success).toBe(true)
122
- if (result.success) {
123
- expect(result.data.entries).toEqual([])
124
- }
125
- })
126
- })
127
-
128
- // ---------------------------------------------------------------------------
129
- // Group 4: Semantic class enum — all 8 values declared
130
- // ---------------------------------------------------------------------------
131
-
132
- describe('StatusSemanticClassSchema enum coverage', () => {
133
- const expectedClasses = [
134
- 'delivery.task',
135
- 'delivery.project',
136
- 'delivery.milestone',
137
- 'queue',
138
- 'execution',
139
- 'schedule',
140
- 'schedule.run',
141
- 'request'
142
- ] as const
143
-
144
- it('enum exposes exactly 8 semantic classes', () => {
145
- expect(StatusSemanticClassSchema.options).toHaveLength(8)
146
- })
147
-
148
- it.each(expectedClasses)('"%s" is a valid semanticClass value', (cls) => {
149
- const result = StatusSemanticClassSchema.safeParse(cls)
150
- expect(result.success).toBe(true)
151
- })
152
-
153
- it('every entry in the seed uses one of the 8 known semanticClass values', () => {
154
- const valid = new Set<string>(StatusSemanticClassSchema.options)
155
- for (const entry of DEFAULT_ORGANIZATION_MODEL_STATUSES.entries) {
156
- expect(
157
- valid.has(entry.semanticClass),
158
- `Unexpected semanticClass "${entry.semanticClass}" on entry "${entry.id}"`
159
- ).toBe(true)
160
- }
161
- })
162
-
163
- it('all 8 semanticClass values have at least one seed entry', () => {
164
- const presentClasses = new Set(DEFAULT_ORGANIZATION_MODEL_STATUSES.entries.map((e) => e.semanticClass))
165
- for (const cls of StatusSemanticClassSchema.options) {
166
- expect(presentClasses.has(cls), `No seed entry found for semanticClass "${cls}"`).toBe(true)
167
- }
168
- })
169
- })
170
-
171
- // ---------------------------------------------------------------------------
172
- // Group 5: Seed completeness — per-group counts
173
- // ---------------------------------------------------------------------------
174
-
175
- describe('DEFAULT_ORGANIZATION_MODEL_STATUSES seed — per-group counts', () => {
176
- function countBySemClass(cls: string) {
177
- return DEFAULT_ORGANIZATION_MODEL_STATUSES.entries.filter((e) => e.semanticClass === cls).length
178
- }
179
-
180
- it('has 6 delivery.project entries', () => {
181
- expect(countBySemClass('delivery.project')).toBe(6)
182
- })
183
-
184
- it('has 5 delivery.milestone entries', () => {
185
- expect(countBySemClass('delivery.milestone')).toBe(5)
186
- })
187
-
188
- it('has 5 execution entries', () => {
189
- expect(countBySemClass('execution')).toBe(5)
190
- })
191
-
192
- it('has 4 schedule entries', () => {
193
- expect(countBySemClass('schedule')).toBe(4)
194
- })
195
-
196
- it('has 4 schedule.run entries', () => {
197
- expect(countBySemClass('schedule.run')).toBe(4)
198
- })
199
-
200
- it('has 4 request entries', () => {
201
- expect(countBySemClass('request')).toBe(4)
202
- })
203
- })
204
-
205
- // ---------------------------------------------------------------------------
206
- // Group 6: QueueTaskStatus values — all 5 present in seed with class "queue"
207
- // ---------------------------------------------------------------------------
208
-
209
- describe('QueueTaskStatus coverage in seed', () => {
210
- const queueValues: QueueTaskStatus[] = ['pending', 'processing', 'completed', 'failed', 'expired']
211
- const queueIds = DEFAULT_ORGANIZATION_MODEL_STATUSES.entries
212
- .filter((e) => e.semanticClass === 'queue')
213
- .map((e) => e.id)
214
-
215
- it.each(queueValues)('queue.%s is present as a seed entry id', (status) => {
216
- expect(queueIds).toContain(`queue.${status}`)
217
- })
218
- })
219
-
220
- // ---------------------------------------------------------------------------
221
- // Group 7: Delivery TaskStatus values — all 9 present in seed with class "delivery.task"
222
- // ---------------------------------------------------------------------------
223
-
224
- describe('TaskStatus (delivery) coverage in seed', () => {
225
- const taskValues: TaskStatus[] = [
226
- 'planned',
227
- 'in_progress',
228
- 'blocked',
229
- 'submitted',
230
- 'approved',
231
- 'revision_requested',
232
- 'rejected',
233
- 'cancelled',
234
- 'completed'
235
- ]
236
- const taskIds = DEFAULT_ORGANIZATION_MODEL_STATUSES.entries
237
- .filter((e) => e.semanticClass === 'delivery.task')
238
- .map((e) => e.id)
239
-
240
- it.each(taskValues)('delivery.task.%s is present as a seed entry id', (status) => {
241
- expect(taskIds).toContain(`delivery.task.${status}`)
242
- })
243
- })
1
+ import { describe, expect, it } from 'vitest'
2
+ import type { QueueTaskStatus } from '../../../commands/queue/types/task'
3
+ import type { TaskStatus } from '../../../business/projects/types'
4
+ import {
5
+ DEFAULT_ORGANIZATION_MODEL_STATUSES,
6
+ StatusEntrySchema,
7
+ StatusesDomainSchema,
8
+ StatusSemanticClassSchema
9
+ } from '../../domains/statuses'
10
+
11
+ // ---------------------------------------------------------------------------
12
+ // Group 1: StatusEntrySchema — positive parse
13
+ // ---------------------------------------------------------------------------
14
+
15
+ describe('StatusEntrySchema — positive parse', () => {
16
+ it('accepts a fully-specified entry (id, label, semanticClass, category)', () => {
17
+ const result = StatusEntrySchema.safeParse({
18
+ id: 'delivery.task.planned',
19
+ order: 10,
20
+ label: 'Planned',
21
+ semanticClass: 'delivery.task',
22
+ category: 'delivery'
23
+ })
24
+ expect(result.success).toBe(true)
25
+ })
26
+
27
+ it('accepts a minimal entry without category (category is optional)', () => {
28
+ const result = StatusEntrySchema.safeParse({
29
+ id: 'queue.pending',
30
+ order: 10,
31
+ label: 'Pending',
32
+ semanticClass: 'queue'
33
+ })
34
+ expect(result.success).toBe(true)
35
+ if (result.success) {
36
+ expect(result.data.category).toBeUndefined()
37
+ }
38
+ })
39
+
40
+ it('trims whitespace from id and label', () => {
41
+ const result = StatusEntrySchema.safeParse({
42
+ id: ' trimmed-id ',
43
+ order: 10,
44
+ label: ' Trimmed Label ',
45
+ semanticClass: 'execution'
46
+ })
47
+ expect(result.success).toBe(true)
48
+ if (result.success) {
49
+ expect(result.data.id).toBe('trimmed-id')
50
+ expect(result.data.label).toBe('Trimmed Label')
51
+ }
52
+ })
53
+ })
54
+
55
+ // ---------------------------------------------------------------------------
56
+ // Group 2: StatusEntrySchema — negative parse
57
+ // ---------------------------------------------------------------------------
58
+
59
+ describe('StatusEntrySchema — negative parse', () => {
60
+ it('rejects a missing id field', () => {
61
+ const result = StatusEntrySchema.safeParse({
62
+ label: 'No ID',
63
+ semanticClass: 'queue'
64
+ })
65
+ expect(result.success).toBe(false)
66
+ })
67
+
68
+ it('rejects a missing label field', () => {
69
+ const result = StatusEntrySchema.safeParse({
70
+ id: 'queue.pending',
71
+ semanticClass: 'queue'
72
+ })
73
+ expect(result.success).toBe(false)
74
+ })
75
+
76
+ it('rejects a missing semanticClass field', () => {
77
+ const result = StatusEntrySchema.safeParse({
78
+ id: 'queue.pending',
79
+ label: 'Pending'
80
+ })
81
+ expect(result.success).toBe(false)
82
+ })
83
+
84
+ it('rejects an unknown semanticClass value', () => {
85
+ const result = StatusEntrySchema.safeParse({
86
+ id: 'some.entry',
87
+ label: 'Some Entry',
88
+ semanticClass: 'not-a-real-class'
89
+ })
90
+ expect(result.success).toBe(false)
91
+ })
92
+
93
+ it('rejects a non-string id (number)', () => {
94
+ const result = StatusEntrySchema.safeParse({
95
+ id: 42,
96
+ label: 'Label',
97
+ semanticClass: 'queue'
98
+ })
99
+ expect(result.success).toBe(false)
100
+ })
101
+
102
+ it('rejects an empty string label (min length 1 after trim)', () => {
103
+ const result = StatusEntrySchema.safeParse({
104
+ id: 'some.entry',
105
+ label: ' ',
106
+ semanticClass: 'queue'
107
+ })
108
+ expect(result.success).toBe(false)
109
+ })
110
+ })
111
+
112
+ // ---------------------------------------------------------------------------
113
+ // Group 3: StatusesDomainSchema — structural tests
114
+ // ---------------------------------------------------------------------------
115
+
116
+ describe('StatusesDomainSchema — structural tests', () => {
117
+ it('accepts an empty record', () => {
118
+ const result = StatusesDomainSchema.safeParse({})
119
+ expect(result.success).toBe(true)
120
+ })
121
+
122
+ it('applies an empty-record default when the domain is omitted', () => {
123
+ const result = StatusesDomainSchema.safeParse(undefined)
124
+ expect(result.success).toBe(true)
125
+ if (result.success) {
126
+ expect(result.data).toEqual({})
127
+ }
128
+ })
129
+ })
130
+
131
+ // ---------------------------------------------------------------------------
132
+ // Group 4: Semantic class enum all 8 values declared
133
+ // ---------------------------------------------------------------------------
134
+
135
+ describe('StatusSemanticClassSchema — enum coverage', () => {
136
+ const expectedClasses = [
137
+ 'delivery.task',
138
+ 'delivery.project',
139
+ 'delivery.milestone',
140
+ 'queue',
141
+ 'execution',
142
+ 'schedule',
143
+ 'schedule.run',
144
+ 'request'
145
+ ] as const
146
+
147
+ it('enum exposes exactly 8 semantic classes', () => {
148
+ expect(StatusSemanticClassSchema.options).toHaveLength(8)
149
+ })
150
+
151
+ it.each(expectedClasses)('"%s" is a valid semanticClass value', (cls) => {
152
+ const result = StatusSemanticClassSchema.safeParse(cls)
153
+ expect(result.success).toBe(true)
154
+ })
155
+
156
+ it('every entry in the seed uses one of the 8 known semanticClass values', () => {
157
+ const valid = new Set<string>(StatusSemanticClassSchema.options)
158
+ for (const entry of Object.values(DEFAULT_ORGANIZATION_MODEL_STATUSES)) {
159
+ expect(
160
+ valid.has(entry.semanticClass),
161
+ `Unexpected semanticClass "${entry.semanticClass}" on entry "${entry.id}"`
162
+ ).toBe(true)
163
+ }
164
+ })
165
+
166
+ it('all 8 semanticClass values have at least one seed entry', () => {
167
+ const presentClasses = new Set(Object.values(DEFAULT_ORGANIZATION_MODEL_STATUSES).map((e) => e.semanticClass))
168
+ for (const cls of StatusSemanticClassSchema.options) {
169
+ expect(presentClasses.has(cls), `No seed entry found for semanticClass "${cls}"`).toBe(true)
170
+ }
171
+ })
172
+ })
173
+
174
+ // ---------------------------------------------------------------------------
175
+ // Group 5: Seed completeness — per-group counts
176
+ // ---------------------------------------------------------------------------
177
+
178
+ describe('DEFAULT_ORGANIZATION_MODEL_STATUSES seed — per-group counts', () => {
179
+ function countBySemClass(cls: string) {
180
+ return Object.values(DEFAULT_ORGANIZATION_MODEL_STATUSES).filter((e) => e.semanticClass === cls).length
181
+ }
182
+
183
+ it('has 6 delivery.project entries', () => {
184
+ expect(countBySemClass('delivery.project')).toBe(6)
185
+ })
186
+
187
+ it('has 5 delivery.milestone entries', () => {
188
+ expect(countBySemClass('delivery.milestone')).toBe(5)
189
+ })
190
+
191
+ it('has 5 execution entries', () => {
192
+ expect(countBySemClass('execution')).toBe(5)
193
+ })
194
+
195
+ it('has 4 schedule entries', () => {
196
+ expect(countBySemClass('schedule')).toBe(4)
197
+ })
198
+
199
+ it('has 4 schedule.run entries', () => {
200
+ expect(countBySemClass('schedule.run')).toBe(4)
201
+ })
202
+
203
+ it('has 4 request entries', () => {
204
+ expect(countBySemClass('request')).toBe(4)
205
+ })
206
+ })
207
+
208
+ // ---------------------------------------------------------------------------
209
+ // Group 6: QueueTaskStatus values — all 5 present in seed with class "queue"
210
+ // ---------------------------------------------------------------------------
211
+
212
+ describe('QueueTaskStatus coverage in seed', () => {
213
+ const queueValues: QueueTaskStatus[] = ['pending', 'processing', 'completed', 'failed', 'expired']
214
+ const queueIds = Object.values(DEFAULT_ORGANIZATION_MODEL_STATUSES)
215
+ .filter((e) => e.semanticClass === 'queue')
216
+ .map((e) => e.id)
217
+
218
+ it.each(queueValues)('queue.%s is present as a seed entry id', (status) => {
219
+ expect(queueIds).toContain(`queue.${status}`)
220
+ })
221
+ })
222
+
223
+ // ---------------------------------------------------------------------------
224
+ // Group 7: Delivery TaskStatus values all 9 present in seed with class "delivery.task"
225
+ // ---------------------------------------------------------------------------
226
+
227
+ describe('TaskStatus (delivery) coverage in seed', () => {
228
+ const taskValues: TaskStatus[] = [
229
+ 'planned',
230
+ 'in_progress',
231
+ 'blocked',
232
+ 'submitted',
233
+ 'approved',
234
+ 'revision_requested',
235
+ 'rejected',
236
+ 'cancelled',
237
+ 'completed'
238
+ ]
239
+ const taskIds = Object.values(DEFAULT_ORGANIZATION_MODEL_STATUSES)
240
+ .filter((e) => e.semanticClass === 'delivery.task')
241
+ .map((e) => e.id)
242
+
243
+ it.each(taskValues)('delivery.task.%s is present as a seed entry id', (status) => {
244
+ expect(taskIds).toContain(`delivery.task.${status}`)
245
+ })
246
+ })