@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.
Files changed (112) hide show
  1. package/dist/index.d.ts +2330 -2391
  2. package/dist/index.js +2322 -1147
  3. package/dist/knowledge/index.d.ts +702 -1136
  4. package/dist/knowledge/index.js +9 -9
  5. package/dist/organization-model/index.d.ts +2330 -2391
  6. package/dist/organization-model/index.js +2322 -1147
  7. package/dist/test-utils/index.d.ts +703 -1106
  8. package/dist/test-utils/index.js +1735 -1089
  9. package/package.json +1 -1
  10. package/src/__tests__/template-core-compatibility.test.ts +11 -79
  11. package/src/_gen/__tests__/__snapshots__/contracts.md.snap +360 -98
  12. package/src/business/acquisition/api-schemas.test.ts +2 -2
  13. package/src/business/acquisition/api-schemas.ts +7 -9
  14. package/src/business/acquisition/build-templates.test.ts +4 -4
  15. package/src/business/acquisition/build-templates.ts +72 -30
  16. package/src/business/acquisition/crm-state-actions.test.ts +13 -11
  17. package/src/business/acquisition/types.ts +7 -3
  18. package/src/execution/engine/agent/core/types.ts +1 -1
  19. package/src/execution/engine/workflow/types.ts +2 -2
  20. package/src/knowledge/README.md +8 -7
  21. package/src/knowledge/__tests__/queries.test.ts +74 -73
  22. package/src/knowledge/format.ts +10 -9
  23. package/src/knowledge/index.ts +1 -1
  24. package/src/knowledge/published.ts +1 -1
  25. package/src/knowledge/queries.ts +26 -25
  26. package/src/organization-model/README.md +66 -26
  27. package/src/organization-model/__tests__/content-kinds-registry.test.ts +210 -0
  28. package/src/organization-model/__tests__/defaults.test.ts +72 -98
  29. package/src/organization-model/__tests__/domains/actions.test.ts +56 -0
  30. package/src/organization-model/__tests__/domains/customers.test.ts +299 -295
  31. package/src/organization-model/__tests__/domains/entities.test.ts +56 -0
  32. package/src/organization-model/__tests__/domains/goals.test.ts +493 -479
  33. package/src/organization-model/__tests__/domains/identity.test.ts +280 -279
  34. package/src/organization-model/__tests__/domains/navigation.test.ts +268 -212
  35. package/src/organization-model/__tests__/domains/offerings.test.ts +414 -419
  36. package/src/organization-model/__tests__/domains/policies.test.ts +323 -0
  37. package/src/organization-model/__tests__/domains/resource-mappings.test.ts +271 -271
  38. package/src/organization-model/__tests__/domains/resources.test.ts +159 -37
  39. package/src/organization-model/__tests__/domains/roles.test.ts +147 -86
  40. package/src/organization-model/__tests__/domains/statuses.test.ts +246 -243
  41. package/src/organization-model/__tests__/domains/systems.test.ts +67 -51
  42. package/src/organization-model/__tests__/flatten-additive-merge.test.ts +361 -0
  43. package/src/organization-model/__tests__/foundation.test.ts +74 -102
  44. package/src/organization-model/__tests__/get-resources-for-system.test.ts +144 -0
  45. package/src/organization-model/__tests__/graph.test.ts +899 -71
  46. package/src/organization-model/__tests__/knowledge.test.ts +173 -52
  47. package/src/organization-model/__tests__/lookup-helpers.test.ts +438 -0
  48. package/src/organization-model/__tests__/migration-helpers.test.ts +591 -0
  49. package/src/organization-model/__tests__/prospecting-ssot.test.ts +36 -27
  50. package/src/organization-model/__tests__/recursive-system-schema.test.ts +520 -0
  51. package/src/organization-model/__tests__/resolve.test.ts +174 -23
  52. package/src/organization-model/__tests__/schema.test.ts +291 -114
  53. package/src/organization-model/__tests__/surface-projection.test.ts +207 -97
  54. package/src/organization-model/catalogs/lead-gen.ts +144 -0
  55. package/src/organization-model/content-kinds/config.ts +36 -0
  56. package/src/organization-model/content-kinds/index.ts +74 -0
  57. package/src/organization-model/content-kinds/pipeline.ts +68 -0
  58. package/src/organization-model/content-kinds/registry.ts +44 -0
  59. package/src/organization-model/content-kinds/status.ts +71 -0
  60. package/src/organization-model/content-kinds/template.ts +83 -0
  61. package/src/organization-model/content-kinds/types.ts +117 -0
  62. package/src/organization-model/contracts.ts +13 -3
  63. package/src/organization-model/defaults.ts +488 -96
  64. package/src/organization-model/domains/actions.ts +239 -0
  65. package/src/organization-model/domains/customers.ts +78 -75
  66. package/src/organization-model/domains/entities.ts +144 -0
  67. package/src/organization-model/domains/goals.ts +83 -80
  68. package/src/organization-model/domains/knowledge.ts +74 -16
  69. package/src/organization-model/domains/navigation.ts +107 -384
  70. package/src/organization-model/domains/offerings.ts +71 -66
  71. package/src/organization-model/domains/policies.ts +102 -0
  72. package/src/organization-model/domains/projects.ts +14 -48
  73. package/src/organization-model/domains/prospecting.ts +62 -181
  74. package/src/organization-model/domains/resources.ts +81 -24
  75. package/src/organization-model/domains/roles.ts +13 -10
  76. package/src/organization-model/domains/sales.ts +10 -219
  77. package/src/organization-model/domains/shared.ts +57 -57
  78. package/src/organization-model/domains/statuses.ts +339 -130
  79. package/src/organization-model/domains/systems.ts +186 -29
  80. package/src/organization-model/foundation.ts +54 -67
  81. package/src/organization-model/graph/build.ts +682 -54
  82. package/src/organization-model/graph/link.ts +1 -1
  83. package/src/organization-model/graph/schema.ts +24 -9
  84. package/src/organization-model/graph/types.ts +20 -7
  85. package/src/organization-model/helpers.ts +231 -26
  86. package/src/organization-model/index.ts +116 -5
  87. package/src/organization-model/migration-helpers.ts +249 -0
  88. package/src/organization-model/organization-graph.mdx +16 -15
  89. package/src/organization-model/organization-model.mdx +89 -41
  90. package/src/organization-model/published.ts +120 -18
  91. package/src/organization-model/resolve.ts +117 -54
  92. package/src/organization-model/schema.ts +561 -140
  93. package/src/organization-model/surface-projection.ts +116 -122
  94. package/src/organization-model/types.ts +102 -21
  95. package/src/platform/constants/versions.ts +1 -1
  96. package/src/platform/registry/__tests__/command-view.test.ts +6 -8
  97. package/src/platform/registry/__tests__/resource-link.test.ts +13 -8
  98. package/src/platform/registry/__tests__/resource-registry.integration.test.ts +16 -31
  99. package/src/platform/registry/__tests__/resource-registry.nested-systems.test.ts +245 -0
  100. package/src/platform/registry/__tests__/resource-registry.test.ts +9 -7
  101. package/src/platform/registry/__tests__/validation.test.ts +15 -11
  102. package/src/platform/registry/resource-registry.ts +20 -8
  103. package/src/platform/registry/serialization.ts +7 -7
  104. package/src/platform/registry/types.ts +3 -3
  105. package/src/platform/registry/validation.ts +17 -15
  106. package/src/reference/_generated/contracts.md +362 -99
  107. package/src/reference/glossary.md +18 -18
  108. package/src/supabase/database.types.ts +60 -0
  109. package/src/test-utils/test-utils.test.ts +1 -6
  110. package/src/organization-model/__tests__/domains/operations.test.ts +0 -203
  111. package/src/organization-model/domains/features.ts +0 -31
  112. package/src/organization-model/domains/operations.ts +0 -85
