@elevasis/core 0.26.0 → 0.27.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 (34) hide show
  1. package/dist/index.d.ts +5 -5
  2. package/dist/index.js +209 -173
  3. package/dist/knowledge/index.d.ts +21 -21
  4. package/dist/organization-model/index.d.ts +5 -5
  5. package/dist/organization-model/index.js +209 -173
  6. package/dist/test-utils/index.d.ts +2 -2
  7. package/dist/test-utils/index.js +182 -126
  8. package/package.json +1 -1
  9. package/src/_gen/__tests__/__snapshots__/contracts.md.snap +976 -1063
  10. package/src/business/acquisition/api-schemas.test.ts +1962 -1841
  11. package/src/business/acquisition/api-schemas.ts +1461 -1464
  12. package/src/business/acquisition/crm-next-action.test.ts +45 -25
  13. package/src/business/acquisition/crm-next-action.ts +227 -220
  14. package/src/business/acquisition/crm-priority.test.ts +41 -8
  15. package/src/business/acquisition/crm-priority.ts +365 -349
  16. package/src/business/acquisition/crm-state-actions.test.ts +208 -153
  17. package/src/business/acquisition/derive-actions.test.ts +90 -13
  18. package/src/business/acquisition/derive-actions.ts +8 -139
  19. package/src/business/acquisition/ontology-validation.ts +72 -158
  20. package/src/business/pdf/sections/investment.ts +1 -1
  21. package/src/business/pdf/sections/summary-investment.ts +1 -1
  22. package/src/execution/engine/tools/tool-maps.ts +872 -831
  23. package/src/organization-model/__tests__/cross-ref.test.ts +167 -0
  24. package/src/organization-model/__tests__/published-zero-leak.test.ts +60 -1
  25. package/src/organization-model/__tests__/resolve.test.ts +1 -1
  26. package/src/organization-model/__tests__/schema-refinements.test.ts +72 -0
  27. package/src/organization-model/cross-ref.ts +175 -0
  28. package/src/organization-model/domains/branding.ts +6 -6
  29. package/src/organization-model/domains/sales.test.ts +104 -218
  30. package/src/organization-model/domains/sales.ts +212 -375
  31. package/src/organization-model/index.ts +1 -0
  32. package/src/organization-model/schema-refinements.ts +667 -0
  33. package/src/organization-model/schema.ts +8 -715
  34. package/src/reference/_generated/contracts.md +976 -1063
