@elevasis/core 0.12.0 → 0.14.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 (50) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.js +9 -2
  3. package/dist/organization-model/index.d.ts +1 -1
  4. package/dist/organization-model/index.js +9 -2
  5. package/dist/test-utils/index.d.ts +480 -389
  6. package/dist/test-utils/index.js +28 -2
  7. package/package.json +1 -1
  8. package/src/_gen/__tests__/__snapshots__/contracts.md.snap +2324 -0
  9. package/src/auth/multi-tenancy/credentials/__tests__/encryption.test.ts +217 -216
  10. package/src/auth/multi-tenancy/credentials/server/encryption.ts +5 -19
  11. package/src/auth/multi-tenancy/credentials/server/kek-loader.ts +3 -13
  12. package/src/auth/multi-tenancy/permissions.ts +12 -5
  13. package/src/business/acquisition/activity-events.test.ts +250 -0
  14. package/src/business/acquisition/activity-events.ts +84 -0
  15. package/src/business/acquisition/api-schemas.test.ts +1180 -0
  16. package/src/business/acquisition/api-schemas.ts +456 -235
  17. package/src/business/acquisition/crm-state-actions.test.ts +160 -0
  18. package/src/business/acquisition/derive-actions.test.ts +518 -0
  19. package/src/business/acquisition/derive-actions.ts +103 -0
  20. package/src/business/acquisition/index.ts +51 -11
  21. package/src/business/acquisition/stateful.ts +30 -0
  22. package/src/business/acquisition/types.ts +44 -77
  23. package/src/execution/engine/index.ts +4 -1
  24. package/src/execution/engine/tools/integration/server/adapters/apify/__tests__/apify-run-actor.integration.test.ts +1 -2
  25. package/src/execution/engine/tools/integration/server/adapters/attio/__tests__/attio-crud.integration.test.ts +363 -361
  26. package/src/execution/engine/tools/integration/server/adapters/attio/fetch/get-record/index.test.ts +162 -186
  27. package/src/execution/engine/tools/integration/server/adapters/attio/fetch/list-records/index.test.ts +316 -338
  28. package/src/execution/engine/tools/integration/server/adapters/gmail/gmail-adapter.ts +204 -210
  29. package/src/execution/engine/tools/integration/server/adapters/resend/fetch/send-email/index.test.ts +88 -0
  30. package/src/execution/engine/tools/integration/server/adapters/resend/fetch/send-email/index.ts +141 -134
  31. package/src/execution/engine/tools/integration/server/adapters/resend/fetch/utils/types.ts +76 -75
  32. package/src/execution/engine/tools/integration/service.test.ts +34 -9
  33. package/src/execution/engine/tools/integration/service.ts +6 -3
  34. package/src/execution/engine/tools/lead-service-types.ts +90 -30
  35. package/src/execution/engine/tools/platform/acquisition/types.ts +266 -260
  36. package/src/execution/engine/tools/registry.ts +5 -4
  37. package/src/execution/engine/tools/tool-maps.ts +43 -21
  38. package/src/execution/engine/workflow/types.ts +11 -0
  39. package/src/organization-model/contracts.ts +4 -4
  40. package/src/organization-model/domains/navigation.ts +62 -62
  41. package/src/organization-model/domains/sales.ts +272 -0
  42. package/src/organization-model/organization-graph.mdx +2 -2
  43. package/src/organization-model/published.ts +21 -21
  44. package/src/organization-model/resolve.ts +21 -8
  45. package/src/platform/constants/versions.ts +1 -1
  46. package/src/reference/_generated/contracts.md +2324 -0
  47. package/src/scaffold-registry/index.ts +10 -9
  48. package/src/scaffold-registry/schema.ts +68 -62
  49. package/src/supabase/database.types.ts +2958 -2884
  50. package/src/test-utils/rls/RLSTestContext.ts +585 -553