@@ -0,0 +1,249 @@
1
+ /**
2
+ * Migration helpers — Phase 4 internals swap
3
+ *
4
+ * External signatures are UNCHANGED from the pre-Phase-4 era so callers remain
5
+ * mechanical. Internally, all compound-domain reads (model.sales.pipelines,
6
+ * model.prospecting.*, model.projects.*) are replaced by walking system.content
7
+ * via listAllSystems() and filtering by (kind, type).
8
+ *
9
+ * Registry entries used:
10
+ * 'schema:pipeline' — one pipeline per owning system
11
+ * 'schema:stage' — stage within a pipeline; parentContentId = pipeline local id
12
+ * 'schema:template' — prospecting build template
13
+ * 'schema:template-step' — step within a template; parentContentId = template local id
14
+ * 'schema:status-flow' — status set for a project/milestone/task scope
15
+ * 'schema:status' — single status within a flow; parentContentId = status-flow local id
16
+ */
17
+
18
+ import type { OrganizationModel } from './types'
19
+ import type { z } from 'zod'
20
+ import type { SalesPipelineSchema, SalesStageSchema } from './domains/sales'
21
+ import type { ProspectingBuildTemplateSchema, ProspectingLifecycleStageSchema } from './domains/prospecting'
22
+ import type { ProjectsDomainStateSchema } from './domains/projects'
23
+ import { listAllSystems } from './helpers'
24
+
25
+ // ---------------------------------------------------------------------------
26
+ // Locally-scoped inferred types — external signatures use these shapes.
27
+ // ---------------------------------------------------------------------------
28
+ type Pipeline = z.infer<typeof SalesPipelineSchema>
29
+ type Stage = z.infer<typeof SalesStageSchema>
30
+ type BuildTemplate = z.infer<typeof ProspectingBuildTemplateSchema>
31
+ type ProspectingStage = z.infer<typeof ProspectingLifecycleStageSchema>
32
+ type ProjectStatus = z.infer<typeof ProjectsDomainStateSchema>
33
+
34
+ // ---------------------------------------------------------------------------
35
+ // Sales — Pipelines + Stages
36
+ // ---------------------------------------------------------------------------
37
+
38
+ /**
39
+ * Return all sales pipelines defined in the model, each tagged with the
40
+ * system path of the owning system.
41
+ *
42
+ * Phase 4: walks every system via listAllSystems(), finds content nodes where
43
+ * (kind, type) === ('schema', 'pipeline'), and reconstructs the Pipeline shape
44
+ * by pulling sibling stage content nodes (parentContentId === pipeline local id).
45
+ */
46
+ export function getAllPipelines(model: OrganizationModel): Array<{ systemPath: string; pipeline: Pipeline }> {
47
+ const results: Array<{ systemPath: string; pipeline: Pipeline }> = []
48
+
49
+ for (const { path: systemPath, system } of listAllSystems(model)) {
50
+ const content = system.content ?? {}
51
+
52
+ for (const [localId, node] of Object.entries(content)) {
53
+ if (node.kind !== 'schema' || node.type !== 'pipeline') continue
54
+
55
+ const data = (node.data ?? {}) as Record<string, unknown>
56
+ const stages: Stage[] = Object.entries(content)
57
+ .filter(([, s]) => s.kind === 'schema' && s.type === 'stage' && s.parentContentId === localId)
58
+ .map(([stageLocalId, s]) => {
59
+ const sd = (s.data ?? {}) as Record<string, unknown>
60
+ return {
61
+ id: stageLocalId,
62
+ label: s.label ?? stageLocalId,
63
+ order: typeof sd.order === 'number' ? sd.order : 0,
64
+ semanticClass: (sd.semanticClass as Stage['semanticClass']) ?? 'open',
65
+ surfaceIds: Array.isArray(sd.surfaceIds) ? (sd.surfaceIds as string[]) : [],
66
+ resourceIds: Array.isArray(sd.resourceIds) ? (sd.resourceIds as string[]) : [],
67
+ color: typeof sd.color === 'string' ? sd.color : undefined
68
+ } satisfies Stage
69
+ })
70
+ .sort((a, b) => a.order - b.order)
71
+
72
+ const pipeline: Pipeline = {
73
+ id: localId,
74
+ label: node.label ?? localId,
75
+ entityId: typeof data.entityId === 'string' ? data.entityId : '',
76
+ stages,
77
+ ...(typeof node.description === 'string' ? { description: node.description } : {})
78
+ }
79
+
80
+ results.push({ systemPath, pipeline })
81
+ }
82
+ }
83
+
84
+ return results
85
+ }
86
+
87
+ /**
88
+ * Return the stages belonging to a given pipeline, identified by systemPath + pipelineLocalId.
89
+ *
90
+ * Phase 4: resolves the system at systemPath, filters its content for stage nodes
91
+ * where parentContentId === pipelineLocalId.
92
+ *
93
+ * @param model - The resolved organization model.
94
+ * @param systemPath - Dot-separated path to the owning system (e.g. 'sales.crm').
95
+ * @param pipelineLocalId - The local content id of the target pipeline node.
96
+ */
97
+ export function getStagesInPipeline(model: OrganizationModel, systemPath: string, pipelineLocalId: string): Stage[] {
98
+ const allSystems = listAllSystems(model)
99
+ const entry = allSystems.find((s) => s.path === systemPath)
100
+ if (!entry) return []
101
+
102
+ const content = entry.system.content ?? {}
103
+ return Object.entries(content)
104
+ .filter(([, node]) => node.kind === 'schema' && node.type === 'stage' && node.parentContentId === pipelineLocalId)
105
+ .map(([stageLocalId, s]) => {
106
+ const sd = (s.data ?? {}) as Record<string, unknown>
107
+ return {
108
+ id: stageLocalId,
109
+ label: s.label ?? stageLocalId,
110
+ order: typeof sd.order === 'number' ? sd.order : 0,
111
+ semanticClass: (sd.semanticClass as Stage['semanticClass']) ?? 'open',
112
+ surfaceIds: Array.isArray(sd.surfaceIds) ? (sd.surfaceIds as string[]) : [],
113
+ resourceIds: Array.isArray(sd.resourceIds) ? (sd.resourceIds as string[]) : [],
114
+ color: typeof sd.color === 'string' ? sd.color : undefined
115
+ } satisfies Stage
116
+ })
117
+ .sort((a, b) => a.order - b.order)
118
+ }
119
+
120
+ // ---------------------------------------------------------------------------
121
+ // Prospecting — Build templates
122
+ // ---------------------------------------------------------------------------
123
+
124
+ /**
125
+ * Return all prospecting build templates defined in the model.
126
+ *
127
+ * Phase 4: walks every system, finds content nodes where
128
+ * (kind, type) === ('schema', 'template'), reconstructs BuildTemplate shape
129
+ * by pulling sibling template-step nodes (parentContentId === template local id).
130
+ */
131
+ export function getAllBuildTemplates(model: OrganizationModel): BuildTemplate[] {
132
+ const results: BuildTemplate[] = []
133
+
134
+ for (const { system } of listAllSystems(model)) {
135
+ const content = system.content ?? {}
136
+
137
+ for (const [localId, node] of Object.entries(content)) {
138
+ if (node.kind !== 'schema' || node.type !== 'template') continue
139
+ const nd = (node.data ?? {}) as Record<string, unknown>
140
+
141
+ const steps = Object.entries(content)
142
+ .filter(([, s]) => s.kind === 'schema' && s.type === 'template-step' && s.parentContentId === localId)
143
+ .map(([stepLocalId, s]) => {
144
+ const sd = (s.data ?? {}) as Record<string, unknown>
145
+ return {
146
+ id: stepLocalId,
147
+ label: s.label ?? stepLocalId,
148
+ ...(s.description ? { description: s.description } : {}),
149
+ // Pass through all data fields — template-step payload is richer than Pipeline;
150
+ // Wave 2 authors the canonical shape; Wave 4 verifies round-trip fidelity.
151
+ ...sd
152
+ }
153
+ })
154
+
155
+ results.push({
156
+ id: localId,
157
+ label: node.label ?? localId,
158
+ ...(node.description ? { description: node.description } : {}),
159
+ ...(typeof nd.color === 'string' ? { color: nd.color } : {}),
160
+ // BuildTemplate requires steps array — cast via spread; Wave 4 adds type-safe assertions.
161
+ steps: steps as BuildTemplate['steps']
162
+ })
163
+ }
164
+ }
165
+
166
+ return results
167
+ }
168
+
169
+ /**
170
+ * Return the prospecting lifecycle stages for a given entity kind.
171
+ *
172
+ * Phase 4: walks every system, finds content nodes where
173
+ * (kind, type) === ('schema', 'stage') AND data.entityKind === kind.
174
+ * Prospecting stages are distinguished from pipeline stages by the presence of
175
+ * data.entityKind ('company' | 'contact') authored by Wave 2.
176
+ *
177
+ * @param kind - 'company' or 'contact'.
178
+ */
179
+ export function getAllProspectingStages(model: OrganizationModel, kind: 'company' | 'contact'): ProspectingStage[] {
180
+ const results: ProspectingStage[] = []
181
+
182
+ for (const { system } of listAllSystems(model)) {
183
+ const content = system.content ?? {}
184
+
185
+ for (const [localId, node] of Object.entries(content)) {
186
+ if (node.kind !== 'schema' || node.type !== 'stage') continue
187
+ const sd = (node.data ?? {}) as Record<string, unknown>
188
+ if (sd.entityKind !== kind) continue
189
+
190
+ results.push({
191
+ id: localId,
192
+ label: node.label ?? localId,
193
+ order: typeof sd.order === 'number' ? sd.order : 0,
194
+ ...(typeof sd.color === 'string' ? { color: sd.color } : {}),
195
+ ...(node.description ? { description: node.description } : {})
196
+ } satisfies ProspectingStage)
197
+ }
198
+ }
199
+
200
+ return results.sort((a, b) => a.order - b.order)
201
+ }
202
+
203
+ // ---------------------------------------------------------------------------
204
+ // Projects — Statuses
205
+ // ---------------------------------------------------------------------------
206
+
207
+ /**
208
+ * Return the project statuses for a given entity type.
209
+ *
210
+ * Phase 4: walks every system, finds status-flow content nodes where
211
+ * data.appliesTo === appliesTo, then collects their child status nodes
212
+ * (parentContentId === status-flow local id), sorted by order.
213
+ *
214
+ * @param appliesTo - 'project', 'milestone', or 'task'.
215
+ */
216
+ export function getAllProjectStatuses(
217
+ model: OrganizationModel,
218
+ appliesTo: 'project' | 'milestone' | 'task'
219
+ ): ProjectStatus[] {
220
+ const results: ProjectStatus[] = []
221
+
222
+ for (const { system } of listAllSystems(model)) {
223
+ const content = system.content ?? {}
224
+
225
+ // Find the status-flow node for this appliesTo scope.
226
+ for (const [flowLocalId, flowNode] of Object.entries(content)) {
227
+ if (flowNode.kind !== 'schema' || flowNode.type !== 'status-flow') continue
228
+ const fd = (flowNode.data ?? {}) as Record<string, unknown>
229
+ if (fd.appliesTo !== appliesTo) continue
230
+
231
+ // Collect child status nodes.
232
+ for (const [statusLocalId, statusNode] of Object.entries(content)) {
233
+ if (statusNode.kind !== 'schema' || statusNode.type !== 'status') continue
234
+ if (statusNode.parentContentId !== flowLocalId) continue
235
+
236
+ const sd = (statusNode.data ?? {}) as Record<string, unknown>
237
+ results.push({
238
+ id: statusLocalId,
239
+ label: statusNode.label ?? statusLocalId,
240
+ order: typeof sd.order === 'number' ? sd.order : 0,
241
+ ...(typeof sd.color === 'string' ? { color: sd.color } : {}),
242
+ ...(statusNode.description ? { description: statusNode.description } : {})
243
+ } satisfies ProjectStatus)
244
+ }
245
+ }
246
+ }
247
+
248
+ return results.sort((a, b) => a.order - b.order)
249
+ }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: Organization Graph
3
- description: Organization OS graph layer documentation for the organization graph derived from flat Organization Model features and resource metadata links.
3
+ description: Organization OS graph layer documentation for the organization graph derived from Organization Model Systems, resources, capabilities, and typed links.
4
4
  ---