@@ -0,0 +1,167 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { DEFAULT_ORGANIZATION_MODEL } from '../defaults'
3
+ import { buildOmCrossRefIndex, knowledgeTargetExists } from '../cross-ref'
4
+ import { OrganizationModelSchema } from '../schema'
5
+ import type { OrganizationModel } from '../types'
6
+
7
+ // ---------------------------------------------------------------------------
8
+ // Test helpers
9
+ // ---------------------------------------------------------------------------
10
+
11
+ /**
12
+ * Build a minimal but schema-valid OrganizationModel that contains:
13
+ * - a top-level system with id "sales" (path "sales")
14
+ * - a nested subsystem with id "sales.lead-gen" (path "sales.lead-gen")
15
+ * - a stage-kind catalog with id "sales.lead-gen:catalog/company-stage"
16
+ * and a single entry "prospect"
17
+ * - a knowledge node whose link targets the "prospect" stage
18
+ */
19
+ function makeModelWithStage(): OrganizationModel {
20
+ return {
21
+ ...DEFAULT_ORGANIZATION_MODEL,
22
+ systems: {
23
+ sales: {
24
+ id: 'sales',
25
+ order: 10,
26
+ label: 'Sales',
27
+ enabled: true,
28
+ lifecycle: 'active' as const,
29
+ systems: {
30
+ 'lead-gen': {
31
+ id: 'sales.lead-gen',
32
+ order: 10,
33
+ label: 'Lead Gen',
34
+ enabled: true,
35
+ lifecycle: 'active' as const,
36
+ path: '/sales/lead-gen',
37
+ ontology: {
38
+ catalogTypes: {
39
+ 'sales.lead-gen:catalog/company-stage': {
40
+ id: 'sales.lead-gen:catalog/company-stage',
41
+ label: 'Company Stages',
42
+ ownerSystemId: 'sales.lead-gen',
43
+ kind: 'stage' as const,
44
+ entries: {
45
+ prospect: {
46
+ label: 'Prospect',
47
+ description: 'Company identified as a potential lead.',
48
+ order: 1
49
+ }
50
+ }
51
+ }
52
+ }
53
+ }
54
+ }
55
+ }
56
+ }
57
+ },
58
+ knowledge: {
59
+ 'knowledge.lead-gen-playbook': {
60
+ id: 'knowledge.lead-gen-playbook',
61
+ kind: 'playbook' as const,
62
+ title: 'Lead Gen Playbook',
63
+ summary: 'Governs the lead gen stage progression.',
64
+ body: '## Overview\n\nPlaybook content.',
65
+ links: [
66
+ {
67
+ target: { kind: 'stage' as const, id: 'prospect' },
68
+ nodeId: 'stage:prospect'
69
+ }
70
+ ],
71
+ ownerIds: [],
72
+ updatedAt: '2026-05-17'
73
+ }
74
+ }
75
+ }
76
+ }
77
+
78
+ // ---------------------------------------------------------------------------
79
+ // (a) stage-kind knowledge-link targets resolve via knowledgeTargetExists
80
+ // ---------------------------------------------------------------------------
81
+
82
+ describe('knowledgeTargetExists — stage kind', () => {
83
+ it('returns true for a stage id that exists in a stage-kind catalog', () => {
84
+ const model = makeModelWithStage()
85
+ const idx = buildOmCrossRefIndex(model)
86
+ expect(knowledgeTargetExists(idx, 'stage', 'prospect')).toBe(true)
87
+ })
88
+
89
+ it('returns false for a stage id that does not exist in any catalog', () => {
90
+ const model = makeModelWithStage()
91
+ const idx = buildOmCrossRefIndex(model)
92
+ expect(knowledgeTargetExists(idx, 'stage', 'nonexistent-stage')).toBe(false)
93
+ })
94
+ })
95
+
96
+ // ---------------------------------------------------------------------------
97
+ // (b) system targets resolve by dotted path AND by system.id (dual-keyed)
98
+ // ---------------------------------------------------------------------------
99
+
100
+ describe('knowledgeTargetExists — system kind dual-keyed lookup', () => {
101
+ it('resolves a system by its dotted path', () => {
102
+ const model = makeModelWithStage()
103
+ const idx = buildOmCrossRefIndex(model)
104
+ // "sales.lead-gen" is the dotted path in the systems tree
105
+ expect(knowledgeTargetExists(idx, 'system', 'sales.lead-gen')).toBe(true)
106
+ })
107
+
108
+ it('resolves a system by system.id when id differs from tree key', () => {
109
+ const model = makeModelWithStage()
110
+ const idx = buildOmCrossRefIndex(model)
111
+ // system.id === "sales.lead-gen" — same here, but the index is keyed by BOTH
112
+ // the path AND the id so this also exercises the id branch
113
+ expect(knowledgeTargetExists(idx, 'system', 'sales.lead-gen')).toBe(true)
114
+ })
115
+
116
+ it('returns false for an unknown system identifier', () => {
117
+ const model = makeModelWithStage()
118
+ const idx = buildOmCrossRefIndex(model)
119
+ expect(knowledgeTargetExists(idx, 'system', 'sales.crm')).toBe(false)
120
+ })
121
+ })
122
+
123
+ // ---------------------------------------------------------------------------
124
+ // (c) Schema path and verify path agree on stage-targeting knowledge node
125
+ // ---------------------------------------------------------------------------
126
+
127
+ describe('schema / verify path parity — stage target', () => {
128
+ it('OrganizationModelSchema accepts a knowledge node with a stage link', () => {
129
+ const model = makeModelWithStage()
130
+ const result = OrganizationModelSchema.safeParse(model)
131
+ const stageIssues = result.success
132
+ ? []
133
+ : result.error.issues.filter(
134
+ (issue) =>
135
+ issue.message.includes('stage') ||
136
+ (Array.isArray(issue.path) && issue.path.includes('knowledge'))
137
+ )
138
+ expect(stageIssues).toHaveLength(0)
139
+ })
140
+
141
+ it('knowledgeTargetExists returns true for the stage target (verify path would accept)', () => {
142
+ const model = makeModelWithStage()
143
+ const idx = buildOmCrossRefIndex(model)
144
+ const knowledgeNode = model.knowledge['knowledge.lead-gen-playbook']
145
+ expect(knowledgeNode).toBeDefined()
146
+ for (const link of knowledgeNode.links) {
147
+ expect(knowledgeTargetExists(idx, link.target.kind, link.target.id)).toBe(true)
148
+ }
149
+ })
150
+
151
+ it('schema and verify path agree: both accept the stage link without error', () => {
152
+ const model = makeModelWithStage()
153
+
154
+ // Schema path: parse must succeed (no issues about the stage link)
155
+ const parseResult = OrganizationModelSchema.safeParse(model)
156
+ const knowledgeIssues = parseResult.success
157
+ ? []
158
+ : parseResult.error.issues.filter((issue) => Array.isArray(issue.path) && issue.path[0] === 'knowledge')
159
+ expect(knowledgeIssues).toHaveLength(0)
160
+
161
+ // Verify path: knowledgeTargetExists must return true for every link
162
+ const idx = buildOmCrossRefIndex(model)
163
+ const node = model.knowledge['knowledge.lead-gen-playbook']
164
+ const missingTargets = node.links.filter((link) => !knowledgeTargetExists(idx, link.target.kind, link.target.id))
165
+ expect(missingTargets).toHaveLength(0)
166
+ })
167
+ })
@@ -1,10 +1,27 @@
1
1
  import { describe, expect, it } from 'vitest'
