@elevasis/sdk 1.18.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.
@@ -4742,6 +4742,63 @@ z.object({
4742
4742
  defaultPipelineId: ModelIdSchema,
4743
4743
  pipelines: z.array(SalesPipelineSchema).min(1)
4744
4744
  });
4745
+ var CRM_DISCOVERY_REPLIED_STATE = {
4746
+ stateKey: "discovery_replied",
4747
+ label: "Discovery Replied"
4748
+ };
4749
+ var CRM_DISCOVERY_LINK_SENT_STATE = {
4750
+ stateKey: "discovery_link_sent",
4751
+ label: "Discovery Link Sent"
4752
+ };
4753
+ var CRM_DISCOVERY_NUDGING_STATE = {
4754
+ stateKey: "discovery_nudging",
4755
+ label: "Discovery Nudging"
4756
+ };
4757
+ var CRM_DISCOVERY_BOOKING_CANCELLED_STATE = {
4758
+ stateKey: "discovery_booking_cancelled",
4759
+ label: "Discovery Booking Cancelled"
4760
+ };
4761
+ var CRM_REPLY_SENT_STATE = {
4762
+ stateKey: "reply_sent",
4763
+ label: "Reply Sent"
4764
+ };
4765
+ var CRM_FOLLOWUP_1_SENT_STATE = {
4766
+ stateKey: "followup_1_sent",
4767
+ label: "Follow-up 1 Sent"
4768
+ };
4769
+ var CRM_FOLLOWUP_2_SENT_STATE = {
4770
+ stateKey: "followup_2_sent",
4771
+ label: "Follow-up 2 Sent"
4772
+ };
4773
+ var CRM_FOLLOWUP_3_SENT_STATE = {
4774
+ stateKey: "followup_3_sent",
4775
+ label: "Follow-up 3 Sent"
4776
+ };
4777
+ var CRM_PIPELINE_DEFINITION = {
4778
+ pipelineKey: "crm",
4779
+ stages: [
4780
+ {
4781
+ stageKey: "interested",
4782
+ label: "Interested",
4783
+ color: "blue",
4784
+ states: [
4785
+ CRM_DISCOVERY_REPLIED_STATE,
4786
+ CRM_DISCOVERY_LINK_SENT_STATE,
4787
+ CRM_DISCOVERY_NUDGING_STATE,
4788
+ CRM_DISCOVERY_BOOKING_CANCELLED_STATE,
4789
+ CRM_REPLY_SENT_STATE,
4790
+ CRM_FOLLOWUP_1_SENT_STATE,
4791
+ CRM_FOLLOWUP_2_SENT_STATE,
4792
+ CRM_FOLLOWUP_3_SENT_STATE
4793
+ ]
4794
+ },
4795
+ { stageKey: "proposal", label: "Proposal", color: "yellow", states: [] },
4796
+ { stageKey: "closing", label: "Closing", color: "orange", states: [] },
4797
+ { stageKey: "closed_won", label: "Closed Won", color: "green", states: [] },
4798
+ { stageKey: "closed_lost", label: "Closed Lost", color: "red", states: [] },
4799
+ { stageKey: "nurturing", label: "Nurturing", color: "grape", states: [] }
4800
+ ]
4801
+ };
4745
4802
  var LEAD_GEN_STAGE_CATALOG = {
4746
4803
  // Prospecting — company population
4747
4804
  scraped: {
@@ -4849,20 +4906,86 @@ var ProspectingBuildTemplateSchema = DisplayMetadataSchema.extend({
4849
4906
  id: ModelIdSchema,
4850
4907
  steps: z.array(ProspectingBuildTemplateStepSchema).min(1)
4851
4908
  });
4852
- var CAPABILITY_REGISTRY = {
4853
- "lead-gen.company.source": "lgn-import-workflow",
4854
- "lead-gen.company.apollo-import": "lgn-01c-apollo-import-workflow",
4855
- "lead-gen.contact.discover": "lgn-04-email-discovery-workflow",
4856
- "lead-gen.contact.verify-email": "lgn-05-email-verification-workflow",
4857
- "lead-gen.company.website-extract": "lgn-02-website-extract-workflow",
4858
- "lead-gen.company.qualify": "lgn-03-company-qualification-workflow",
4859
- "lead-gen.company.dtc-subscription-qualify": "lgn-03b-dtc-subscription-score-workflow",
4860
- "lead-gen.contact.apollo-decision-maker-enrich": "lgn-04b-apollo-decision-maker-enrich-workflow",
4861
- "lead-gen.contact.personalize": "ist-personalization-workflow",
4862
- "lead-gen.review.outreach-ready": "ist-upload-contacts-workflow",
4863
- "lead-gen.export.list": "lgn-06-export-list-workflow",
4864
- "lead-gen.company.cleanup": "lgn-company-cleanup-workflow"
4865
- };
4909
+ z.object({
4910
+ id: ModelIdSchema,
4911
+ label: z.string(),
4912
+ description: z.string(),
4913
+ resourceId: ModelIdSchema
4914
+ });
4915
+ var CAPABILITY_REGISTRY = [
4916
+ {
4917
+ id: "lead-gen.company.source",
4918
+ label: "Source companies",
4919
+ description: "Import source companies from a list provider.",
4920
+ resourceId: "lgn-import-workflow"
4921
+ },
4922
+ {
4923
+ id: "lead-gen.company.apollo-import",
4924
+ label: "Import from Apollo",
4925
+ description: "Pull companies and seed contact data from an Apollo search or list.",
4926
+ resourceId: "lgn-01c-apollo-import-workflow"
4927
+ },
4928
+ {
4929
+ id: "lead-gen.contact.discover",
4930
+ label: "Discover contact emails",
4931
+ description: "Find email addresses for contacts at qualified companies.",
4932
+ resourceId: "lgn-04-email-discovery-workflow"
4933
+ },
4934
+ {
4935
+ id: "lead-gen.contact.verify-email",
4936
+ label: "Verify emails",
4937
+ description: "Check email deliverability before outreach.",
4938
+ resourceId: "lgn-05-email-verification-workflow"
4939
+ },
4940
+ {
4941
+ id: "lead-gen.company.website-extract",
4942
+ label: "Extract website signals",
4943
+ description: "Scrape and analyze company websites for qualification signals.",
4944
+ resourceId: "lgn-02-website-extract-workflow"
4945
+ },
4946
+ {
4947
+ id: "lead-gen.company.qualify",
4948
+ label: "Qualify companies",
4949
+ description: "Score and filter companies against the ICP rubric.",
4950
+ resourceId: "lgn-03-company-qualification-workflow"
4951
+ },
4952
+ {
4953
+ id: "lead-gen.company.dtc-subscription-qualify",
4954
+ label: "Qualify DTC subscription fit",
4955
+ description: "Classify subscription potential and consumable-product fit for DTC brands.",
4956
+ resourceId: "lgn-03b-dtc-subscription-score-workflow"
4957
+ },
4958
+ {
4959
+ id: "lead-gen.contact.apollo-decision-maker-enrich",
4960
+ label: "Enrich decision-makers",
4961
+ description: "Find and enrich qualified contacts at qualified companies via Apollo.",
4962
+ resourceId: "lgn-04b-apollo-decision-maker-enrich-workflow"
4963
+ },
4964
+ {
4965
+ id: "lead-gen.contact.personalize",
4966
+ label: "Personalize outreach",
4967
+ description: "Generate personalized opening lines for each contact.",
4968
+ resourceId: "ist-personalization-workflow"
4969
+ },
4970
+ {
4971
+ id: "lead-gen.review.outreach-ready",
4972
+ label: "Upload to outreach",
4973
+ description: "Upload approved contacts to the outreach sequence after QC review.",
4974
+ resourceId: "ist-upload-contacts-workflow"
4975
+ },
4976
+ {
4977
+ id: "lead-gen.export.list",
4978
+ label: "Export lead list",
4979
+ description: "Export approved leads as a downloadable lead list.",
4980
+ resourceId: "lgn-06-export-list-workflow"
4981
+ },
4982
+ {
4983
+ id: "lead-gen.company.cleanup",
4984
+ label: "Clean up companies",
4985
+ description: "Remove disqualified or duplicate companies from the list.",
4986
+ resourceId: "lgn-company-cleanup-workflow"
4987
+ }
4988
+ ];
4866
4989
  var PROSPECTING_STEPS = {
4867
4990
  localServices: {
4868
4991
  sourceCompanies: {
@@ -5098,9 +5221,13 @@ var ProcessingStageStatusSchema = z.enum(["success", "no_result", "skipped", "er
5098
5221
  var LeadGenStageKeySchema = z.string().refine((value) => Object.prototype.hasOwnProperty.call(LEAD_GEN_STAGE_CATALOG, value), {
5099
5222
  message: "processing state key must match LEAD_GEN_STAGE_CATALOG"
5100
5223
  });
5101
- var LeadGenCapabilityKeySchema = z.string().refine((value) => Object.prototype.hasOwnProperty.call(CAPABILITY_REGISTRY, value), {
5224
+ var LeadGenCapabilityKeySchema = z.string().refine((value) => CAPABILITY_REGISTRY.some((c) => c.id === value), {
5102
5225
  message: "capabilityKey must match CAPABILITY_REGISTRY"
5103
5226
  });
5227
+ var crmStageKeys = CRM_PIPELINE_DEFINITION.stages.map((stage) => stage.stageKey);
5228
+ var crmStateKeys = CRM_PIPELINE_DEFINITION.stages.flatMap((stage) => stage.states.map((state) => state.stateKey));
5229
+ var CrmStageKeySchema = z.enum(crmStageKeys);
5230
+ var CrmStateKeySchema = z.enum(crmStateKeys);
5104
5231
  var ProcessingStateEntrySchema = z.object({
5105
5232
  status: ProcessingStageStatusSchema,
5106
5233
  data: z.unknown().optional()
@@ -5108,7 +5235,7 @@ var ProcessingStateEntrySchema = z.object({
5108
5235
  var ProcessingStateSchema = z.record(LeadGenStageKeySchema, ProcessingStateEntrySchema);
5109
5236
  var CompanyProcessingStateSchema = ProcessingStateSchema;
5110
5237
  var ContactProcessingStateSchema = ProcessingStateSchema;
5111
- var DealStageSchema = z.enum(["interested", "proposal", "closing", "closed_won", "closed_lost", "nurturing"]);
5238
+ var DealStageSchema = CrmStageKeySchema;
5112
5239
  var AcqDealTaskKindSchema = z.enum(["call", "email", "meeting", "other"]);
5113
5240
  z.object({
5114
5241
  dealId: UuidSchema
@@ -5144,12 +5271,19 @@ z.object({
5144
5271
  z.object({
5145
5272
  pipelineKey: z.string().min(1),
5146
5273
  stageKey: z.string().min(1),
5147
- stateKey: z.string().nullable().optional(),
5274
+ stateKey: z.string().min(1).nullable().optional(),
5275
+ reason: z.string().optional(),
5276
+ expectedUpdatedAt: z.string().datetime().optional()
5277
+ }).strict();
5278
+ z.object({
5279
+ pipelineKey: z.literal(CRM_PIPELINE_DEFINITION.pipelineKey),
5280
+ stageKey: CrmStageKeySchema,
5281
+ stateKey: CrmStateKeySchema.nullable().optional(),
5148
5282
  reason: z.string().optional(),
5149
5283
  expectedUpdatedAt: z.string().datetime().optional()
5150
5284
  }).strict();
5151
5285
  z.object({
5152
- stateKey: z.string().min(1),
5286
+ stateKey: CrmStateKeySchema,
5153
5287
  reason: z.string().optional(),
5154
5288
  expectedUpdatedAt: z.string().datetime().optional()
5155
5289
  }).strict();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elevasis/sdk",
3
- "version": "1.18.0",
3
+ "version": "1.19.0",
4
4
  "description": "SDK for building Elevasis organization resources",
5
5
  "type": "module",
6
6
  "bin": {
@@ -57,7 +57,7 @@
57
57
  "tsup": "^8.0.0",
58
58
  "typescript": "5.9.2",
59
59
  "zod": "^4.1.0",
60
- "@repo/core": "0.19.0",
60
+ "@repo/core": "0.20.0",
61
61
  "@repo/eslint-config": "0.0.0",
62
62
  "@repo/typescript-config": "0.0.0"
63
63
  },
@@ -0,0 +1,4 @@
1
+ {
2
+ "generatedBy": "generate-knowledge-nodes",
3
+ "domains": {}
4
+ }
@@ -131,9 +131,9 @@ through `/knowledge`; do not point them at monorepo-only commands.
131
131
  ```bash
132
132
  pnpm exec elevasis knowledge:ls
133
133
  pnpm exec elevasis knowledge:cat <node-id>
134
- pnpm exec elevasis knowledge:graph --axis by-feature
135
- pnpm exec elevasis knowledge:graph --axis by-domain
136
- pnpm exec elevasis knowledge:graph --mount <mount-id>
134
+ pnpm exec elevasis knowledge:ls /by-feature/<feature-id>
135
+ pnpm exec elevasis knowledge:ls /by-owner/<owner-id>
136
+ pnpm exec elevasis knowledge:graph <node-id>
137
137
  ```
138
138
 
139
139
  ### External projects (org instance)
@@ -141,14 +141,15 @@ pnpm exec elevasis knowledge:graph --mount <mount-id>
141
141
  ```bash
142
142
  pnpm exec elevasis-sdk knowledge:ls
143
143
  pnpm exec elevasis-sdk knowledge:cat <node-id>
144
- pnpm exec elevasis-sdk knowledge:graph --axis by-feature
145
- pnpm exec elevasis-sdk knowledge:graph --axis by-domain
146
- pnpm exec elevasis-sdk knowledge:graph --mount <mount-id>
144
+ pnpm exec elevasis-sdk knowledge:ls /by-feature/<feature-id>
145
+ pnpm exec elevasis-sdk knowledge:ls /by-owner/<owner-id>
146
+ pnpm exec elevasis-sdk knowledge:graph <node-id>
147
147
  ```
148
148
 
149
149
  Use `knowledge:ls` to enumerate all knowledge nodes. Use `knowledge:cat` to read a specific
150
- node's content. Use `knowledge:graph` to navigate the governance graph -- `by-feature` is the
151
- default axis for "what governs X?" queries; `by-domain` for domain-wide surveys.
150
+ node's content. Use `knowledge:ls /by-feature/<feature-id>` or
151
+ `knowledge:ls /by-owner/<owner-id>` to navigate feature and owner groupings. Use
152
+ `knowledge:graph <node-id>` to inspect incoming and outgoing graph edges for a specific node.
152
153
 
153
154
  ### `/knowledge read-folder` (chat shorthand from the Knowledge Browser)
154
155
 
@@ -570,12 +570,12 @@ the user what happens if they omit the `default` route (runtime failure for unma
570
570
 
571
571
  ### Item 8: Going to production
572
572
 
573
- **Goal:** The user knows the dev/prod split, version bumping flags, and the `cli-cwd-invariant`
574
- rule for `--prod` flag placement.
573
+ **Goal:** The user knows the dev/prod split, version bumping flags, and the SDK CLI CWD
574
+ guidance in the deployment rule.
575
575
 
576
576
  **Estimated time:** 15 min
577
577
 
578
- **Files referenced:** `.claude/rules/deployment.md`, `.claude/rules/cli-cwd-invariant.md`
578
+ **Files referenced:** `.claude/rules/deployment.md`
579
579
 
580
580
  **Commands:** `pnpm -C operations deploy:prod`
581
581
 
@@ -606,19 +606,17 @@ pnpm elevasis-sdk deploy --prod --major # 1.0.0 -> 2.0.0
606
606
  Bump rules: `--patch` for bug fixes, `--minor` for new features (no breaking schema changes),
607
607
  `--major` for breaking input/output schema changes.
608
608
 
609
- **The `cli-cwd-invariant`.** Read `.claude/rules/cli-cwd-invariant.md`. Two critical rules:
609
+ **SDK CLI CWD guidance.** Read `.claude/rules/deployment.md`. Two critical rules:
610
610
 
611
- 1. The `--prod` flag on the `elevasis-sdk` binary MUST come before the subcommand name:
611
+ 1. The `--prod` flag belongs to the `deploy` command:
612
612
 
613
613
  ```bash
614
614
  # Correct
615
- pnpm elevasis-sdk --prod deploy
616
- # Wrong -- --prod after deploy is silently ignored
617
615
  pnpm elevasis-sdk deploy --prod
618
616
  ```
619
617
 
620
618
  The `pnpm -C operations deploy:prod` script in `package.json` handles this correctly.
621
- Prefer the script over a raw CLI call to avoid the pitfall.
619
+ Prefer the script over a raw CLI call for production deploys.
622
620
 
623
621
  2. Never use bare `cd <dir> && elevasis-sdk ...` -- use a subshell `(cd <dir> && ...)` or
624
622
  `pnpm -C <dir> ...` to avoid CWD drift that causes env resolution failures.
@@ -0,0 +1,60 @@
1
+ # 2026-05-06 -- CRM OM Spine Migration
2
+
3
+ ## Why this note exists
4
+
5
+ The CRM deal vocabulary (`stage_key`, `state_key`, `pipeline_key`) is now a fully-realized OM Spine matching the lead-gen list-builder pattern. `CRM_PIPELINE_DEFINITION` becomes the single source of truth: `@elevasis/core` derives `CrmStageKeySchema` and `CrmStateKeySchema` from the catalog, the catalog gains optional `color?` metadata on each stage, and `@elevasis/sdk` re-exports both schemas plus the catalog so external SDK consumers see the same vocabulary as monorepo callers. `@elevasis/ui` rewires the CRM page helpers (`DEAL_STAGE_COLORS`, `DEAL_STAGE_OPTIONS`, `formatDealStageLabel`, `formatDealStateLabel`) to read from the catalog instead of hardcoded maps -- public exports are preserved, behavior is now catalog-driven.
6
+
7
+ The platform side also closed a long-standing data drift: `pipeline_key='default'` in `acq_deals` is gone; live writers now use `pipeline_key='crm'` matching the catalog's `pipelineKey: 'crm'`. The Elevasis backfill applied directly to prod and dev on 2026-05-06; tenant deal rows are not affected by that backfill and continue to use whatever value tenant code wrote.
8
+
9
+ ## Applies to
10
+
11
+ - All template-derived projects that consume `@elevasis/core`, `@elevasis/ui`, or `@elevasis/sdk`.
12
+ - Projects that customize CRM stages or states in `core/config/organization-model.ts` under the `sales` domain.
13
+ - Projects that read or write CRM transitions through `@elevasis/sdk` worker adapters (`acqDb.transitionDeal`, `acqDb.transitionItem`).
14
+ - Projects that render CRM pipeline UI from `@elevasis/ui/features/crm`.
15
+
16
+ ## Required actions
17
+
18
+ 1. Pull synced template package baselines through `/git-sync`:
19
+ - `core/package.json`: `@elevasis/core` -> 0.20.0
20
+ - `ui/package.json`: `@elevasis/ui` -> 2.29.0
21
+ - `operations/package.json`: `@elevasis/core` -> 0.20.0 and `@elevasis/sdk` -> 1.19.0
22
+
23
+ 2. Run `pnpm install` and rebuild the project:
24
+
25
+ ```bash
26
+ pnpm install
27
+ pnpm -C ui build
28
+ pnpm -C ui exec tsc --noEmit
29
+ pnpm -C operations exec tsc --noEmit
30
+ ```
31
+
32
+ 3. **Optional: adopt `color?` on customized CRM stages.** If `core/config/organization-model.ts` overrides `sales.stages` with custom labels, you may now add an optional `color` field per stage (any Mantine palette key: `blue`, `yellow`, `orange`, `green`, `red`, `grape`, etc.). The shipped `DEAL_STAGE_COLORS` map and CRM kanban UI will read it. Stages without a `color` fall back to the platform default mapping in the catalog.
33
+
34
+ 4. **Optional: tighten project-owned CRM workflow inputs.** New schemas are available from `@elevasis/sdk`:
35
+
36
+ ```ts
37
+ import { CrmStageKeySchema, CrmStateKeySchema, CRM_PIPELINE_DEFINITION } from '@elevasis/sdk'
38
+ ```
39
+
40
+ Project-authored CRM action workflows that previously used `z.string()` for `toStage` / `toState` can now validate against the catalog-derived enum. The `transitionItem` / `transitionDeal` worker adapters still accept strings, but unknown stage/state keys are rejected at the platform writer layer for `pipelineKey: 'crm'` writers.
41
+
42
+ 5. **No tenant data backfill required.** The `pipeline_key='default'` -> `'crm'` backfill was applied to Elevasis databases only. Tenant `acq_deals` rows are unaffected. If tenant code writes `pipelineKey: 'default'` to `acqDb.transitionDeal`, that behavior is unchanged; only the published catalog declares `'crm'` as canonical and the published schemas validate `'crm'` exclusively for CRM-shaped transitions.
43
+
44
+ ## Verification
45
+
46
+ After applying the actions above:
47
+
48
+ - `pnpm -C ui check-types`
49
+ - `pnpm -C ui build`
50
+ - `pnpm -C ui test`
51
+ - `pnpm -C operations check`
52
+ - `pnpm -C operations check-types`
53
+ - `pnpm -C operations test`
54
+ - Browser smoke: open `/crm/pipeline` (or the project's CRM kanban surface) and verify stage labels and column colors render from the catalog. Custom-labeled stages should show the override label; default stages show the platform palette.
55
+
56
+ ## Not handled by /git-sync
57
+
58
+ - **Tenant CRM action workflows.** If a project authored its own CRM action workflows in `operations/` that import `transitionDeal` / `syncDealStateKeyToDb` directly (rather than `emitCrmTransition`), `/git-sync` does NOT refactor them. The platform-side `emitCrmTransition` factory is internal to `@repo/elevasis-operations` (workspace-internal) and is not part of the published SDK surface. Project-owned workflows continue to call the worker adapters directly; the new validation guard rejects unknown stage/state keys but does not require migration.
59
+ - **Customized stage colors.** Existing tenant overrides under `sales.stages[].label` and `sales.stages[].states[]` continue to work unchanged. Adopting the new optional `color` field is a project-by-project decision; `/git-sync` will not infer colors for custom stages.
60
+ - **`pipeline_key` data in tenant databases.** If a project has historic `acq_deals` rows with `pipeline_key='default'` and wants to align with the new canonical `'crm'` identity, that is a tenant-managed migration -- not part of this train.
@@ -1126,7 +1126,7 @@ export const DEFAULT_CRM_PRIORITY_RULE_CONFIG: CrmPriorityRuleConfig = {
1126
1126
  ### `DealStageSchema`
1127
1127
 
1128
1128
  ```typescript
1129
- export const DealStageSchema = z.enum(['interested', 'proposal', 'closing', 'closed_won', 'closed_lost', 'nurturing'])
1129
+ export const DealStageSchema = CrmStageKeySchema
1130
1130
  ```
1131
1131
 
1132
1132
  ### `AcqDealTaskKindSchema`
@@ -1218,7 +1218,7 @@ export const TransitionItemRequestSchema = z
1218
1218
  .object({
1219
1219
  pipelineKey: z.string().min(1),
1220
1220
  stageKey: z.string().min(1),
1221
- stateKey: z.string().nullable().optional(),
1221
+ stateKey: z.string().min(1).nullable().optional(),
1222
1222
  reason: z.string().optional(),
1223
1223
  expectedUpdatedAt: z.string().datetime().optional()
1224
1224
  })
@@ -1412,6 +1412,11 @@ export const DealTaskListResponseSchema = z.array(DealTaskResponseSchema)
1412
1412
 
1413
1413
  ```typescript
1414
1414
  export const DealSchemas = {
1415
+ // Primitives
1416
+ CrmStageKey: CrmStageKeySchema,
1417
+ CrmStateKey: CrmStateKeySchema,
1418
+ DealStage: DealStageSchema,
1419
+
1415
1420
  // Params
1416
1421
  DealIdParams: DealIdParamsSchema,
1417
1422
  DealTaskIdParams: DealTaskIdParamsSchema,
@@ -1424,7 +1429,7 @@ export const DealSchemas = {
1424
1429
  // Request bodies
1425
1430
  CreateDealNoteRequest: CreateDealNoteRequestSchema,
1426
1431
  CreateDealTaskRequest: CreateDealTaskRequestSchema,
1427
- TransitionItemRequest: TransitionItemRequestSchema,
1432
+ TransitionItemRequest: CrmTransitionItemRequestSchema,
1428
1433
  TransitionDealStateRequest: TransitionDealStateRequestSchema,
1429
1434
  ExecuteActionParams: ExecuteActionParamsSchema,
1430
1435
  ExecuteActionRequest: ExecuteActionRequestSchema,
@@ -2555,7 +2560,7 @@ export const AcqSubstrateSchemas = {
2555
2560
  ListCompanyIdParams: ListCompanyIdParamsSchema,
2556
2561
  AcqListCompanyResponse: AcqListCompanyResponseSchema,
2557
2562
 
2558
- // Transition (shared with deals — TransitionItemRequestSchema)
2563
+ // Transition (generic stateful substrate)
2559
2564
  TransitionItemRequest: TransitionItemRequestSchema
2560
2565
  }
2561
2566
  ```
@@ -2623,6 +2628,8 @@ export interface StatefulStageDefinition {
2623
2628
  /** Matches stage_key values written by workflow steps. */
2624
2629
  stageKey: string
2625
2630
  label: string
2631
+ /** UI color token. Consumers may map this to their design system. */
2632
+ color?: string
2626
2633
  states: StatefulStateDefinition[]
2627
2634
  }
2628
2635
  ```