@@ -241,7 +241,7 @@ import type {
241
241
  MarkProposalReviewedParams,
242
242
  UpdateCloseLostReasonParams,
243
243
  UpdateFeesParams,
244
- SyncDealStageParams,
244
+ TransitionItemParams,
245
245
  SetContactNurtureParams,
246
246
  CancelSchedulesAndHitlByEmailParams,
247
247
  CancelHitlByDealIdParams,
@@ -249,7 +249,9 @@ import type {
249
249
  DeleteDealParams,
250
250
  DealFilters,
251
251
  DealPipelineAnalytics,
252
- ListConfig,
252
+ ScrapingConfig,
253
+ IcpRubric,
254
+ PipelineConfig,
253
255
  RecordListExecutionParams,
254
256
  UpdateCompanyStageParams,
255
257
  UpdateContactStageParams,
@@ -402,8 +404,6 @@ export type ProjectsToolMap = {
402
404
  type CrmRecentActivityParams = Partial<z.infer<typeof CrmSchemas.GetRecentActivityQuery>>
403
405
  type CrmListDealsParams = Partial<z.infer<typeof DealSchemas.ListDealsQuery>>
404
406
  type CrmGetDealParams = z.infer<typeof DealSchemas.DealIdParams>
405
- type CrmUpdateDealStageParams = z.infer<typeof DealSchemas.DealIdParams> &
406
- z.infer<typeof DealSchemas.SyncDealStageRequest>
407
407
  type CrmGetDealByEmailParams = { email: string }
408
408
  type CrmTaskDueParams = Partial<z.infer<typeof DealSchemas.ListDealTasksDueQuery>>
409
409
  type CrmDealTaskParams = Omit<CreateDealTaskParams, 'organizationId'>
@@ -416,7 +416,6 @@ export type CrmToolMap = {
416
416
  listDeals: { params: CrmListDealsParams; result: DealListItem[] }
417
417
  getDeal: { params: CrmGetDealParams; result: DealDetail | null }
418
418
  getDealByEmail: { params: CrmGetDealByEmailParams; result: DealDetail | null }
419
- updateDealStage: { params: CrmUpdateDealStageParams; result: void }
420
419
  createDealNote: { params: CrmDealNoteParams; result: AcqDealNote }
421
420
  listDealNotes: { params: Omit<ListDealNotesParams, 'organizationId'>; result: AcqDealNote[] }
422
421
  createDealTask: { params: CrmDealTaskParams; result: AcqDealTask }
@@ -572,20 +571,20 @@ export type MillionVerifierToolMap = {
572
571
  export type LeadToolMap = {
573
572
  // List operations
574
573
  listLists: { params: Record<string, never>; result: AcqList[] }
575
- createList: { params: Omit<CreateListParams, 'organizationId'>; result: AcqList }
576
- updateList: { params: { id: string } & UpdateListParams; result: AcqList }
577
- deleteList: { params: { id: string }; result: void }
578
- addContactsToList: { params: Omit<AddContactsToListParams, 'organizationId'>; result: AddContactsToListResult }
579
- updateCompanyStage: {
580
- params: Omit<UpdateCompanyStageParams, 'organizationId'>
581
- result: void
582
- }
583
- updateContactStage: {
584
- params: Omit<UpdateContactStageParams, 'organizationId'>
585
- result: void
586
- }
587
- // Company operations
588
- createCompany: { params: Omit<CreateCompanyParams, 'organizationId'>; result: AcqCompany }
574
+ createList: { params: Omit<CreateListParams, 'organizationId'>; result: AcqList }
575
+ updateList: { params: { id: string } & UpdateListParams; result: AcqList }
576
+ deleteList: { params: { id: string }; result: void }
577
+ addContactsToList: { params: Omit<AddContactsToListParams, 'organizationId'>; result: AddContactsToListResult }
578
+ updateCompanyStage: {
579
+ params: Omit<UpdateCompanyStageParams, 'organizationId'>
580
+ result: void
581
+ }
582
+ updateContactStage: {
583
+ params: Omit<UpdateContactStageParams, 'organizationId'>
584
+ result: void
585
+ }
586
+ // Company operations
587
+ createCompany: { params: Omit<CreateCompanyParams, 'organizationId'>; result: AcqCompany }
589
588
  upsertCompany: { params: Omit<UpsertCompanyParams, 'organizationId'>; result: AcqCompany }
590
589
  updateCompany: { params: { id: string } & UpdateCompanyParams; result: AcqCompany }
591
590
  getCompany: { params: { id: string }; result: AcqCompany | null }
@@ -626,7 +625,7 @@ export type LeadToolMap = {
626
625
  markProposalReviewed: { params: Omit<MarkProposalReviewedParams, 'organizationId'>; result: void }
627
626
  updateCloseLostReason: { params: Omit<UpdateCloseLostReasonParams, 'organizationId'>; result: void }
628
627
  updateFees: { params: Omit<UpdateFeesParams, 'organizationId'>; result: void }
629
- syncDealStage: { params: Omit<SyncDealStageParams, 'organizationId'>; result: void }
628
+ transitionItem: { params: Omit<TransitionItemParams, 'organizationId'>; result: void }
630
629
  setContactNurture: { params: Omit<SetContactNurtureParams, 'organizationId'>; result: void }
631
630
  cancelSchedulesAndHitlByEmail: {
632
631
  params: Omit<CancelSchedulesAndHitlByEmailParams, 'organizationId'>
@@ -678,6 +677,26 @@ export type LeadToolMap = {
678
677
  params: { posts: Omit<UpsertSocialPostParams, 'organizationId'>[] }
679
678
  result: UpsertSocialPostsResult
680
679
  }
680
+ setDealStateKey: {
681
+ params: {
682
+ dealId: string
683
+ stateKey: string
684
+ }
685
+ result: { ok: true }
686
+ }
687
+ // CRM workflow helpers
688
+ transitionDeal: {
689
+ params: {
690
+ dealId: string
691
+ toStage: string
692
+ toState?: string
693
+ }
694
+ result: { deal: AcqDeal }
695
+ }
696
+ loadDeal: {
697
+ params: { dealId: string }
698
+ result: DealDetail | null
699
+ }
681
700
  }
682
701
 
683
702
  // ---------------------------------------------------------------------------
@@ -685,7 +704,10 @@ export type LeadToolMap = {
685
704
  // ---------------------------------------------------------------------------
686
705
 
687
706
  export type ListToolMap = {
688
- getConfig: { params: { listId: string }; result: ListConfig }
707
+ getConfig: {
708
+ params: { listId: string }
709
+ result: { scrapingConfig: ScrapingConfig; icp: IcpRubric; pipelineConfig: PipelineConfig }
710
+ }
689
711
  recordExecution: {
690
712
  params: Omit<RecordListExecutionParams, 'organizationId'>
691
713
  result: void
@@ -82,6 +82,17 @@ export interface WorkflowDefinition {
82
82
  * If provided, workflow appears in Execution Runner UI
83
83
  */
84
84
  interface?: ExecutionInterface
85
+
86
+ /**
87
+ * Lead-gen processing stage this workflow implements (optional).
88
+ * Must match a key in the platform lead-gen stage catalog.
89
+ * Used by org-os graph derivation to surface workflow→stage edges and
90
+ * by pipeline_config validation to confirm each catalog stage has an
91
+ * implementing workflow before a list is activated.
92
+ *
93
+ * Example: stageImplemented: 'verified' on the email-verification workflow.
94
+ */
95
+ stageImplemented?: string
85
96
  }
86
97
 
87
98
  /**
@@ -9,7 +9,7 @@ export const MONITORING_FEATURE_ID = 'monitoring' as const
9
9
  export const SETTINGS_FEATURE_ID = 'settings' as const
10
10
  export const SEO_FEATURE_ID = 'seo' as const
11
11
 
12
- export const SALES_PIPELINE_SURFACE_ID = 'crm.pipeline' as const
13
- export const PROSPECTING_LISTS_SURFACE_ID = 'lead-gen.lists' as const
14
- export const OPERATIONS_COMMAND_VIEW_SURFACE_ID = 'operations.command-view' as const
15
- export const SETTINGS_ROLES_SURFACE_ID = 'settings.roles' as const
12
+ export const SALES_PIPELINE_SURFACE_ID = 'crm.pipeline' as const
13
+ export const PROSPECTING_LISTS_SURFACE_ID = 'lead-gen.lists' as const
14
+ export const OPERATIONS_COMMAND_VIEW_SURFACE_ID = 'operations.command-view' as const
15
+ export const SETTINGS_ROLES_SURFACE_ID = 'settings.roles' as const
@@ -1,11 +1,11 @@
1
1
  import { z } from 'zod'
2
- import {
3
- OPERATIONS_COMMAND_VIEW_SURFACE_ID,
4
- PROJECTS_VIEW_CAPABILITY_ID,
5
- PROJECTS_FEATURE_ID,
6
- PROJECTS_INDEX_SURFACE_ID,
7
- SETTINGS_ROLES_SURFACE_ID
8
- } from '../contracts'
2
+ import {
3
+ OPERATIONS_COMMAND_VIEW_SURFACE_ID,
4
+ PROJECTS_VIEW_CAPABILITY_ID,
5
+ PROJECTS_FEATURE_ID,
6
+ PROJECTS_INDEX_SURFACE_ID,
7
+ SETTINGS_ROLES_SURFACE_ID
8
+ } from '../contracts'
9
9
  import { DescriptionSchema, IconNameSchema, LabelSchema, ModelIdSchema, PathSchema, ReferenceIdsSchema } from './shared'
10
10
 
11
11
  export const SurfaceTypeSchema = z.enum(['page', 'dashboard', 'graph', 'detail', 'list', 'settings'])
@@ -15,10 +15,10 @@ export const SurfaceDefinitionSchema = z.object({
15
15
  label: LabelSchema,
16
16
  path: PathSchema,
17
17
  surfaceType: SurfaceTypeSchema,
18
- description: DescriptionSchema.optional(),
19
- enabled: z.boolean().default(true),
20
- devOnly: z.boolean().optional(),
21
- icon: IconNameSchema.optional(),
18
+ description: DescriptionSchema.optional(),
19
+ enabled: z.boolean().default(true),
20
+ devOnly: z.boolean().optional(),
21
+ icon: IconNameSchema.optional(),
22
22
  featureId: ModelIdSchema.optional(),
23
23
  featureIds: ReferenceIdsSchema,
24
24
  entityIds: ReferenceIdsSchema,
@@ -92,16 +92,16 @@ export const DEFAULT_ORGANIZATION_MODEL_NAVIGATION: z.infer<typeof OrganizationM
92
92
  resourceIds: [],
93
93
  capabilityIds: [PROJECTS_VIEW_CAPABILITY_ID]
94
94
  },
95
- {
96
- id: OPERATIONS_COMMAND_VIEW_SURFACE_ID,
97
- label: 'Command View',
98
- path: '/operations/command-view',
99
- surfaceType: 'graph',
100
- enabled: true,
101
- devOnly: true,
102
- featureId: 'operations',
103
- featureIds: ['operations'],
104
- entityIds: [],
95
+ {
96
+ id: OPERATIONS_COMMAND_VIEW_SURFACE_ID,
97
+ label: 'Command View',
98
+ path: '/operations/command-view',
99
+ surfaceType: 'graph',
100
+ enabled: true,
101
+ devOnly: true,
102
+ featureId: 'operations',
103
+ featureIds: ['operations'],
104
+ entityIds: [],
105
105
  resourceIds: [],
106
106
  capabilityIds: ['operations.command-view']
107
107
  },
@@ -261,45 +261,45 @@ export const DEFAULT_ORGANIZATION_MODEL_NAVIGATION: z.infer<typeof OrganizationM
261
261
  resourceIds: [],
262
262
  capabilityIds: []
263
263
  },
264
- {
265
- id: 'settings.appearance',
266
- label: 'Appearance',
267
- path: '/settings/appearance',
264
+ {
265
+ id: 'settings.appearance',
266
+ label: 'Appearance',
267
+ path: '/settings/appearance',
268
+ surfaceType: 'settings',
269
+ enabled: true,
270
+ featureId: 'settings',
271
+ featureIds: ['settings'],
272
+ entityIds: [],
273
+ resourceIds: [],
274
+ capabilityIds: []
275
+ },
276
+ {
277
+ id: SETTINGS_ROLES_SURFACE_ID,
278
+ label: 'My Roles',
279
+ path: '/settings/roles',
268
280
  surfaceType: 'settings',
269
281
  enabled: true,
270
282
  featureId: 'settings',
271
283
  featureIds: ['settings'],
272
284
  entityIds: [],
273
- resourceIds: [],
274
- capabilityIds: []
275
- },
276
- {
277
- id: SETTINGS_ROLES_SURFACE_ID,
278
- label: 'My Roles',
279
- path: '/settings/roles',
280
- surfaceType: 'settings',
281
- enabled: true,
282
- featureId: 'settings',
283
- featureIds: ['settings'],
284
- entityIds: [],
285
- resourceIds: [],
286
- capabilityIds: []
287
- },
288
- {
289
- id: 'settings.organization',
290
- label: 'Organization',
291
- path: '/settings/organization',
285
+ resourceIds: [],
286
+ capabilityIds: []
287
+ },
288
+ {
289
+ id: 'settings.organization',
290
+ label: 'Organization',
291
+ path: '/settings/organization',
292
292
  surfaceType: 'settings',
293
293
  enabled: true,
294
294
  featureId: 'settings',
295
295
  featureIds: ['settings'],
296
296
  entityIds: [],
297
- resourceIds: [],
298
- capabilityIds: []
299
- },
300
- {
301
- id: 'settings.credentials',
302
- label: 'Credentials',
297
+ resourceIds: [],
298
+ capabilityIds: []
299
+ },
300
+ {
301
+ id: 'settings.credentials',
302
+ label: 'Credentials',
303
303
  path: '/settings/credentials',
304
304
  surfaceType: 'settings',
305
305
  enabled: true,
@@ -355,12 +355,12 @@ export const DEFAULT_ORGANIZATION_MODEL_NAVIGATION: z.infer<typeof OrganizationM
355
355
  },
356
356
  {
357
357
  id: 'primary-operations',
358
- label: 'Operations',
359
- placement: 'primary',
360
- surfaceIds: [
361
- OPERATIONS_COMMAND_VIEW_SURFACE_ID,
362
- 'operations.overview',
363
- 'operations.resources',
358
+ label: 'Operations',
359
+ placement: 'primary',
360
+ surfaceIds: [
361
+ OPERATIONS_COMMAND_VIEW_SURFACE_ID,
362
+ 'operations.overview',
363
+ 'operations.resources',
364
364
  'operations.command-queue',
365
365
  'operations.sessions',
366
366
  'operations.task-scheduler'
@@ -385,12 +385,12 @@ export const DEFAULT_ORGANIZATION_MODEL_NAVIGATION: z.infer<typeof OrganizationM
385
385
  label: 'Settings',
386
386
  placement: 'bottom',
387
387
  surfaceIds: [
388
- 'settings.account',
389
- 'settings.appearance',
390
- SETTINGS_ROLES_SURFACE_ID,
391
- 'settings.organization',
392
- 'settings.credentials',
393
- 'settings.api-keys',
388
+ 'settings.account',
389
+ 'settings.appearance',
390
+ SETTINGS_ROLES_SURFACE_ID,
391
+ 'settings.organization',
392
+ 'settings.credentials',
393
+ 'settings.api-keys',
394
394
  'settings.webhooks',
395
395
  'settings.deployments'
396
396
  ]
@@ -92,3 +92,275 @@ export const DEFAULT_ORGANIZATION_MODEL_SALES: z.infer<typeof OrganizationModelS
92
92
  }
93
93
  ]
94
94
  }
95
+
96
+ // ============================================================================
97
+ // Lead-Gen Stateful Pipeline Definitions (Decision N8, Wave 4)
98
+ //
99
+ // Defines the (pipeline_key, stage_key, state_key) vocabulary for the three
100
+ // entities that carry the Stateful trait via Track B:
101
+ // - acq_lists (pipeline_key='lead-gen', stage_key='lifecycle')
102
+ // - acq_list_members (pipeline_key='lead-gen', stages: outreach / prospecting / qualification)
103
+ // - acq_list_companies (pipeline_key='lead-gen', stages: outreach / prospecting / qualification)
104
+ //
105
+ // DB columns (pipeline_key, stage_key, state_key) remain free-form text with no
106
+ // CHECK constraint — new states can be introduced without a migration (Decision N8).
107
+ // These definitions are the org-specific source of truth consumed by UI and tooling.
108
+ //
109
+ // State vocabularies sourced from the post-restructure sales tree (W3 canonical):
110
+ // outreach/:
111
+ // - personalized (instantly-personalization.ts → contacts)
112
+ // - uploaded (instantly-upload.ts → contacts)
113
+ // - interested (instantly-reply-handler.ts → contacts, initial reply transition)
114
+ // prospecting/:
115
+ // - populated (apify-acquire.ts, apify-scrape.ts → companies)
116
+ // - extracted (website-extract.ts → companies)
117
+ // - discovered (email-discovery.ts, anymailfinder-enrich.ts → contacts)
118
+ // - verified (email-verification.ts → contacts)
119
+ // qualification/:
120
+ // - qualified (company-qualification.ts → companies)
121
+ //
122
+ // The 'pending' state is the W2 backfill default (coalesce(stage, 'pending')).
123
+ // It is valid in any stage and represents "not yet processed by a workflow step".
124
+ // ============================================================================
125
+
126
+ /** One state within a stage — minimal shape: key + display label. */
127
+ export interface StatefulStateDefinition {
128
+ /** Matches state_key values written by workflow steps. */
129
+ stateKey: string
130
+ label: string
131
+ }
132
+
133
+ /** One stage within a pipeline — has a stage_key and an ordered list of valid states. */
134
+ export interface StatefulStageDefinition {
135
+ /** Matches stage_key values written by workflow steps. */
136
+ stageKey: string
137
+ label: string
138
+ states: StatefulStateDefinition[]
139
+ }
140
+
141
+ /**
142
+ * Pipeline definition for a single entity participating in the Stateful trait.
143
+ * Parallel to acq_deals' pipeline_key concept but structured for lead-gen entities.
144
+ */
145
+ export interface StatefulPipelineDefinition {
146
+ /** Matches pipeline_key values in the database (e.g. 'lead-gen'). */
147
+ pipelineKey: string
148
+ label: string
149
+ /** Entity this pipeline applies to (e.g. 'acq.list', 'acq.list-member', 'acq.list-company'). */
150
+ entityKey: string
151
+ stages: StatefulStageDefinition[]
152
+ }
153
+
154
+ /**
155
+ * Find a pipeline definition by pipeline_key within an array of definitions.
156
+ * Preferred over direct array indexing since the model is array-based (not keyed).
157
+ */
158
+ export function findPipeline(
159
+ definitions: StatefulPipelineDefinition[],
160
+ pipelineKey: string
161
+ ): StatefulPipelineDefinition | undefined {
162
+ return definitions.find((def) => def.pipelineKey === pipelineKey)
163
+ }
164
+
165
+ /** Common states that appear across multiple stages. */
166
+ const PENDING_STATE: StatefulStateDefinition = { stateKey: 'pending', label: 'Pending' }
167
+
168
+ /**
169
+ * Lead-gen pipeline definition for acq_list_members (contacts).
170
+ * Three stages matching the post-restructure sales subdomain tree.
171
+ *
172
+ * Note: members visit outreach and prospecting states depending on which
173
+ * workflow last processed them. stage_key is set per-transition by the workflow.
174
+ */
175
+ export const ACQ_LIST_MEMBERS_LEAD_GEN_PIPELINE: StatefulPipelineDefinition = {
176
+ pipelineKey: 'lead-gen',
177
+ label: 'Lead Generation',
178
+ entityKey: 'acq.list-member',
179
+ stages: [
180
+ {
181
+ stageKey: 'outreach',
182
+ label: 'Outreach',
183
+ states: [
184
+ PENDING_STATE,
185
+ { stateKey: 'personalized', label: 'Personalized' },
186
+ { stateKey: 'uploaded', label: 'Uploaded' },
187
+ { stateKey: 'interested', label: 'Interested' }
188
+ ]
189
+ },
190
+ {
191
+ stageKey: 'prospecting',
192
+ label: 'Prospecting',
193
+ states: [
194
+ PENDING_STATE,
195
+ { stateKey: 'discovered', label: 'Discovered' },
196
+ { stateKey: 'verified', label: 'Verified' }
197
+ ]
198
+ },
199
+ {
200
+ stageKey: 'qualification',
201
+ label: 'Qualification',
202
+ states: [PENDING_STATE]
203
+ }
204
+ ]
205
+ }
206
+
207
+ /**
208
+ * Lead-gen pipeline definition for acq_list_companies.
209
+ * Three stages matching the post-restructure sales subdomain tree.
210
+ *
211
+ * Note: companies visit prospecting and qualification states depending on which
212
+ * workflow last processed them. stage_key is set per-transition by the workflow.
213
+ */
214
+ export const ACQ_LIST_COMPANIES_LEAD_GEN_PIPELINE: StatefulPipelineDefinition = {
215
+ pipelineKey: 'lead-gen',
216
+ label: 'Lead Generation',
217
+ entityKey: 'acq.list-company',
218
+ stages: [
219
+ {
220
+ stageKey: 'outreach',
221
+ label: 'Outreach',
222
+ states: [PENDING_STATE]
223
+ },
224
+ {
225
+ stageKey: 'prospecting',
226
+ label: 'Prospecting',
227
+ states: [
228
+ PENDING_STATE,
229
+ { stateKey: 'populated', label: 'Populated' },
230
+ { stateKey: 'extracted', label: 'Extracted' }
231
+ ]
232
+ },
233
+ {
234
+ stageKey: 'qualification',
235
+ label: 'Qualification',
236
+ states: [PENDING_STATE, { stateKey: 'qualified', label: 'Qualified' }]
237
+ }
238
+ ]
239
+ }
240
+
241
+ /**
242
+ * All lead-gen pipeline definitions indexed by entity key.
243
+ * Use findPipeline() to locate a definition by pipeline_key within any of these arrays.
244
+ */
245
+ export const LEAD_GEN_PIPELINE_DEFINITIONS: Record<string, StatefulPipelineDefinition[]> = {
246
+ 'acq.list-member': [ACQ_LIST_MEMBERS_LEAD_GEN_PIPELINE],
247
+ 'acq.list-company': [ACQ_LIST_COMPANIES_LEAD_GEN_PIPELINE]
248
+ }
249
+
250
+ // ============================================================================
251
+ // Lead-Gen Stage Catalog (Slice C — flag-based processing model)
252
+ //
253
+ // Canonical set of processing stage keys for the flag-based model that replaces
254
+ // the stateful trait on acq_list_members and acq_list_companies. Each key maps
255
+ // to a flag in the processing_state jsonb column (bare boolean per Decision #7).
256
+ //
257
+ // Sources:
258
+ // ACQ_LIST_MEMBERS_LEAD_GEN_PIPELINE → personalized, uploaded, interested,
259
+ // discovered, verified
260
+ // ACQ_LIST_COMPANIES_LEAD_GEN_PIPELINE → populated, extracted, qualified
261
+ // Design plan hint (lead-gen-domain-cleanup.mdx §4) → scraped, enriched
262
+ //
263
+ // Wave 2 will validate pipeline_config.stages[].key against this catalog at
264
+ // list-create/update time. Each lead-gen workflow in operations will declare
265
+ // stageImplemented: '<key>' in its WorkflowDefinition (Slice D-2).
266
+ // ============================================================================
267
+
268
+ /** One entry in the lead-gen stage catalog. */
269
+ export interface LeadGenStageCatalogEntry {
270
+ /** Matches the flag key written into processing_state jsonb (e.g. 'scraped'). */
271
+ key: string
272
+ /** Human-readable label for UI display. */
273
+ label: string
274
+ /** Short description of what this stage represents. */
275
+ description: string
276
+ /** Canonical pipeline order for UI sorting. Lower = earlier in the funnel. */
277
+ order: number
278
+ /** Which entity's processing_state jsonb carries this flag. */
279
+ entity: 'company' | 'contact'
280
+ }
281
+
282
+ /**
283
+ * Canonical lead-gen processing stage catalog.
284
+ * Keys are the flag names written by workflow steps into processing_state jsonb.
285
+ *
286
+ * Ordered roughly by pipeline progression (prospecting → outreach → qualification).
287
+ */
288
+ export const LEAD_GEN_STAGE_CATALOG: Record<string, LeadGenStageCatalogEntry> = {
289
+ // Prospecting — company population
290
+ scraped: {
291
+ key: 'scraped',
292
+ label: 'Scraped',
293
+ description: 'Company was scraped from a source directory (Apify actor run).',
294
+ order: 1,
295
+ entity: 'company'
296
+ },
297
+ populated: {
298
+ key: 'populated',
299
+ label: 'Populated',
300
+ description: 'Company record populated with structured data from scrape results.',
301
+ order: 2,
302
+ entity: 'company'
303
+ },
304
+ extracted: {
305
+ key: 'extracted',
306
+ label: 'Extracted',
307
+ description: 'Website content extracted and parsed for company intelligence.',
308
+ order: 3,
309
+ entity: 'company'
310
+ },
311
+ enriched: {
312
+ key: 'enriched',
313
+ label: 'Enriched',
314
+ description: 'Company or contact enriched with third-party data (e.g. Tomba, Anymailfinder).',
315
+ order: 4,
316
+ entity: 'company'
317
+ },
318
+
319
+ // Prospecting — contact discovery
320
+ discovered: {
321
+ key: 'discovered',
322
+ label: 'Discovered',
323
+ description: 'Contact email address discovered via an email-discovery workflow.',
324
+ order: 5,
325
+ entity: 'contact'
326
+ },
327
+ verified: {
328
+ key: 'verified',
329
+ label: 'Verified',
330
+ description: 'Contact email address verified as deliverable (email verification workflow).',
331
+ order: 6,
332
+ entity: 'contact'
333
+ },
334
+
335
+ // Qualification
336
+ qualified: {
337
+ key: 'qualified',
338
+ label: 'Qualified',
339
+ description: 'Company passed the ICP qualification rubric (company-qualification workflow).',
340
+ order: 7,
341
+ entity: 'company'
342
+ },
343
+
344
+ // Outreach
345
+ personalized: {
346
+ key: 'personalized',
347
+ label: 'Personalized',
348
+ description: 'Outreach message personalized for the contact (Instantly personalization workflow).',
349
+ order: 8,
350
+ entity: 'contact'
351
+ },
352
+ uploaded: {
353
+ key: 'uploaded',
354
+ label: 'Uploaded',
355
+ description: 'Contact uploaded to an Instantly campaign for outreach.',
356
+ order: 9,
357
+ entity: 'contact'
358
+ },
359
+ interested: {
360
+ key: 'interested',
361
+ label: 'Interested',
362
+ description: 'Contact replied with a positive signal (Instantly reply-handler transition).',
363
+ order: 10,
364
+ entity: 'contact'
365
+ }
366
+ }
@@ -25,10 +25,10 @@ Node kinds:
25
25
 
26
26
  - `organization`
27
27
  - `feature`
28
+ - `surface`
28
29
  - `entity`
29
30
  - `capability`
30
31
  - `resource`
31
- - `integration`
32
32
 
33
33
  Edge kinds:
34
34
 
@@ -62,7 +62,7 @@ interface BuildOrganizationGraphInput {
62
62
  `buildOrganizationGraph`:
63
63
 
64
64
  1. Reads flat Organization Model features and derives `feature:*` nodes.
65
- 2. Reads entities, capabilities, integrations, and resources.
65
+ 2. Reads Command View resources, including integration resources, as `resource` nodes with `resourceType` metadata.
66
66
  3. Emits authored graph links from resource/entity/capability metadata.
67
67
  4. Bridges Command View runtime topology into resource nodes and relationship edges.
68
68
  5. Returns a renderer-agnostic DTO.
@@ -1,6 +1,6 @@
1
1
  export { OrganizationModelSchema } from './schema'
2
- export { FeatureSchema, NodeIdPathSchema, NodeIdStringSchema, UiPositionSchema } from './domains/features'
3
- export { LinkSchema } from './graph/link'
2
+ export { FeatureSchema, NodeIdPathSchema, NodeIdStringSchema, UiPositionSchema } from './domains/features'
3
+ export { LinkSchema } from './graph/link'
4
4
  export { TechStackEntrySchema } from './domains/shared'
5
5
  export {
6
6
  PROJECTS_FEATURE_ID,
@@ -11,12 +11,12 @@ export {
11
11
  OPERATIONS_FEATURE_ID,
12
12
  MONITORING_FEATURE_ID,
13
13
  SETTINGS_FEATURE_ID,
14
- SEO_FEATURE_ID,
15
- SALES_PIPELINE_SURFACE_ID,
16
- PROSPECTING_LISTS_SURFACE_ID,
17
- OPERATIONS_COMMAND_VIEW_SURFACE_ID,
18
- SETTINGS_ROLES_SURFACE_ID
19
- } from './contracts'
14
+ SEO_FEATURE_ID,
15
+ SALES_PIPELINE_SURFACE_ID,
16
+ PROSPECTING_LISTS_SURFACE_ID,
17
+ OPERATIONS_COMMAND_VIEW_SURFACE_ID,
18
+ SETTINGS_ROLES_SURFACE_ID
19
+ } from './contracts'
20
20
  export { DEFAULT_ORGANIZATION_MODEL } from './defaults'
21
21
  export {
22
22
  DEFAULT_ORGANIZATION_MODEL_STATUSES,
@@ -57,25 +57,25 @@ export type {
57
57
  OrganizationModelCustomerFirmographics,
58
58
  OrganizationModelCustomers,
59
59
  OrganizationModelCustomerSegment,
60
- OrganizationModelFeature,
61
- OrganizationModelGoals,
62
- OrganizationModelKeyResult,
63
- OrganizationModelObjective,
60
+ OrganizationModelFeature,
61
+ OrganizationModelGoals,
62
+ OrganizationModelKeyResult,
63
+ OrganizationModelObjective,
64
64
  OrganizationModelOfferings,
65
65
  OrganizationModelOperationEntry,
66
66
  OrganizationModelOperationSemanticClass,
67
67
  OrganizationModelOperations,
68
- OrganizationModelPricingModel,
69
- OrganizationModelProduct,
70
- OrganizationModelRole,
68
+ OrganizationModelPricingModel,
69
+ OrganizationModelProduct,
70
+ OrganizationModelRole,
71
71
  OrganizationModelTechStackEntry,
72
72
  OrganizationModelRoles,
73
- OrganizationModelStatuses,
74
- OrganizationModelStatusEntry,
75
- OrganizationModelStatusSemanticClass,
76
- NodeIdPath,
77
- NodeIdString
78
- } from './types'
73
+ OrganizationModelStatuses,
74
+ OrganizationModelStatusEntry,
75
+ OrganizationModelStatusSemanticClass,
76
+ NodeIdPath,
77
+ NodeIdString
78
+ } from './types'
79
79
 
80
80
  export type {
81
81
  FoundationBranding,