2
+ import * as publishedCore from '../../index'
2
3
  import * as publishedOrganizationModel from '../published'
3
4
 
4
5
  describe('published organization-model barrel zero-leak guard', () => {
5
6
  it('does not export Elevasis instance data through @repo/core/organization-model', () => {
6
7
  expect(Object.keys(publishedOrganizationModel)).not.toEqual(
7
- expect.arrayContaining(['LEAD_GEN_STAGE_CATALOG', 'CRM_ACTION_ENTRIES', 'LEAD_GEN_ACTION_ENTRIES'])
8
+ expect.arrayContaining([
9
+ 'LEAD_GEN_STAGE_CATALOG',
10
+ 'CRM_ACTION_ENTRIES',
11
+ 'LEAD_GEN_ACTION_ENTRIES',
12
+ 'CRM_PIPELINE_DEFINITION',
13
+ 'CRM_DISCOVERY_REPLIED_STATE',
14
+ 'CRM_DISCOVERY_LINK_SENT_STATE',
15
+ 'CRM_DISCOVERY_NUDGING_STATE',
16
+ 'CRM_DISCOVERY_BOOKING_CANCELLED_STATE',
17
+ 'CRM_REPLY_SENT_STATE',
18
+ 'CRM_FOLLOWUP_1_SENT_STATE',
19
+ 'CRM_FOLLOWUP_2_SENT_STATE',
20
+ 'CRM_FOLLOWUP_3_SENT_STATE',
21
+ 'CRM_PRIORITY_BUCKETS',
22
+ 'DEFAULT_CRM_PRIORITY_RULE_CONFIG',
23
+ 'DEFAULT_CRM_NEXT_ACTION_RULE_CONFIG'
24
+ ])
8
25
  )
9
26
 
10
27
  const serializedExports = JSON.stringify(publishedOrganizationModel)
@@ -13,5 +30,47 @@ describe('published organization-model barrel zero-leak guard', () => {
13
30
  expect(serializedExports).not.toContain('lgn-05-email-verification-workflow')
14
31
  expect(serializedExports).not.toContain('localServices')
15
32
  expect(serializedExports).not.toContain('dtcApolloClickup')
33
+ expect(serializedExports).not.toContain('Elevasis')
34
+ expect(serializedExports).not.toContain('elevasis.io')
35
+ expect(serializedExports).not.toContain('discovery_replied')
36
+ expect(serializedExports).not.toContain('discovery_link_sent')
37
+ expect(serializedExports).not.toContain('crm-send-booking-link-workflow')
38
+ })
39
+
40
+ it('does not expose Elevasis CRM stage data through the @repo/core root barrel', () => {
41
+ expect(Object.keys(publishedCore)).not.toEqual(
42
+ expect.arrayContaining([
43
+ 'CRM_PIPELINE_DEFINITION',
44
+ 'CRM_DISCOVERY_REPLIED_STATE',
45
+ 'CRM_DISCOVERY_LINK_SENT_STATE',
46
+ 'CRM_DISCOVERY_NUDGING_STATE',
47
+ 'CRM_DISCOVERY_BOOKING_CANCELLED_STATE',
48
+ 'CRM_REPLY_SENT_STATE',
49
+ 'CRM_FOLLOWUP_1_SENT_STATE',
50
+ 'CRM_FOLLOWUP_2_SENT_STATE',
51
+ 'CRM_FOLLOWUP_3_SENT_STATE',
52
+ 'CRM_PRIORITY_BUCKETS',
53
+ 'DEFAULT_CRM_PRIORITY_RULE_CONFIG',
54
+ 'DEFAULT_CRM_NEXT_ACTION_RULE_CONFIG',
55
+ 'DEFAULT_CRM_ACTIONS'
56
+ ])
57
+ )
58
+
59
+ let legacyCrmStatesResult: unknown
60
+ try {
61
+ legacyCrmStatesResult = (
62
+ publishedCore as typeof publishedCore & {
63
+ getCrmStatesForStage?: (stageKey: string) => unknown
64
+ }
65
+ ).getCrmStatesForStage?.('interested')
66
+ } catch {
67
+ legacyCrmStatesResult = undefined
68
+ }
69
+
70
+ expect(JSON.stringify(legacyCrmStatesResult ?? null)).not.toContain('discovery_replied')
71
+ const serializedRootExports = JSON.stringify(publishedCore)
72
+ expect(serializedRootExports).not.toContain('discovery_replied')
73
+ expect(serializedRootExports).not.toContain('discovery_link_sent')
74
+ expect(serializedRootExports).not.toContain('crm-send-booking-link-workflow')
16
75
  })
17
76
  })
@@ -169,7 +169,7 @@ describe('organization-model resolve', () => {
169
169
  })
170
170
 
171
171
  expect(model.branding.organizationName).toBe('OverriddenOrg')
172
- expect(model.branding.productName).toBe('Elevasis')
172
+ expect(model.branding.productName).toBe('Organization OS')
173
173
  expect(model.systems).toEqual({})
174
174
  })