5
5
 
6
6
  ## Overview
@@ -24,30 +24,31 @@ Graph contracts live in `@repo/core`; rendering lives in `@repo/ui`.
24
24
  Node kinds:
25
25
 
26
26
  - `organization`
27
- - `feature`
28
- - `surface`
29
- - `entity`
27
+ - `system`
28
+ - `role`
30
29
  - `capability`
31
30
  - `resource`
31
+ - `knowledge`
32
+ - `policy`
32
33
 
33
34
  Edge kinds:
34
35
 
35
36
  - `contains`
36
37
  - `references`
37
- - `exposes`
38
38
  - `maps_to`
39
- - `operates-on`
40
39
  - `uses`
40
+ - `governs`
41
+ - `governed-by`
41
42
 
42
- Feature nodes come from the flat `OrganizationModel.features` array. Their graph IDs use `feature:<id>`, such as `feature:sales.crm`.
43
+ System nodes come from the id-keyed `OrganizationModel.systems` map. Their graph IDs use `system:<id>`, such as `system:sales.crm`.
43
44
 
44
- Resource edges come from resource metadata:
45
+ Resource and capability edges are derived from canonical OM maps:
45
46
 
46
47
  ```ts
47
- links: [
48
- { nodeId: 'feature:sales.lead-gen', kind: 'operates-on' },
49
- { nodeId: 'integration:instantly', kind: 'uses' }
50
- ]
48
+ // ResourceEntry.systemPath => system -> resource contains
49
+ // SystemEntry.capabilities[] => system -> capability uses
50
+ // Capability.resourceId => capability -> resource maps_to
51
+ // AgentResource.invocations[] => agent resource -> invocation target uses/references
51
52
  ```
