@elevasis/sdk 1.17.0 → 1.19.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.
@@ -198,6 +198,18 @@ export type OrgKnowledgeNode = z.infer<typeof OrgKnowledgeNodeSchema>
198
198
  export type OrgKnowledgeKind = z.infer<typeof OrgKnowledgeKindSchema>
199
199
  ```
200
200
 
201
+ ### `KnowledgeSkillBinding`
202
+
203
+ ```typescript
204
+ export type KnowledgeSkillBinding = z.infer<typeof KnowledgeSkillBindingSchema>
205
+ ```
206
+
207
+ ### `KnowledgeDomainBinding`
208
+
209
+ ```typescript
210
+ export type KnowledgeDomainBinding = z.infer<typeof KnowledgeDomainBindingSchema>
211
+ ```
212
+
201
213
  ### `OrganizationModelIconToken`
202
214
 
203
215
  ```typescript
@@ -869,7 +881,9 @@ export interface AcqCompany {
869
881
  category: string | null
870
882
  categoryPain: string | null
871
883
  segment: string | null
872
- pipelineStatus: CompanyPipelineStatus | null
884
+ processingState: CompanyProcessingState | null
885
+ /** @deprecated Use `processingState`. This legacy DB column has been removed; responses return null. */
886
+ pipelineStatus?: LegacyPipelineStatus | null
873
887
  enrichmentData: CompanyEnrichmentData | null
874
888
  source: string | null
875
889
  batchId: string | null
@@ -909,7 +923,9 @@ export interface AcqContact {
909
923
  openingLine: string | null
910
924
  source: string | null
911
925
  sourceId: string | null
912
- pipelineStatus: ContactPipelineStatus | null
926
+ processingState: ContactProcessingState | null
927
+ /** @deprecated Use `processingState`. This legacy DB column has been removed; responses return null. */
928
+ pipelineStatus?: LegacyPipelineStatus | null
913
929
  enrichmentData: ContactEnrichmentData | null
914
930
  /** Attio Person record ID - set when contact responds and is added to CRM */
915
931
  attioPersonId: string | null
@@ -972,7 +988,7 @@ export interface DealContact {
972
988
  title: string | null
973
989
  headline: string | null
974
990
  linkedin_url: string | null
975
- pipeline_status: Record<string, unknown> | null
991
+ processing_state: Record<string, unknown> | null
976
992
  enrichment_data: Record<string, unknown> | null
977
993
  company: {
978
994
  id: string
@@ -1110,7 +1126,7 @@ export const DEFAULT_CRM_PRIORITY_RULE_CONFIG: CrmPriorityRuleConfig = {
1110
1126
  ### `DealStageSchema`
1111
1127
 
1112
1128
  ```typescript
1113
- export const DealStageSchema = z.enum(['interested', 'proposal', 'closing', 'closed_won', 'closed_lost', 'nurturing'])
1129
+ export const DealStageSchema = CrmStageKeySchema
1114
1130
  ```
1115
1131
 
1116
1132
  ### `AcqDealTaskKindSchema`
@@ -1202,7 +1218,7 @@ export const TransitionItemRequestSchema = z
1202
1218
  .object({
1203
1219
  pipelineKey: z.string().min(1),
1204
1220
  stageKey: z.string().min(1),
1205
- stateKey: z.string().nullable().optional(),
1221
+ stateKey: z.string().min(1).nullable().optional(),
1206
1222
  reason: z.string().optional(),
1207
1223
  expectedUpdatedAt: z.string().datetime().optional()
1208
1224
  })
@@ -1245,7 +1261,7 @@ export const DealContactSummarySchema = z.object({
1245
1261
  title: z.string().nullable(),
1246
1262
  headline: z.string().nullable(),
1247
1263
  linkedin_url: z.string().nullable(),
1248
- pipeline_status: z.record(z.string(), z.unknown()).nullable(),
1264
+ processing_state: ProcessingStateSchema.nullable(),
1249
1265
  enrichment_data: z.record(z.string(), z.unknown()).nullable(),
1250
1266
  company: z
1251
1267
  .object({
@@ -1396,6 +1412,11 @@ export const DealTaskListResponseSchema = z.array(DealTaskResponseSchema)
1396
1412
 
1397
1413
  ```typescript
1398
1414
  export const DealSchemas = {
1415
+ // Primitives
1416
+ CrmStageKey: CrmStageKeySchema,
1417
+ CrmStateKey: CrmStateKeySchema,
1418
+ DealStage: DealStageSchema,
1419
+
1399
1420
  // Params
1400
1421
  DealIdParams: DealIdParamsSchema,
1401
1422
  DealTaskIdParams: DealTaskIdParamsSchema,
@@ -1408,7 +1429,7 @@ export const DealSchemas = {
1408
1429
  // Request bodies
1409
1430
  CreateDealNoteRequest: CreateDealNoteRequestSchema,
1410
1431
  CreateDealTaskRequest: CreateDealTaskRequestSchema,
1411
- TransitionItemRequest: TransitionItemRequestSchema,
1432
+ TransitionItemRequest: CrmTransitionItemRequestSchema,
1412
1433
  TransitionDealStateRequest: TransitionDealStateRequestSchema,
1413
1434
  ExecuteActionParams: ExecuteActionParamsSchema,
1414
1435
  ExecuteActionRequest: ExecuteActionRequestSchema,
@@ -1573,51 +1594,6 @@ export interface WebPost {
1573
1594
  }
1574
1595
  ```
1575
1596
 
1576
- ### `CompanyPipelineStatus`
1577
-
1578
- ```typescript
1579
- /**
1580
- * Tracks pipeline status for a company across all processing stages.
1581
- */
1582
- export interface CompanyPipelineStatus {
1583
- acquired: boolean
1584
- enrichment: {
1585
- [source: string]: {
1586
- status: 'pending' | 'complete' | 'failed' | 'skipped'
1587
- completedAt?: string
1588
- error?: string
1589
- }
1590
- }
1591
- }
1592
- ```
1593
-
1594
- ### `ContactPipelineStatus`
1595
-
1596
- ```typescript
1597
- /**
1598
- * Tracks pipeline status for a contact across all processing stages.
1599
- */
1600
- export interface ContactPipelineStatus {
1601
- enrichment: {
1602
- [source: string]: {
1603
- status: 'pending' | 'complete' | 'failed' | 'skipped'
1604
- completedAt?: string
1605
- error?: string
1606
- }
1607
- }
1608
- personalization: {
1609
- status: 'pending' | 'complete' | 'failed' | 'skipped'
1610
- completedAt?: string
1611
- }
1612
- outreach: {
1613
- status: 'pending' | 'sent' | 'replied' | 'bounced' | 'opted-out'
1614
- sentAt?: string
1615
- channel?: string
1616
- campaignId?: string
1617
- }
1618
- }
1619
- ```
1620
-
1621
1597
  ### `CompanyEnrichmentData`
1622
1598
 
1623
1599
  ```typescript
@@ -1733,7 +1709,9 @@ export interface AcqCompany {
1733
1709
  category: string | null
1734
1710
  categoryPain: string | null
1735
1711
  segment: string | null
1736
- pipelineStatus: CompanyPipelineStatus | null
1712
+ processingState: CompanyProcessingState | null
1713
+ /** @deprecated Use `processingState`. This legacy DB column has been removed; responses return null. */
1714
+ pipelineStatus?: LegacyPipelineStatus | null
1737
1715
  enrichmentData: CompanyEnrichmentData | null
1738
1716
  source: string | null
1739
1717
  batchId: string | null
@@ -1773,7 +1751,9 @@ export interface AcqContact {
1773
1751
  openingLine: string | null
1774
1752
  source: string | null
1775
1753
  sourceId: string | null
1776
- pipelineStatus: ContactPipelineStatus | null
1754
+ processingState: ContactProcessingState | null
1755
+ /** @deprecated Use `processingState`. This legacy DB column has been removed; responses return null. */
1756
+ pipelineStatus?: LegacyPipelineStatus | null
1777
1757
  enrichmentData: ContactEnrichmentData | null
1778
1758
  /** Attio Person record ID - set when contact responds and is added to CRM */
1779
1759
  attioPersonId: string | null
@@ -2084,6 +2064,7 @@ export const ListCompaniesQuerySchema = z
2084
2064
  website: z.string().trim().min(1).max(2048).optional(),
2085
2065
  segment: z.string().trim().min(1).max(255).optional(),
2086
2066
  category: z.string().trim().min(1).max(255).optional(),
2067
+ pipelineStatus: z.unknown().optional(),
2087
2068
  batchId: z.string().trim().min(1).max(255).optional(),
2088
2069
  status: AcqCompanyStatusSchema.optional(),
2089
2070
  includeAll: QueryBooleanSchema.optional(),
@@ -2125,6 +2106,7 @@ export const CreateCompanyRequestSchema = z
2125
2106
  category: z.string().trim().min(1).max(255).optional(),
2126
2107
  source: z.string().trim().min(1).max(255).optional(),
2127
2108
  batchId: z.string().trim().min(1).max(255).optional(),
2109
+ pipelineStatus: z.unknown().optional(),
2128
2110
  verticalResearch: z.string().trim().min(1).max(5000).optional()
2129
2111
  })
2130
2112
  .strict()
@@ -2145,7 +2127,8 @@ export const UpdateCompanyRequestSchema = z
2145
2127
  locationState: z.string().trim().min(1).max(255).optional(),
2146
2128
  category: z.string().trim().min(1).max(255).optional(),
2147
2129
  segment: z.string().trim().min(1).max(255).optional(),
2148
- pipelineStatus: z.record(z.string(), z.unknown()).optional(),
2130
+ processingState: CompanyProcessingStateSchema.optional(),
2131
+ pipelineStatus: z.unknown().optional(),
2149
2132
  enrichmentData: z.record(z.string(), z.unknown()).optional(),
2150
2133
  source: z.string().trim().min(1).max(255).optional(),
2151
2134
  batchId: z.string().trim().min(1).max(255).optional(),
@@ -2165,6 +2148,7 @@ export const UpdateCompanyRequestSchema = z
2165
2148
  data.locationState !== undefined ||
2166
2149
  data.category !== undefined ||
2167
2150
  data.segment !== undefined ||
2151
+ data.processingState !== undefined ||
2168
2152
  data.pipelineStatus !== undefined ||
2169
2153
  data.enrichmentData !== undefined ||
2170
2154
  data.source !== undefined ||
@@ -2190,7 +2174,8 @@ export const CreateContactRequestSchema = z
2190
2174
  title: z.string().trim().min(1).max(255).optional(),
2191
2175
  source: z.string().trim().min(1).max(255).optional(),
2192
2176
  sourceId: z.string().trim().min(1).max(255).optional(),
2193
- batchId: z.string().trim().min(1).max(255).optional()
2177
+ batchId: z.string().trim().min(1).max(255).optional(),
2178
+ pipelineStatus: z.unknown().optional()
2194
2179
  })
2195
2180
  .strict()
2196
2181
  ```
@@ -2209,7 +2194,8 @@ export const UpdateContactRequestSchema = z
2209
2194
  headline: z.string().trim().min(1).max(5000).optional(),
2210
2195
  filterReason: z.string().trim().min(1).max(5000).optional(),
2211
2196
  openingLine: z.string().trim().min(1).max(5000).optional(),
2212
- pipelineStatus: z.record(z.string(), z.unknown()).optional(),
2197
+ processingState: ContactProcessingStateSchema.optional(),
2198
+ pipelineStatus: z.unknown().optional(),
2213
2199
  enrichmentData: z.record(z.string(), z.unknown()).optional(),
2214
2200
  status: AcqContactStatusSchema.optional()
2215
2201
  })
@@ -2225,6 +2211,7 @@ export const UpdateContactRequestSchema = z
2225
2211
  data.headline !== undefined ||
2226
2212
  data.filterReason !== undefined ||
2227
2213
  data.openingLine !== undefined ||
2214
+ data.processingState !== undefined ||
2228
2215
  data.pipelineStatus !== undefined ||
2229
2216
  data.enrichmentData !== undefined ||
2230
2217
  data.status !== undefined,
@@ -2251,7 +2238,8 @@ export const AcqCompanyResponseSchema = z.object({
2251
2238
  category: z.string().nullable(),
2252
2239
  categoryPain: z.string().nullable(),
2253
2240
  segment: z.string().nullable(),
2254
- pipelineStatus: z.record(z.string(), z.unknown()).nullable(),
2241
+ processingState: CompanyProcessingStateSchema.nullable(),
2242
+ pipelineStatus: z.unknown().nullable().optional(),
2255
2243
  enrichmentData: z.record(z.string(), z.unknown()).nullable(),
2256
2244
  source: z.string().nullable(),
2257
2245
  batchId: z.string().nullable(),
@@ -2317,7 +2305,8 @@ export const AcqContactResponseSchema = z.object({
2317
2305
  openingLine: z.string().nullable(),
2318
2306
  source: z.string().nullable(),
2319
2307
  sourceId: z.string().nullable(),
2320
- pipelineStatus: z.record(z.string(), z.unknown()).nullable(),
2308
+ processingState: ContactProcessingStateSchema.nullable(),
2309
+ pipelineStatus: z.unknown().nullable().optional(),
2321
2310
  enrichmentData: z.record(z.string(), z.unknown()).nullable(),
2322
2311
  attioPersonId: z.string().nullable(),
2323
2312
  batchId: z.string().nullable(),
@@ -2483,6 +2472,7 @@ export const AcqListCompanyResponseSchema = z.object({
2483
2472
 
2484
2473
  ```typescript
2485
2474
  export const AcqCompanySchemas = {
2475
+ CompanyProcessingState: CompanyProcessingStateSchema,
2486
2476
  CompanyIdParams: CompanyIdParamsSchema,
2487
2477
  ListCompaniesQuery: ListCompaniesQuerySchema,
2488
2478
  CreateCompanyRequest: CreateCompanyRequestSchema,
@@ -2497,6 +2487,7 @@ export const AcqCompanySchemas = {
2497
2487
 
2498
2488
  ```typescript
2499
2489
  export const AcqContactSchemas = {
2490
+ ContactProcessingState: ContactProcessingStateSchema,
2500
2491
  ContactIdParams: ContactIdParamsSchema,
2501
2492
  ListContactsQuery: ListContactsQuerySchema,
2502
2493
  CreateContactRequest: CreateContactRequestSchema,
@@ -2522,7 +2513,10 @@ export const AcqListSchemas = {
2522
2513
  BuildPlanSnapshot: BuildPlanSnapshotSchema,
2523
2514
  BuildPlanSnapshotStep: BuildPlanSnapshotStepSchema,
2524
2515
  AcqListMetadata: AcqListMetadataSchema,
2516
+ LeadGenStageKey: LeadGenStageKeySchema,
2517
+ LeadGenCapabilityKey: LeadGenCapabilityKeySchema,
2525
2518
  ProcessingStageStatus: ProcessingStageStatusSchema,
2519
+ ProcessingState: ProcessingStateSchema,
2526
2520
  ListStageCounts: ListStageCountsSchema,
2527
2521
  ListTelemetry: ListTelemetrySchema,
2528
2522
 
@@ -2566,7 +2560,7 @@ export const AcqSubstrateSchemas = {
2566
2560
  ListCompanyIdParams: ListCompanyIdParamsSchema,
2567
2561
  AcqListCompanyResponse: AcqListCompanyResponseSchema,
2568
2562
 
2569
- // Transition (shared with deals — TransitionItemRequestSchema)
2563
+ // Transition (generic stateful substrate)
2570
2564
  TransitionItemRequest: TransitionItemRequestSchema
2571
2565
  }
2572
2566
  ```
@@ -2634,6 +2628,8 @@ export interface StatefulStageDefinition {
2634
2628
  /** Matches stage_key values written by workflow steps. */
2635
2629
  stageKey: string
2636
2630
  label: string
2631
+ /** UI color token. Consumers may map this to their design system. */
2632
+ color?: string
2637
2633
  states: StatefulStateDefinition[]
2638
2634
  }
2639
2635
  ```
@@ -2815,6 +2811,8 @@ export interface CreateCompanyParams {
2815
2811
  source?: string
2816
2812
  batchId?: string
2817
2813
  verticalResearch?: string
2814
+ /** @deprecated Use processingState. Accepted as a no-op compatibility bridge for external tenants. */
2815
+ pipelineStatus?: unknown
2818
2816
  }
2819
2817
  ```
2820
2818
 
@@ -2832,7 +2830,9 @@ export interface UpdateCompanyParams {
2832
2830
  locationState?: string
2833
2831
  category?: string
2834
2832
  segment?: string
2835
- pipelineStatus?: Record<string, unknown>
2833
+ processingState?: ProcessingState
2834
+ /** @deprecated Use processingState. Accepted as a no-op compatibility bridge for external tenants. */
2835
+ pipelineStatus?: unknown
2836
2836
  enrichmentData?: Record<string, unknown>
2837
2837
  source?: string
2838
2838
  batchId?: string
@@ -2840,7 +2840,7 @@ export interface UpdateCompanyParams {
2840
2840
  verticalResearch?: string | null
2841
2841
  /** Track A: flat qualification score column (null until a scoring rubric is defined) */
2842
2842
  qualificationScore?: number | null
2843
- /** Track A: flat qualification signals jsonb — mirrors the former pipeline_status.qualification shape */
2843
+ /** Track A: flat qualification signals jsonb */
2844
2844
  qualificationSignals?: Record<string, unknown> | null
2845
2845
  /** Track A: key identifying the rubric used for qualification */
2846
2846
  qualificationRubricKey?: string | null
@@ -2863,13 +2863,15 @@ export interface CompanyFilters {
2863
2863
  website?: string
2864
2864
  segment?: string
2865
2865
  category?: string
2866
- pipelineStatus?: Record<string, unknown>
2867
- /** Exclude companies whose pipeline_status contains this value (PostgREST NOT contains) */
2868
- pipelineStatusNot?: Record<string, unknown>
2866
+ processingState?: ProcessingState
2867
+ /** @deprecated Use processingState. Accepted as a no-op compatibility bridge for external tenants. */
2868
+ pipelineStatus?: unknown
2869
+ /** Exclude companies whose processing state contains this value (PostgREST NOT contains) */
2870
+ processingStateNot?: ProcessingState
2869
2871
  batchId?: string
2870
2872
  status?: 'active' | 'invalid'
2871
2873
  includeAll?: boolean
2872
- excludeColumns?: Array<'enrichmentData' | 'pipelineStatus'>
2874
+ excludeColumns?: Array<'enrichmentData' | 'processingState'>
2873
2875
  limit?: number
2874
2876
  }
2875
2877
  ```
@@ -2888,6 +2890,8 @@ export interface CreateContactParams {
2888
2890
  source?: string
2889
2891
  sourceId?: string
2890
2892
  batchId?: string
2893
+ /** @deprecated Use processingState. Accepted as a no-op compatibility bridge for external tenants. */
2894
+ pipelineStatus?: unknown
2891
2895
  }
2892
2896
  ```
2893
2897
 
@@ -2904,7 +2908,9 @@ export interface UpdateContactParams {
2904
2908
  headline?: string
2905
2909
  filterReason?: string
2906
2910
  openingLine?: string
2907
- pipelineStatus?: Record<string, unknown>
2911
+ processingState?: ProcessingState
2912
+ /** @deprecated Use processingState. Accepted as a no-op compatibility bridge for external tenants. */
2913
+ pipelineStatus?: unknown
2908
2914
  enrichmentData?: Record<string, unknown>
2909
2915
  status?: 'active' | 'invalid'
2910
2916
  }
@@ -2923,7 +2929,9 @@ export interface ContactFilters {
2923
2929
  listId?: string // Filter to contacts in a specific list (via acq_list_members)
2924
2930
  search?: string
2925
2931
  openingLineIsNull?: boolean // Filter to contacts without personalization
2926
- pipelineStatus?: Record<string, unknown>
2932
+ processingState?: ProcessingState
2933
+ /** @deprecated Use processingState. Accepted as a no-op compatibility bridge for external tenants. */
2934
+ pipelineStatus?: unknown
2927
2935
  batchId?: string
2928
2936
  contactStatus?: 'active' | 'invalid' // Filter by contact status (soft-delete flag)
2929
2937
  }
@@ -3122,7 +3130,7 @@ export interface BulkImportCompanyEntry {
3122
3130
  category?: string
3123
3131
  source?: string
3124
3132
  enrichmentData?: Record<string, unknown>
3125
- pipelineStatus?: Record<string, unknown>
3133
+ processingState?: ProcessingState
3126
3134
  }
3127
3135
  ```
3128
3136
 
@@ -3303,6 +3311,14 @@ export type ListToolMap = {
3303
3311
  params: Omit<UpdateContactStageParams, 'organizationId'>
3304
3312
  result: void
3305
3313
  }
3314
+ listPendingCompanyIds: {
3315
+ params: Omit<ListPendingCompanyIdsParams, 'organizationId'>
3316
+ result: string[]
3317
+ }
3318
+ listPendingContactIds: {
3319
+ params: Omit<ListPendingContactIdsParams, 'organizationId'>
3320
+ result: string[]
3321
+ }
3306
3322
  }
3307
3323
  ```
3308
3324
 
@@ -3338,6 +3354,10 @@ export const OrgKnowledgeNodeSchema = z.object({
3338
3354
  * Each link emits a `governs` edge: knowledge-node -> target node.
3339
3355
  */
3340
3356
  links: z.array(KnowledgeLinkSchema).default([]),
3357
+ /** Operator skill or command bindings relevant to this node. */
3358
+ skills: z.array(KnowledgeSkillBindingSchema).optional(),
3359
+ /** Domain key used to derive fast graph->skill registries. */
3360
+ domain: KnowledgeDomainBindingSchema.optional(),
3341
3361
  /** Identifiers of the roles or members who own this knowledge node. */
3342
3362
  ownerIds: z.array(ModelIdSchema).default([]),
3343
3363
  /** ISO date string (YYYY-MM-DD or full ISO 8601) of last meaningful update. */
@@ -31,7 +31,7 @@ Feature IDs defined in `DEFAULT_ORGANIZATION_MODEL.features` (`packages/core/src
31
31
 
32
32
  ```typescript
33
33
  // FeatureSchema: { id, label, enabled, color?, icon?, entityIds, surfaceIds, resourceIds, capabilityIds }
34
- type DefaultFeatureId = 'dashboard' | 'identity' | 'platform' | 'finance' | 'sales' | 'sales.crm' | 'sales.lead-gen' | 'projects' | 'operations' | 'knowledge.command-view' | 'operations.overview' | 'operations.resources' | 'operations.command-queue' | 'operations.sessions' | 'operations.task-scheduler' | 'monitoring' | 'monitoring.activity-log' | 'monitoring.execution-logs' | 'monitoring.execution-health' | 'monitoring.cost-analytics' | 'monitoring.notifications' | 'monitoring.submitted-requests' | 'settings' | 'settings.account' | 'settings.appearance' | 'settings.roles' | 'settings.organization' | 'settings.credentials' | 'settings.api-keys' | 'settings.webhooks' | 'settings.deployments' | 'admin' | 'admin.system-health' | 'admin.organizations' | 'admin.users' | 'admin.design-showcase' | 'admin.debug' | 'archive' | 'archive.agent-chat' | 'archive.execution-runner' | 'seo' | 'knowledge' | 'knowledge.base'
34
+ type DefaultFeatureId = 'dashboard' | 'identity' | 'platform' | 'finance' | 'sales' | 'sales.crm' | 'sales.lead-gen' | 'projects' | 'operations' | 'knowledge.command-view' | 'operations.overview' | 'operations.resources' | 'operations.command-queue' | 'operations.sessions' | 'operations.task-scheduler' | 'monitoring' | 'monitoring.calendar' | 'monitoring.activity-log' | 'monitoring.execution-logs' | 'monitoring.execution-health' | 'monitoring.cost-analytics' | 'monitoring.notifications' | 'monitoring.submitted-requests' | 'settings' | 'settings.account' | 'settings.appearance' | 'settings.roles' | 'settings.organization' | 'settings.credentials' | 'settings.api-keys' | 'settings.webhooks' | 'settings.deployments' | 'admin' | 'admin.system-health' | 'admin.organizations' | 'admin.users' | 'admin.design-showcase' | 'admin.debug' | 'archive' | 'archive.agent-chat' | 'archive.execution-runner' | 'seo' | 'knowledge' | 'knowledge.base'
35
35
  ```
36
36
 
37
37
  These are the built-in feature IDs. The `featureId` field on a `FeatureModule` manifest must match the `id` of a feature in the organization model to enable access-flag gating.
@@ -0,0 +1,99 @@
1
+ ---
2
+ title: Spine Primer
3
+ description: Tenant-facing primer for using an Organization Model catalog as the shared coordination spine between workflow producers, runtime state, API filters, and UI projections.
4
+ ---
5
+ <!-- @generated by packages/sdk/scripts/copy-reference-docs.mjs -- DO NOT EDIT -->
6
+ <!-- Regenerate: pnpm scaffold:sync -->
7
+
8
+
9
+ # Spine Primer
10
+
11
+ Use this primer when a tenant domain has a closed set of stages, statuses, or catalog keys that multiple surfaces must share. A spine is the tenant Organization Model vocabulary that coordinates workflows, runtime state, API reads, and UI rendering without forcing those surfaces to import from each other.
12
+
13
+ The lead-generation pattern is the reference shape: `organizationModel.prospecting.stages` defines the stage vocabulary, workflow templates reference those stages, workflow factories validate stage keys before running, entity state stores sparse per-stage progress, and UI views render progress from the same vocabulary.
14
+
15
+ ## What The Spine Owns
16
+
17
+ A spine owns the shared vocabulary for one domain. The vocabulary is not just a list of strings. Each key should carry enough metadata for consumers to derive behavior consistently:
18
+
19
+ - `key` identifies the stage or catalog member.
20
+ - `label` gives a human-readable name.
21
+ - `description` explains the business meaning.
22
+ - `order` gives stable display and workflow ordering.
23
+ - `entity` identifies which tenant entity the stage updates.
24
+
25
+ The same keys then appear in four places:
26
+
27
+ | Role | Tenant-facing shape |
28
+ | --- | --- |
29
+ | Vocabulary | `organizationModel.prospecting.stages` |
30
+ | Process | workflow templates and build steps that reference stage keys |
31
+ | Runtime state | entity state maps such as `{ [stageKey]: { status, updatedAt, data } }` |
32
+ | Consumer projection | API filters, progress summaries, and UI step rendering |
33
+
34
+ ## Layering
35
+
36
+ ```text
37
+ tenant Organization Model
38
+ - prospecting stages
39
+ - workflow templates
40
+ - capability bindings
41
+ |
42
+ +--> workflow factory
43
+ | - validates stage keys
44
+ | - runs producers
45
+ | - dispatches entity-tagged results
46
+ |
47
+ +--> API and query helpers
48
+ | - filter pending entities by stage key
49
+ | - aggregate progress from state maps
50
+ |
51
+ +--> UI projections
52
+ - render labels and order from the catalog
53
+ - distinguish known and unknown state keys
54
+
55
+ entity runtime state
56
+ { [stageKey]: { status, updatedAt, data } }
57
+ ```
58
+
59
+ The important boundary is that producers and consumers coordinate through the Organization Model vocabulary plus runtime state. They do not coordinate through direct imports, duplicated string constants, or workflow-specific side channels.
60
+
61
+ ## Invariants
62
+
63
+ 1. **The vocabulary is closed and validated.** Workflow factories should reject stage keys that are not present in the tenant Organization Model.
64
+
65
+ 2. **The vocabulary carries metadata.** Labels, descriptions, ordering, and entity ownership should come from the catalog rather than being copied into each consumer.
66
+
67
+ 3. **Runtime state is sparse and additive.** New stages appear in entity state when reached. Adding a catalog member should not require backfilling every entity.
68
+
69
+ 4. **Producers return entity-tagged results.** Workflow steps should return which entity changed, its identifier, status, and optional data. The factory owns writing those results to the correct state map.
70
+
71
+ 5. **Capability binding is separate from stage naming.** Workflow templates should point at capability keys, and the tenant environment can bind those capabilities to concrete workflow resources.
72
+
73
+ ## Applying The Pattern
74
+
75
+ Use this checklist when adding or changing a tenant domain spine:
76
+
77
+ 1. Define the domain catalog in the tenant Organization Model.
78
+ 2. Include labels, descriptions, ordering, and entity ownership in each catalog entry.
79
+ 3. Make workflow templates reference catalog keys instead of free-form strings.
80
+ 4. Validate template stage keys when constructing workflow factories.
81
+ 5. Store progress in sparse entity state maps keyed by catalog member.
82
+ 6. Return entity-tagged workflow results and let the factory dispatch state updates.
83
+ 7. Read progress through query helpers that use the same catalog keys.
84
+ 8. Render UI labels, order, and status from the catalog plus state map.
85
+
86
+ Promote a vocabulary to a spine when the same catalog coordinates all three surfaces: at least one process definition, at least one workflow producer, and at least one independent consumer such as an API query or UI view.
87
+
88
+ ## Counter-Patterns
89
+
90
+ Avoid these patterns in spine-governed domains:
91
+
92
+ - Free-form stage strings in workflow inputs.
93
+ - Duplicated UI-only labels or ordering.
94
+ - Per-workflow skip logic that bypasses the shared pending and progress contract.
95
+ - State writes from individual steps instead of the workflow factory.
96
+ - Hidden side channels for progress, such as ad hoc context keys.
97
+ - Direct coupling between producer code and consumer UI code.
98
+
99
+ When in doubt, update the Organization Model vocabulary first, then let workflow templates, factories, queries, and views project from it.