175
175
 
@@ -0,0 +1,72 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { z } from 'zod'
3
+ import { DEFAULT_ORGANIZATION_MODEL } from '../defaults'
4
+ import { refineOrganizationModel } from '../schema-refinements'
5
+ import type { OrganizationModel } from '../types'
6
+
7
+ function collectRefinementIssues(model: OrganizationModel): z.ZodIssue[] {
8
+ const issues: z.ZodIssue[] = []
9
+ const ctx = {
10
+ addIssue(issue: z.ZodIssue): void {
11
+ issues.push(issue)
12
+ }
13
+ } as z.RefinementCtx
14
+
15
+ refineOrganizationModel(model, ctx)
16
+ return issues
17
+ }
18
+
19
+ describe('refineOrganizationModel', () => {
20
+ it('emits resource systemPath issues through the extracted refinement boundary', () => {
21
+ const model: OrganizationModel = {
22
+ ...DEFAULT_ORGANIZATION_MODEL,
23
+ resources: {
24
+ ...DEFAULT_ORGANIZATION_MODEL.resources,
25
+ 'missing-system-workflow': {
26
+ id: 'missing-system-workflow',
27
+ order: 10,
28
+ kind: 'workflow',
29
+ systemPath: 'missing.system',
30
+ status: 'active'
31
+ }
32
+ }
33
+ }
34
+
35
+ const issues = collectRefinementIssues(model)
36
+
37
+ expect(issues).toEqual(
38
+ expect.arrayContaining([
39
+ expect.objectContaining({
40
+ code: z.ZodIssueCode.custom,
41
+ path: ['resources', 'missing-system-workflow', 'systemPath'],
42
+ message: 'Resource "missing-system-workflow" references unknown system path "missing.system"'
43
+ })
44
+ ])
45
+ )
46
+ })
47
+
48
+ it('uses the shared ontology reference key map for loose ontology payload references', () => {
49
+ const model: OrganizationModel = {
50
+ ...DEFAULT_ORGANIZATION_MODEL,
51
+ ontology: {
52
+ ...DEFAULT_ORGANIZATION_MODEL.ontology,
53
+ objectTypes: {
54
+ ...DEFAULT_ORGANIZATION_MODEL.ontology.objectTypes,
55
+ 'global:object/test-object': {
56
+ id: 'global:object/test-object',
57
+ label: 'Test Object',
58
+ properties: {
59
+ badValueRef: { valueType: 'global:value-type/missing' }
60
+ }
61
+ }
62
+ }
63
+ }
64
+ }
65
+
66
+ const issues = collectRefinementIssues(model)
67
+
68
+ expect(issues.some((issue) => issue.message.includes('valueType references unknown value-type ontology ID'))).toBe(
69
+ true
70
+ )
71
+ })
72
+ })
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Browser-safe shared cross-reference index for the Organization Model.
3
+ *
4
+ * This module is the single source of truth for OM cross-reference resolution.
5
+ * It is consumed by:
6
+ * - `OrganizationModelSchema.superRefine` (Zod validation, browser-safe)
7
+ * - `packages/cli/src/knowledge/verify.ts` (CLI gate, Node-only)
8
+ *
9
+ * INVARIANT: No Node.js builtins, no `@repo/elevasis-core` import, no dynamic import().
10
+ */
11
+
12
+ import { compileOrganizationOntology } from './ontology'
13
+ import { listAllSystems } from './helpers'
14
+ import type { OntologyKind } from './ontology'
15
+ import type { OrganizationModel } from './types'
16
+
17
+ // ---------------------------------------------------------------------------
18
+ // Shared key-to-kind map
19
+ // ---------------------------------------------------------------------------
20
+
21
+ /**
22
+ * Maps ontology reference field keys (as they appear inside ontology records
23
+ * and resource ontology bindings) to their expected OntologyKind.
24
+ *
25
+ * Single source of truth — replaces both the byte-identical
26
+ * `ontologyReferenceKeyKinds` in `schema.ts` and `genericReferenceKeyKinds`
27
+ * in `verify.ts`.
28
+ */
29
+ export const ONTOLOGY_REFERENCE_KEY_KINDS: Record<string, OntologyKind> = {
30
+ valueType: 'value-type',
31
+ catalogType: 'catalog',
32
+ objectType: 'object',
33
+ eventType: 'event',
34
+ actionType: 'action',
35
+ linkType: 'link',
36
+ interfaceType: 'interface',
37
+ propertyType: 'property',
38
+ groupType: 'group',
39
+ surfaceType: 'surface',
40
+ stepCatalog: 'catalog'
41
+ } satisfies Record<string, OntologyKind>
42
+
43
+ // ---------------------------------------------------------------------------
44
+ // Cross-reference index
45
+ // ---------------------------------------------------------------------------
46
+
47
+ /**
48
+ * Pre-built look-up sets derived from a resolved OrganizationModel.
49
+ * Built once, then consumed by both validation paths (superRefine + verify.ts).
50
+ */
51
+ export interface OmCrossRefIndex {
52
+ /**
53
+ * Systems keyed by BOTH dotted path (e.g. "sales.lead-gen") AND system.id.
54
+ * Value is opaque (`unknown`) — consumers only call `.has()`.
55
+ */
56
+ systemsById: Map<string, unknown>
57
+ resourceIds: Set<string>
58
+ knowledgeIds: Set<string>
59
+ roleIds: Set<string>
60
+ goalIds: Set<string>
61
+ actionIds: Set<string>
62
+ customerSegmentIds: Set<string>
63
+ offeringIds: Set<string>
64
+ ontologyIds: Set<string>
65
+ /** Ontology records indexed by kind (value is a plain id→record map). */
66
+ ontologyIndexByKind: Record<OntologyKind, Record<string, unknown>>
67
+ /** IDs of individual stage entries from all catalogs with `kind === 'stage'`. */
68
+ stageIds: Set<string>
69
+ }
70
+
71
+ /**
72
+ * Build the OmCrossRefIndex from a resolved OrganizationModel.
73
+ *
74
+ * Call once per validation pass and share the result across all checks.
75
+ */
76
+ export function buildOmCrossRefIndex(model: OrganizationModel): OmCrossRefIndex {
77
+ // Systems: keyed by path AND by system.id (path-OR-id resolution)
78
+ const systemsById = new Map<string, unknown>()
79
+ for (const { path, system } of listAllSystems(model)) {
80
+ systemsById.set(path, system)
81
+ systemsById.set(system.id, system)
82
+ }
83
+
84
+ const resourceIds = new Set(Object.keys(model.resources ?? {}))
85
+ const knowledgeIds = new Set(Object.keys(model.knowledge ?? {}))
86
+ const roleIds = new Set(Object.keys(model.roles ?? {}))
87
+ const goalIds = new Set(Object.keys(model.goals ?? {}))
88
+ const actionIds = new Set(Object.keys(model.actions ?? {}))
89
+ const customerSegmentIds = new Set(Object.keys(model.customers ?? {}))
90
+ const offeringIds = new Set(Object.keys(model.offerings ?? {}))
91
+
92
+ const ontologyCompilation = compileOrganizationOntology(model)
93
+
94
+ const ontologyIndexByKind: Record<OntologyKind, Record<string, unknown>> = {
95
+ object: ontologyCompilation.ontology.objectTypes,
96
+ link: ontologyCompilation.ontology.linkTypes,
97
+ action: ontologyCompilation.ontology.actionTypes,
98
+ catalog: ontologyCompilation.ontology.catalogTypes,
99
+ event: ontologyCompilation.ontology.eventTypes,
100
+ interface: ontologyCompilation.ontology.interfaceTypes,
101
+ 'value-type': ontologyCompilation.ontology.valueTypes,
102
+ property: ontologyCompilation.ontology.sharedProperties,
103
+ group: ontologyCompilation.ontology.groups,
104
+ surface: ontologyCompilation.ontology.surfaces
105
+ }
106
+
107
+ const ontologyIds = new Set(Object.values(ontologyIndexByKind).flatMap((index) => Object.keys(index)))
108
+
109
+ // Stage IDs: entry keys from all catalogs whose kind === 'stage'
110
+ const stageIds = new Set<string>()
111
+ for (const catalog of Object.values(ontologyCompilation.ontology.catalogTypes)) {
112
+ if ((catalog as { kind?: string }).kind !== 'stage') continue
113
+ const entries = (catalog as { entries?: Record<string, unknown> }).entries
114
+ if (entries !== undefined) {
115
+ for (const stageId of Object.keys(entries)) {
116
+ stageIds.add(stageId)
117
+ }
118
+ }
119
+ }
120
+
121
+ return {
122
+ systemsById,
123
+ resourceIds,
124
+ knowledgeIds,
125
+ roleIds,
126
+ goalIds,
127
+ actionIds,
128
+ customerSegmentIds,
129
+ offeringIds,
130
+ ontologyIds,
131
+ ontologyIndexByKind,
132
+ stageIds
133
+ }
134
+ }
135
+
136
+ // ---------------------------------------------------------------------------
137
+ // Canonical resolution functions
138
+ // ---------------------------------------------------------------------------
139
+
140
+ /**
141
+ * The ONLY definition of which (kind, id) knowledge-link targets resolve.
142
+ *
143
+ * Fixes two confirmed divergences vs. the old inline `exists()` in verify.ts:
144
+ * 1. `kind === 'stage'` — previously missing in verify.ts, causing a false-positive error.
145
+ * 2. `kind === 'system'` — resolves via `systemsById` which is keyed by BOTH path AND
146
+ * `system.id`, so a system referenced by its id (not its dotted path) is also found.
147
+ */
148
+ export function knowledgeTargetExists(index: OmCrossRefIndex, kind: string, id: string): boolean {
149
+ if (kind === 'system') return index.systemsById.has(id)
150
+ if (kind === 'resource') return index.resourceIds.has(id)
151
+ if (kind === 'knowledge') return index.knowledgeIds.has(id)
152
+ if (kind === 'stage') return index.stageIds.has(id)
153
+ if (kind === 'action') return index.actionIds.has(id)
154
+ if (kind === 'role') return index.roleIds.has(id)
155
+ if (kind === 'goal') return index.goalIds.has(id)
156
+ if (kind === 'customer-segment') return index.customerSegmentIds.has(id)
157
+ if (kind === 'offering') return index.offeringIds.has(id)
158
+ if (kind === 'ontology') return index.ontologyIds.has(id)
159
+ return false
160
+ }
161
+
162
+ /**
163
+ * Returns `true` when a resource ontology binding references an ontology ID
164
+ * that does not exist in the compiled index for the expected kind.
165
+ *
166
+ * Shared between `schema.ts` resource-ontology binding validation and
167
+ * `verify.ts` resource ontology reference checks.
168
+ */
169
+ export function resourceOntologyBindingMissing(
170
+ index: OmCrossRefIndex,
171
+ expectedKind: OntologyKind,
172
+ ontologyId: string
173
+ ): boolean {
174
+ return index.ontologyIndexByKind[expectedKind][ontologyId] === undefined
175
+ }
@@ -14,9 +14,9 @@ export const OrganizationModelBrandingSchema = z.object({
14
14
  .default({})
15
15
  })
16
16
 
17
- export const DEFAULT_ORGANIZATION_MODEL_BRANDING: z.infer<typeof OrganizationModelBrandingSchema> = {
18
- organizationName: 'Default Organization',
19
- productName: 'Elevasis',
20
- shortName: 'Elevasis',
21
- logos: {}
22
- }
17
+ export const DEFAULT_ORGANIZATION_MODEL_BRANDING: z.infer<typeof OrganizationModelBrandingSchema> = {
18
+ organizationName: 'Default Organization',
19
+ productName: 'Organization OS',
20
+ shortName: 'Org OS',
21
+ logos: {}
22
+ }