52
53
 
53
54
  ## Build Pipeline
@@ -61,9 +62,9 @@ interface BuildOrganizationGraphInput {
61
62
 
62
63
  `buildOrganizationGraph`:
63
64
 
64
- 1. Reads flat Organization Model features and derives `feature:*` nodes.
65
- 2. Reads Command View resources, including integration resources, as `resource` nodes with `resourceType` metadata.
66
- 3. Emits authored graph links from resource/entity/capability metadata.
65
+ 1. Reads Organization Model Systems and derives `system:*` nodes.
66
+ 2. Reads OM resources, including workflow, agent, integration, and script resources, as `resource` nodes.
67
+ 3. Emits derived graph links from System, Resource, Capability, Agent invocation, and Knowledge contracts.
67
68
  4. Bridges Command View runtime topology into resource nodes and relationship edges.
68
69
  5. Returns a renderer-agnostic DTO.
69
70
 
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  title: Organization Model
3
- description: Organization OS Model layer documentation for the flat feature hierarchy, semantic domains, resource descriptors, and curated @elevasis/core public API.
3
+ description: Organization OS Model layer documentation for the System hierarchy, semantic domains, resource descriptors, and curated @elevasis/core public API.
4
4
  ---
5
5
 
6
6
  ## Overview
7
7
 
8
- The organization model is the semantic contract that maps an organization's product shape to flat feature hierarchy, business semantics, shell navigation, and graph binding. It is schema-first, versioned, and validated.
8
+ The organization model is the semantic contract that maps an organization's System hierarchy, business semantics, shell navigation, resource governance, and graph binding. It is schema-first, versioned, and validated.
9
9
 
10
10
  The model is authored in `@repo/core` and published through the curated `@elevasis/core/organization-model` surface.
11
11
 
@@ -24,7 +24,7 @@ The model is authored in `@repo/core` and published through the curated `@elevas
24
24
  Top-level fields on `OrganizationModel`:
25
25
 
26
26
  - `version`
27
- - `features`
27
+ - `domainMetadata`
28
28
  - `branding`
29
29
  - `navigation`
30
30
  - `sales`
@@ -37,23 +37,26 @@ Top-level fields on `OrganizationModel`:
37
37
  - `goals`
38
38
  - `systems`
39
39
  - `resources`
40
+ - `capabilities`
41
+ - `policies`
40
42
  - `statuses`
41
- - `operations`
42
43
  - `knowledge`
43
44
 
44
- Resource identity is authored inside `OrganizationModel.resources.entries`. Runtime workflows, agents, and integrations import those descriptors, derive `resourceId` and kind from them, and attach executable behavior in operations code.
45
+ The pure collection domains are id-keyed maps: `systems`, `roles`, `goals`, `customers`, `offerings`, `resources`, `capabilities`, `policies`, and `statuses`. The map key must match the entry `id`. Entries carry `order` for deterministic ordered views; use `listDomain(record)` when order matters.
45
46
 
46
- ## Feature Shape
47
+ Resource identity is authored inside `OrganizationModel.resources`. Runtime workflows, agents, integrations, and scripts import those descriptors, derive `resourceId` and kind from them, and attach executable behavior in operations code.
47
48
 
48
- `OrganizationModel.features` is a flat array. Hierarchy is derived from dotted IDs:
49
+ ## System Shape
50
+
51
+ `OrganizationModel.systems` is the canonical semantic domain map. Hierarchy is derived from `parentSystemId` and dotted IDs:
49
52
 
50
53
  ```ts
51
- features: [
52
- { id: 'dashboard', label: 'Dashboard', enabled: true, path: '/', uiPosition: 'sidebar-primary' },
53
- { id: 'sales', label: 'Sales', enabled: true, uiPosition: 'sidebar-primary' },
54
- { id: 'sales.crm', label: 'CRM', enabled: true, path: '/crm' },
55
- { id: 'operations.resources', label: 'Resources', enabled: true, path: '/operations/resources' }
56
- ]
54
+ systems: {
55
+ dashboard: { id: 'dashboard', order: 10, label: 'Dashboard', lifecycle: 'active' },
56
+ sales: { id: 'sales', order: 20, label: 'Sales', lifecycle: 'active' },
57
+ clients: { id: 'clients', order: 30, label: 'Clients', lifecycle: 'active' },
58
+ projects: { id: 'projects', order: 40, label: 'Projects', lifecycle: 'active' }
59
+ }
57
60
  ```
58
61
 
59
62
  Authored fields:
@@ -61,29 +64,74 @@ Authored fields:
61
64
  - `id`
62
65
  - `label`
63
66
  - `description`
64
- - `enabled`
65
- - `path`
66
- - `icon`
67
- - `color`
68
- - `uiPosition`
67
+ - `kind`
68
+ - `parentSystemId`
69
+ - `ui`
70
+ - `lifecycle`
69
71
  - `requiresAdmin`
70
- - `devOnly`
72
+ - `capabilities`
73
+ - `policies`
74
+ - `order`
75
+
76
+ Systems describe ownership, hierarchy, lifecycle, access, and governance. Sidebar presentation lives in `navigation.sidebar`, not on System entries. UI-backed Systems may still provide `ui.path` for route matching during the migration, but `ui.surfaces` is not an authored contract. `lifecycle` replaces the old feature enabled/dev-only split.
71
77
 
72
- Containers omit `path`; leaves provide `path`. `uiPosition`, `requiresAdmin`, and `devOnly` inherit from ancestors.
73
- Development-only features remain defined and enabled with `devOnly: true`; shell consumers hide those entries and route paths outside development mode while preserving the semantic contract.
78
+ ## Navigation Shape
74
79
 
75
- Navigation surfaces may also carry `devOnly` for compatibility with the legacy/domain navigation model. `knowledge.command-view` is intentionally development-only while its graph visualization modes continue to mature.
80
+ `OrganizationModel.navigation.sidebar` is the authored shell tree. It has `primary` and `bottom` sections whose records contain recursive group nodes and routeable surface nodes:
81
+
82
+ ```ts
83
+ navigation: {
84
+ sidebar: {
85
+ primary: {
86
+ dashboard: {
87
+ type: 'surface',
88
+ order: 10,
89
+ label: 'Dashboard',
90
+ path: '/',
91
+ surfaceType: 'dashboard',
92
+ targets: { systems: ['dashboard'] }
93
+ },
94
+ business: {
95
+ type: 'group',
96
+ order: 20,
97
+ label: 'Business',
98
+ children: {
99
+ sales: {
100
+ type: 'surface',
101
+ order: 10,
102
+ label: 'Sales',
103
+ path: '/sales',
104
+ surfaceType: 'page',
105
+ targets: { systems: ['sales'] }
106
+ },
107
+ clients: {
108
+ type: 'surface',
109
+ order: 20,
110
+ label: 'Clients',
111
+ path: '/clients',
112
+ surfaceType: 'list',
113
+ targets: { systems: ['clients'] }
114
+ }
115
+ }
116
+ }
117
+ },
118
+ bottom: {}
119
+ }
120
+ }
121
+ ```
122
+
123
+ Dashboard is ordered before Business in the primary sidebar. Business is a navigation group only; it is not a System and it is not a URL namespace. Routeable leaves are projected into flat surface DTOs by `projectOrganizationSurfaces(model)`.
76
124
 
77
125
  ## Graph IDs and Resource Descriptors
78
126
 
79
127
  Cross-collection links use kind-prefixed graph IDs:
80
128
 
81
- - `feature:sales.crm`
129
+ - `system:sales.crm`
82
130
  - `integration:instantly`
83
131
  - `resource:lead-import`
84
- - `capability:operations.queue.review`
132
+ - `action:operations.queue.review`
85
133
 
86
- Resource identity is authored in the OM Resources domain. Operations imports descriptors from `organizationModel.resources.entries` and derives runtime `resourceId` / `type` while attaching executable behavior.
134
+ Resource identity is authored in the OM Resources domain. Operations imports descriptors from `organizationModel.resources` and derives runtime `resourceId` / `type` while attaching executable behavior.
87
135
 
88
136
  ```ts
89
137
  import { defineResources } from '@elevasis/core/organization-model'
@@ -92,23 +140,22 @@ export const resourceDescriptors = defineResources({
92
140
  leadImport: {
93
141
  id: 'lead-import',
94
142
  kind: 'workflow',
95
- systemId: 'sys.prospecting',
143
+ systemPath: 'sales.lead-gen',
96
144
  ownerRoleId: 'role-ops-lead',
97
145
  status: 'active',
98
- capabilityKey: 'prospecting.lead-import'
146
+ actionKey: 'prospecting.lead-import'
99
147
  }
100
148
  })
101
149
 
102
150
  export const resourceGovernanceModel = {
103
- systems: {
104
- systems
105
- },
106
- resources: {
107
- entries: Object.values(resourceDescriptors)
108
- }
151
+ systems,
152
+ resources: resourceDescriptors
109
153
  } as const
110
154
  ```
111
155
 
156
+ Legacy `sys.*` paths may still appear in older examples and external compatibility mirrors.
157
+ For new Organization OS examples, prefer the current semantic System path.
158
+
112
159
  ## Domain Semantics
113
160
 
114
161
  The model keeps business semantics in named domains:
@@ -119,7 +166,7 @@ The model keeps business semantics in named domains:
119
166
  - `identity`, `customers`, `offerings`, `roles`, `goals` -- organizational reality
120
167
  - `systems` -- bounded contexts that group governed operational resources
121
168
  - `resources` -- governance-only workflow, agent, and integration descriptors
122
- - `statuses` and `operations` -- runtime/vibe-layer semantic registries
169
+ - `statuses` -- runtime/vibe-layer semantic registry
123
170
  - `knowledge` -- playbooks, strategies, references, and graph-governing links
124
171
 
125
172
  ## Authoring and Resolution
@@ -128,15 +175,16 @@ The model keeps business semantics in named domains:
128
175
  - `resolveOrganizationModel(partial)` deep-merges a partial override into `DEFAULT_ORGANIZATION_MODEL` and validates the result.
129
176
  - `createFoundationOrganizationModel(partial)` resolves the canonical model and returns template-facing helpers.
130
177
  - Plain objects merge recursively.
178
+ - Id-keyed domain maps merge additively by key.
131
179
  - Arrays replace defaults.
132
180
 
133
181
  ## Referential Integrity
134
182
 
135
183
  `OrganizationModelSchema` validates:
136
184
 
137
- - unique feature IDs
138
- - ancestor existence for dotted feature IDs
139
- - container/leaf path rules
185
+ - unique System IDs
186
+ - ancestor existence for dotted System IDs and `parentSystemId`
187
+ - UI path rules for Systems with UI presence
140
188
  - valid sidebar positions
141
189
  - reality-domain cross references such as offering target segments and role reporting lines
142
190
  - system, resource, role, knowledge, and goal cross references used by resource governance
@@ -145,11 +193,11 @@ The model keeps business semantics in named domains:
145
193
 
146
194
  ## Provider Integration
147
195
 
148
- `ElevasisFeaturesProvider` uses the organization model to:
196
+ `ElevasisSystemsProvider` uses the organization model to:
149
197
 
150
- 1. validate each manifest's `featureId`
151
- 2. resolve effective feature access
152
- 3. derive sidebar entries from `features`
198
+ 1. validate each manifest's `systemId`
199
+ 2. resolve effective system access
200
+ 3. derive sidebar entries from `navigation.sidebar`
153
201
  4. expose shell helpers such as `childrenOf`, `ancestorsOf`, and `findByPath`
154
202
  5. bridge the operations graph into shared UI
155
203