@elevasis/core 0.21.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/dist/index.d.ts +2518 -2169
  2. package/dist/index.js +2495 -1095
  3. package/dist/knowledge/index.d.ts +706 -1044
  4. package/dist/knowledge/index.js +9 -9
  5. package/dist/organization-model/index.d.ts +2518 -2169
  6. package/dist/organization-model/index.js +2495 -1095
  7. package/dist/test-utils/index.d.ts +826 -1014
  8. package/dist/test-utils/index.js +1894 -1032
  9. package/package.json +3 -3
  10. package/src/__tests__/template-core-compatibility.test.ts +11 -79
  11. package/src/_gen/__tests__/__snapshots__/contracts.md.snap +852 -397
  12. package/src/auth/multi-tenancy/permissions.ts +20 -8
  13. package/src/business/README.md +2 -2
  14. package/src/business/acquisition/api-schemas.test.ts +175 -2
  15. package/src/business/acquisition/api-schemas.ts +132 -16
  16. package/src/business/acquisition/build-templates.test.ts +4 -4
  17. package/src/business/acquisition/build-templates.ts +72 -30
  18. package/src/business/acquisition/crm-state-actions.test.ts +13 -11
  19. package/src/business/acquisition/index.ts +12 -0
  20. package/src/business/acquisition/types.ts +7 -3
  21. package/src/business/clients/api-schemas.test.ts +115 -0
  22. package/src/business/clients/api-schemas.ts +158 -0
  23. package/src/business/clients/index.ts +1 -0
  24. package/src/business/deals/api-schemas.ts +8 -0
  25. package/src/business/index.ts +5 -2
  26. package/src/business/projects/types.ts +19 -0
  27. package/src/execution/engine/__tests__/fixtures/test-agents.ts +10 -8
  28. package/src/execution/engine/agent/core/__tests__/agent.test.ts +16 -12
  29. package/src/execution/engine/agent/core/__tests__/error-passthrough.test.ts +4 -3
  30. package/src/execution/engine/agent/core/types.ts +25 -15
  31. package/src/execution/engine/agent/index.ts +6 -4
  32. package/src/execution/engine/agent/reasoning/__tests__/request-builder.test.ts +24 -18
  33. package/src/execution/engine/index.ts +3 -0
  34. package/src/execution/engine/workflow/types.ts +9 -2
  35. package/src/knowledge/README.md +8 -7
  36. package/src/knowledge/__tests__/queries.test.ts +74 -73
  37. package/src/knowledge/format.ts +10 -9
  38. package/src/knowledge/index.ts +1 -1
  39. package/src/knowledge/published.ts +1 -1
  40. package/src/knowledge/queries.ts +26 -25
  41. package/src/organization-model/README.md +73 -26
  42. package/src/organization-model/__tests__/content-kinds-registry.test.ts +210 -0
  43. package/src/organization-model/__tests__/defaults.test.ts +76 -96
  44. package/src/organization-model/__tests__/domains/actions.test.ts +56 -0
  45. package/src/organization-model/__tests__/domains/customers.test.ts +299 -295
  46. package/src/organization-model/__tests__/domains/entities.test.ts +56 -0
  47. package/src/organization-model/__tests__/domains/goals.test.ts +493 -479
  48. package/src/organization-model/__tests__/domains/identity.test.ts +280 -279
  49. package/src/organization-model/__tests__/domains/navigation.test.ts +268 -212
  50. package/src/organization-model/__tests__/domains/offerings.test.ts +414 -419
  51. package/src/organization-model/__tests__/domains/policies.test.ts +323 -0
  52. package/src/organization-model/__tests__/domains/resource-mappings.test.ts +271 -271
  53. package/src/organization-model/__tests__/domains/resources.test.ts +310 -0
  54. package/src/organization-model/__tests__/domains/roles.test.ts +463 -347
  55. package/src/organization-model/__tests__/domains/statuses.test.ts +246 -243
  56. package/src/organization-model/__tests__/domains/systems.test.ts +209 -0
  57. package/src/organization-model/__tests__/flatten-additive-merge.test.ts +361 -0
  58. package/src/organization-model/__tests__/foundation.test.ts +74 -102
  59. package/src/organization-model/__tests__/get-resources-for-system.test.ts +144 -0
  60. package/src/organization-model/__tests__/graph.test.ts +899 -71
  61. package/src/organization-model/__tests__/knowledge.test.ts +209 -49
  62. package/src/organization-model/__tests__/lookup-helpers.test.ts +438 -0
  63. package/src/organization-model/__tests__/migration-helpers.test.ts +591 -0
  64. package/src/organization-model/__tests__/prospecting-ssot.test.ts +36 -27
  65. package/src/organization-model/__tests__/recursive-system-schema.test.ts +520 -0
  66. package/src/organization-model/__tests__/resolve.test.ts +174 -23
  67. package/src/organization-model/__tests__/schema.test.ts +291 -114
  68. package/src/organization-model/__tests__/surface-projection.test.ts +207 -97
  69. package/src/organization-model/catalogs/lead-gen.ts +144 -0
  70. package/src/organization-model/content-kinds/config.ts +36 -0
  71. package/src/organization-model/content-kinds/index.ts +74 -0
  72. package/src/organization-model/content-kinds/pipeline.ts +68 -0
  73. package/src/organization-model/content-kinds/registry.ts +44 -0
  74. package/src/organization-model/content-kinds/status.ts +71 -0
  75. package/src/organization-model/content-kinds/template.ts +83 -0
  76. package/src/organization-model/content-kinds/types.ts +117 -0
  77. package/src/organization-model/contracts.ts +13 -3
  78. package/src/organization-model/defaults.ts +499 -86
  79. package/src/organization-model/domains/actions.ts +239 -0
  80. package/src/organization-model/domains/customers.ts +78 -75
  81. package/src/organization-model/domains/entities.ts +144 -0
  82. package/src/organization-model/domains/goals.ts +83 -80
  83. package/src/organization-model/domains/knowledge.ts +76 -17
  84. package/src/organization-model/domains/navigation.ts +107 -384
  85. package/src/organization-model/domains/offerings.ts +71 -66
  86. package/src/organization-model/domains/policies.ts +102 -0
  87. package/src/organization-model/domains/projects.ts +14 -48
  88. package/src/organization-model/domains/prospecting.ts +62 -181
  89. package/src/organization-model/domains/resources.ts +145 -0
  90. package/src/organization-model/domains/roles.ts +96 -55
  91. package/src/organization-model/domains/sales.ts +10 -219
  92. package/src/organization-model/domains/shared.ts +57 -57
  93. package/src/organization-model/domains/statuses.ts +339 -130
  94. package/src/organization-model/domains/systems.ts +203 -0
  95. package/src/organization-model/foundation.ts +54 -67
  96. package/src/organization-model/graph/build.ts +682 -54
  97. package/src/organization-model/graph/link.ts +1 -1
  98. package/src/organization-model/graph/schema.ts +24 -9
  99. package/src/organization-model/graph/types.ts +20 -7
  100. package/src/organization-model/helpers.ts +231 -26
  101. package/src/organization-model/icons.ts +1 -0
  102. package/src/organization-model/index.ts +118 -5
  103. package/src/organization-model/migration-helpers.ts +249 -0
  104. package/src/organization-model/organization-graph.mdx +16 -15
  105. package/src/organization-model/organization-model.mdx +111 -44
  106. package/src/organization-model/published.ts +172 -19
  107. package/src/organization-model/resolve.ts +117 -54
  108. package/src/organization-model/schema.ts +654 -112
  109. package/src/organization-model/surface-projection.ts +116 -122
  110. package/src/organization-model/types.ts +146 -20
  111. package/src/platform/api/types.ts +38 -35
  112. package/src/platform/constants/versions.ts +1 -1
  113. package/src/platform/registry/__tests__/command-view.test.ts +6 -8
  114. package/src/platform/registry/__tests__/resource-link.test.ts +13 -8
  115. package/src/platform/registry/__tests__/resource-registry.integration.test.ts +16 -31
  116. package/src/platform/registry/__tests__/resource-registry.nested-systems.test.ts +245 -0
  117. package/src/platform/registry/__tests__/resource-registry.test.ts +2053 -2005
  118. package/src/platform/registry/__tests__/validation.test.ts +1347 -1086
  119. package/src/platform/registry/index.ts +14 -0
  120. package/src/platform/registry/resource-registry.ts +52 -2
  121. package/src/platform/registry/serialization.ts +241 -202
  122. package/src/platform/registry/serialized-types.ts +1 -0
  123. package/src/platform/registry/types.ts +411 -361
  124. package/src/platform/registry/validation.ts +745 -513
  125. package/src/projects/api-schemas.ts +290 -267
  126. package/src/reference/_generated/contracts.md +853 -397
  127. package/src/reference/glossary.md +23 -18
  128. package/src/supabase/database.types.ts +181 -0
  129. package/src/test-utils/test-utils.test.ts +1 -6
  130. package/src/organization-model/__tests__/domains/operations.test.ts +0 -203
  131. package/src/organization-model/domains/features.ts +0 -31
  132. package/src/organization-model/domains/operations.ts +0 -85
@@ -6,13 +6,18 @@
6
6
  * - API middleware (via requireOrganizationPermission(key))
7
7
  * - UI hooks (via useOrganizationPermissions().hasPermission(key))
8
8
  *
9
- * The DB table `org_rol_permissions` mirrors this constant. Reconciliation
10
- * runs at API boot (insert-or-update only — never auto-delete; see the
11
- * deletion runbook in the auth-role-system doc -- review/auth-role-system/).
9
+ * The DB table `org_rol_permissions` mirrors this constant. There is no
10
+ * runtime reconciler; parity is enforced two ways:
11
+ * 1. Each migration that adds/removes/modifies a permission must INSERT
12
+ * (or UPDATE / DELETE) the corresponding `org_rol_permissions` row in
13
+ * the same transaction.
14
+ * 2. `apps/api/src/auth/multi-tenancy/__tests__/permissions-catalog-sync.integration.test.ts`
15
+ * asserts the TS catalog and the DB rows agree; CI fails on drift.
12
16
  *
13
17
  * Adding a permission:
14
18
  * 1. Add an entry below.
15
- * 2. Add a row to the migration / via reconcilePermissionCatalog at boot.
19
+ * 2. Add a row to the migration (INSERT INTO org_rol_permissions ...) in
20
+ * the same transaction as any policies/grants that reference the key.
16
21
  * 3. Reference it in RLS / middleware as needed.
17
22
  * 4. Optionally grant it to one or more system roles in org_rol_grants.
18
23
  *
@@ -30,15 +35,17 @@ export const PERMISSIONS = {
30
35
  OPERATIONS_READ: 'operations.read',
31
36
  OPERATIONS_MANAGE: 'operations.manage',
32
37
  ACQUISITION_MANAGE: 'acquisition.manage',
33
- PROJECTS_MANAGE: 'projects.manage'
38
+ PROJECTS_MANAGE: 'projects.manage',
39
+ CLIENTS_MANAGE: 'clients.manage'
34
40
  } as const
35
41
 
36
42
  export type PermissionKey = (typeof PERMISSIONS)[keyof typeof PERMISSIONS]
37
43
 
38
44
  /**
39
- * Static metadata for each permission. Mirrored into org_rol_permissions on
40
- * boot reconciliation. is_org_grantable=false means the permission is reserved
41
- * to system roles only custom roles cannot include it (privilege-escalation guard).
45
+ * Static metadata for each permission. Mirrored into org_rol_permissions by
46
+ * a migration `INSERT` in the same transaction as any change to this catalog.
47
+ * is_org_grantable=false means the permission is reserved to system roles
48
+ * only — custom roles cannot include it (privilege-escalation guard).
42
49
  */
43
50
  export interface PermissionDescriptor {
44
51
  key: PermissionKey
@@ -97,6 +104,11 @@ export const PERMISSION_CATALOG: readonly PermissionDescriptor[] = [
97
104
  key: 'projects.manage',
98
105
  description: 'Create, update, and delete project records (prj_projects, prj_milestones, prj_tasks, prj_notes)',
99
106
  isOrgGrantable: false
107
+ },
108
+ {
109
+ key: 'clients.manage',
110
+ description: 'Create, update, and delete client hub records (clients, clt_* satellites)',
111
+ isOrgGrantable: false
100
112
  }
101
113
  ] as const
102
114
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Published base entity contracts for the Elevasis platform. Each entity ships as a TypeScript interface, a matching Zod schema, and an inferred `Input` type, generic over a `<TMeta>` extension slot.
4
4
 
5
- External projects extend these in `foundations/types/entities.ts` to attach project-specific metadata while keeping the canonical shape stable.
5
+ External projects extend these in `core/types/entities.ts` to attach project-specific metadata while keeping the canonical shape stable.
6
6
 
7
7
  ## Published Exports
8
8
 
@@ -49,4 +49,4 @@ export type Deal = BaseDeal
49
49
 
50
50
  The full pattern is documented in the SDK scaffold bundle: `node_modules/@elevasis/sdk/reference/scaffold/recipes/extend-a-base-entity.md`.
51
51
 
52
- The canonical template demo lives at `external/_template/foundations/types/entities.ts`.
52
+ The canonical template demo lives at `external/_template/core/types/entities.ts`.
@@ -10,10 +10,12 @@ import {
10
10
  AddCompaniesToListRequestSchema,
11
11
  AddContactsToListRequestSchema,
12
12
  AcqArtifactOwnerKindSchema,
13
+ AcqListDetailResponseSchema,
13
14
  AcqContactResponseSchema,
14
15
  AcqContactStatusSchema,
15
16
  AcqEmailValidSchema,
16
17
  AcqListResponseSchema,
18
+ AcqListStatusResponseSchema,
17
19
  BuildPlanSnapshotSchema,
18
20
  CreateArtifactRequestSchema,
19
21
  CreateCompanyRequestSchema,
@@ -32,12 +34,14 @@ import {
32
34
  DealTaskResponseSchema,
33
35
  ExecuteActionRequestSchema,
34
36
  IcpRubricSchema,
37
+ GetListQuerySchema,
35
38
  ListArtifactsQuerySchema,
36
39
  ListCompaniesQuerySchema,
37
40
  ListContactsQuerySchema,
38
41
  ListDealsQuerySchema,
39
42
  ListDealTasksDueQuerySchema,
40
43
  ListMembersQuerySchema,
44
+ ListReadQuerySchema,
41
45
  ListRecordsQuerySchema,
42
46
  ListStatusSchema,
43
47
  PipelineStageSchema,
@@ -857,6 +861,24 @@ describe('DealDetailResponseSchema (forward-compat)', () => {
857
861
  expect(DealDetailResponseSchema.safeParse(withContact).success).toBe(true)
858
862
  })
859
863
 
864
+ it('accepts thin client lineage refs on deal detail responses', () => {
865
+ expect(
866
+ DealDetailResponseSchema.safeParse({
867
+ ...baseDeal,
868
+ client_id: VALID_UUID,
869
+ lineage: {
870
+ list: null,
871
+ projects: [],
872
+ client: {
873
+ id: VALID_UUID,
874
+ name: 'Acme Client',
875
+ status: 'active'
876
+ }
877
+ }
878
+ }).success
879
+ ).toBe(true)
880
+ })
881
+
860
882
  it('accepts extra unknown fields at top level (not strict)', () => {
861
883
  expect(DealDetailResponseSchema.safeParse({ ...baseDeal, futureField: 'value' }).success).toBe(true)
862
884
  })
@@ -1008,10 +1030,10 @@ describe('BuildPlanSnapshotSchema', () => {
1008
1030
  expect(result.success).toBe(false)
1009
1031
  })
1010
1032
 
1011
- it('rejects a step capabilityKey outside CAPABILITY_REGISTRY', () => {
1033
+ it('rejects a step actionKey outside ACTION_REGISTRY', () => {
1012
1034
  const result = BuildPlanSnapshotSchema.safeParse({
1013
1035
  ...validSnapshot,
1014
- steps: [{ ...validSnapshot!.steps[0], capabilityKey: 'lead-gen.missing.capability' }]
1036
+ steps: [{ ...validSnapshot!.steps[0], actionKey: 'lead-gen.missing.action' }]
1015
1037
  })
1016
1038
 
1017
1039
  expect(result.success).toBe(false)
@@ -1602,6 +1624,67 @@ describe('ListMembersQuerySchema', () => {
1602
1624
  })
1603
1625
  })
1604
1626
 
1627
+ // ---------------------------------------------------------------------------
1628
+ // ListReadQuerySchema
1629
+ // ---------------------------------------------------------------------------
1630
+
1631
+ describe('ListReadQuerySchema', () => {
1632
+ it('accepts SDK list filters and coerces pagination', () => {
1633
+ const result = ListReadQuerySchema.safeParse({
1634
+ status: 'launched',
1635
+ batch: 'batch-2026-05',
1636
+ vertical: 'veterinary',
1637
+ limit: '25',
1638
+ offset: '50'
1639
+ })
1640
+
1641
+ expect(result.success).toBe(true)
1642
+ if (result.success) {
1643
+ expect(result.data).toMatchObject({ limit: 25, offset: 50 })
1644
+ }
1645
+ })
1646
+
1647
+ it('keeps pagination optional for backward-compatible list reads', () => {
1648
+ expect(ListReadQuerySchema.safeParse({}).success).toBe(true)
1649
+ })
1650
+
1651
+ it('rejects unknown fields (strict mode)', () => {
1652
+ expect(ListReadQuerySchema.safeParse({ includeDeals: true }).success).toBe(false)
1653
+ })
1654
+ })
1655
+
1656
+ // ---------------------------------------------------------------------------
1657
+ // GetListQuerySchema
1658
+ // ---------------------------------------------------------------------------
1659
+
1660
+ describe('GetListQuerySchema', () => {
1661
+ it('defaults to thin deal refs and omits progress unless requested', () => {
1662
+ const result = GetListQuerySchema.safeParse({})
1663
+
1664
+ expect(result.success).toBe(true)
1665
+ if (result.success) {
1666
+ expect(result.data).toEqual({ includeDeals: true, includeProgress: false, dealLimit: 25 })
1667
+ }
1668
+ })
1669
+
1670
+ it('coerces boolean include flags from query strings', () => {
1671
+ const result = GetListQuerySchema.safeParse({
1672
+ includeDeals: 'false',
1673
+ includeProgress: 'true',
1674
+ dealLimit: '10'
1675
+ })
1676
+
1677
+ expect(result.success).toBe(true)
1678
+ if (result.success) {
1679
+ expect(result.data).toEqual({ includeDeals: false, includeProgress: true, dealLimit: 10 })
1680
+ }
1681
+ })
1682
+
1683
+ it('rejects unknown fields (strict mode)', () => {
1684
+ expect(GetListQuerySchema.safeParse({ depth: 2 }).success).toBe(false)
1685
+ })
1686
+ })
1687
+
1605
1688
  // ---------------------------------------------------------------------------
1606
1689
  // ListRecordsQuerySchema
1607
1690
  // ---------------------------------------------------------------------------
@@ -1657,6 +1740,96 @@ describe('AcqListResponseSchema (forward-compat)', () => {
1657
1740
  })
1658
1741
  })
1659
1742
 
1743
+ // ---------------------------------------------------------------------------
1744
+ // AcqListDetailResponseSchema
1745
+ // ---------------------------------------------------------------------------
1746
+
1747
+ describe('AcqListDetailResponseSchema', () => {
1748
+ const baseList = {
1749
+ id: VALID_UUID,
1750
+ organizationId: VALID_UUID,
1751
+ name: 'Test List',
1752
+ description: null,
1753
+ batchIds: [],
1754
+ instantlyCampaignId: null,
1755
+ status: 'draft' as const,
1756
+ metadata: {},
1757
+ launchedAt: null,
1758
+ completedAt: null,
1759
+ createdAt: ISO_TS,
1760
+ scrapingConfig: {},
1761
+ icp: {},
1762
+ pipelineConfig: {}
1763
+ }
1764
+
1765
+ it('accepts thin lineage deal refs on list detail responses', () => {
1766
+ expect(
1767
+ AcqListDetailResponseSchema.safeParse({
1768
+ ...baseList,
1769
+ lineage: {
1770
+ deals: {
1771
+ total: 1,
1772
+ refs: [
1773
+ {
1774
+ id: VALID_UUID,
1775
+ contactEmail: 'lead@example.com',
1776
+ stageKey: 'proposal',
1777
+ stateKey: null,
1778
+ sourceType: 'outreach',
1779
+ lastActivityAt: ISO_TS
1780
+ }
1781
+ ],
1782
+ truncated: false
1783
+ }
1784
+ }
1785
+ }).success
1786
+ ).toBe(true)
1787
+ })
1788
+
1789
+ it('accepts optional progress on list detail responses', () => {
1790
+ expect(
1791
+ AcqListDetailResponseSchema.safeParse({
1792
+ ...baseList,
1793
+ progress: {
1794
+ totalMembers: 0,
1795
+ totalCompanies: 0,
1796
+ byCompanyStage: {},
1797
+ byContactStage: {}
1798
+ }
1799
+ }).success
1800
+ ).toBe(true)
1801
+ })
1802
+ })
1803
+
1804
+ // ---------------------------------------------------------------------------
1805
+ // AcqListStatusResponseSchema
1806
+ // ---------------------------------------------------------------------------
1807
+
1808
+ describe('AcqListStatusResponseSchema', () => {
1809
+ it('accepts a portfolio summary across acquisition lists', () => {
1810
+ expect(
1811
+ AcqListStatusResponseSchema.safeParse({
1812
+ totalLists: 1,
1813
+ totalCompanies: 10,
1814
+ totalContacts: 5,
1815
+ totalDeals: 2,
1816
+ byStatus: { launched: 1 },
1817
+ lists: [
1818
+ {
1819
+ listId: VALID_UUID,
1820
+ name: 'Pipeline',
1821
+ status: 'launched',
1822
+ totalCompanies: 10,
1823
+ totalContacts: 5,
1824
+ totalDeals: 2,
1825
+ createdAt: ISO_TS
1826
+ }
1827
+ ]
1828
+ }).success
1829
+ ).toBe(true)
1830
+ })
1831
+ })
1832
+
1660
1833
  // ---------------------------------------------------------------------------
1661
1834
  // AcqContactResponseSchema (forward-compat)
1662
1835
  // ---------------------------------------------------------------------------
@@ -2,7 +2,7 @@ import { z } from 'zod'
2
2
  import { UuidSchema, NonEmptyStringSchema } from '../../platform/utils/validation'
3
3
  import { CRM_PIPELINE_DEFINITION, LEAD_GEN_STAGE_CATALOG } from '../../organization-model/domains/sales'
4
4
  import {
5
- CAPABILITY_REGISTRY,
5
+ ACTION_REGISTRY,
6
6
  CredentialRequirementSchema,
7
7
  RecordColumnConfigSchema
8
8
  } from '../../organization-model/domains/prospecting'
@@ -18,11 +18,9 @@ export const LeadGenStageKeySchema = z
18
18
  message: 'processing state key must match LEAD_GEN_STAGE_CATALOG'
19
19
  })
20
20
 
21
- export const LeadGenCapabilityKeySchema = z
22
- .string()
23
- .refine((value) => CAPABILITY_REGISTRY.some((c) => c.id === value), {
24
- message: 'capabilityKey must match CAPABILITY_REGISTRY'
25
- })
21
+ export const LeadGenActionKeySchema = z.string().refine((value) => ACTION_REGISTRY.some((c) => c.id === value), {
22
+ message: 'actionKey must match ACTION_REGISTRY'
23
+ })
26
24
 
27
25
  const crmStageKeys = CRM_PIPELINE_DEFINITION.stages.map((stage) => stage.stageKey) as [string, ...string[]]
28
26
  const crmStateKeys = CRM_PIPELINE_DEFINITION.stages.flatMap((stage) => stage.states.map((state) => state.stateKey)) as [
@@ -84,6 +82,9 @@ export const DealTaskIdParamsSchema = z.object({
84
82
  export const ListDealsQuerySchema = z
85
83
  .object({
86
84
  stage: DealStageSchema.optional(),
85
+ list: UuidSchema.optional(),
86
+ batch: z.string().trim().min(1).max(255).optional(),
87
+ staleSince: z.string().datetime().optional(),
87
88
  search: z.string().optional(),
88
89
  limit: z.coerce.number().int().positive().default(50),
89
90
  offset: z.coerce.number().int().min(0).default(0)
@@ -215,6 +216,7 @@ export const DealListItemSchema = z.object({
215
216
  // acq_deals columns
216
217
  id: z.string(),
217
218
  organization_id: z.string(),
219
+ client_id: z.string().nullable().optional(),
218
220
  contact_id: z.string().nullable(),
219
221
  contact_email: z.string(),
220
222
  pipeline_key: z.string(),
@@ -304,12 +306,39 @@ export const DealConversationSchema = z.object({
304
306
  messages: z.array(ConversationMessageSchema)
305
307
  })
306
308
 
309
+ export const DealLineageListRefSchema = z.object({
310
+ id: z.string(),
311
+ name: z.string(),
312
+ status: z.string()
313
+ })
314
+
315
+ export const DealLineageProjectRefSchema = z.object({
316
+ id: z.string(),
317
+ name: z.string(),
318
+ kind: z.string(),
319
+ status: z.string(),
320
+ updatedAt: z.string()
321
+ })
322
+
323
+ export const DealLineageClientRefSchema = z.object({
324
+ id: z.string(),
325
+ name: z.string(),
326
+ status: z.string()
327
+ })
328
+
329
+ export const DealLineageSchema = z.object({
330
+ list: DealLineageListRefSchema.nullable(),
331
+ projects: z.array(DealLineageProjectRefSchema),
332
+ client: DealLineageClientRefSchema.nullable()
333
+ })
334
+
307
335
  /**
308
336
  * Deal detail shape — currently the same as a list item (full joined record).
309
337
  * Additive fields keep existing DealListItem callers compatible.
310
338
  */
311
339
  export const DealDetailResponseSchema = DealListItemSchema.extend({
312
- conversation: DealConversationSchema
340
+ conversation: DealConversationSchema,
341
+ lineage: DealLineageSchema.optional()
313
342
  })
314
343
 
315
344
  /**
@@ -382,6 +411,10 @@ export const DealSchemas = {
382
411
  DealSummaryResponse: DealSummaryResponseSchema,
383
412
  DealLookupResponse: DealLookupResponseSchema,
384
413
  ConversationMessage: ConversationMessageSchema,
414
+ DealLineageListRef: DealLineageListRefSchema,
415
+ DealLineageProjectRef: DealLineageProjectRefSchema,
416
+ DealLineageClientRef: DealLineageClientRefSchema,
417
+ DealLineage: DealLineageSchema,
385
418
  DealDetailResponse: DealDetailResponseSchema,
386
419
  DealNoteResponse: DealNoteResponseSchema,
387
420
  DealNoteListResponse: DealNoteListResponseSchema,
@@ -415,6 +448,10 @@ export type DealSummaryResponse = z.infer<typeof DealSummaryResponseSchema>
415
448
  export type DealLookupItem = z.infer<typeof DealLookupItemSchema>
416
449
  export type DealLookupResponse = z.infer<typeof DealLookupResponseSchema>
417
450
  export type ConversationMessage = z.infer<typeof ConversationMessageSchema>
451
+ export type DealLineageListRef = z.infer<typeof DealLineageListRefSchema>
452
+ export type DealLineageProjectRef = z.infer<typeof DealLineageProjectRefSchema>
453
+ export type DealLineageClientRef = z.infer<typeof DealLineageClientRefSchema>
454
+ export type DealLineage = z.infer<typeof DealLineageSchema>
418
455
  export type DealDetailResponse = z.infer<typeof DealDetailResponseSchema>
419
456
  export type DealNoteResponse = z.infer<typeof DealNoteResponseSchema>
420
457
  export type DealNoteListResponse = z.infer<typeof DealNoteListResponseSchema>
@@ -505,7 +542,7 @@ export const BuildPlanSnapshotStepSchema = z
505
542
  recordSourceStageKey: LeadGenStageKeySchema.optional(),
506
543
  dependsOn: z.array(z.string().trim().min(1).max(100)).optional(),
507
544
  dependencyMode: z.literal('per-record-eligibility'),
508
- capabilityKey: LeadGenCapabilityKeySchema,
545
+ actionKey: LeadGenActionKeySchema,
509
546
  defaultBatchSize: z.number().int().positive(),
510
547
  maxBatchSize: z.number().int().positive(),
511
548
  recordColumns: z
@@ -732,6 +769,30 @@ export const ListTelemetryResponseSchema = ListTelemetrySchema
732
769
 
733
770
  export const ListTelemetryListResponseSchema = z.array(ListTelemetrySchema)
734
771
 
772
+ const QueryBooleanSchema = z.preprocess((value) => {
773
+ if (value === 'true' || value === '1' || value === true) return true
774
+ if (value === 'false' || value === '0' || value === false) return false
775
+ return value
776
+ }, z.boolean())
777
+
778
+ export const ListReadQuerySchema = z
779
+ .object({
780
+ status: ListStatusSchema.optional(),
781
+ batch: z.string().trim().min(1).max(255).optional(),
782
+ vertical: z.string().trim().min(1).max(255).optional(),
783
+ limit: z.coerce.number().int().min(1).max(500).optional(),
784
+ offset: z.coerce.number().int().min(0).optional()
785
+ })
786
+ .strict()
787
+
788
+ export const GetListQuerySchema = z
789
+ .object({
790
+ includeDeals: QueryBooleanSchema.default(true),
791
+ includeProgress: QueryBooleanSchema.default(false),
792
+ dealLimit: z.coerce.number().int().min(0).max(100).default(25)
793
+ })
794
+ .strict()
795
+
735
796
  /**
736
797
  * Per-stage progress aggregate for a single pipeline stage.
737
798
  * `attempted` counts terminal statuses, including success, no-result, skipped,
@@ -761,6 +822,47 @@ export const ListProgressResponseSchema = z.object({
761
822
  byContactStage: z.record(z.string(), ListStageProgressSchema)
762
823
  })
763
824
 
825
+ export const AcqListDealRefSchema = z.object({
826
+ id: z.string(),
827
+ contactEmail: z.string(),
828
+ stageKey: z.string().nullable(),
829
+ stateKey: z.string().nullable(),
830
+ sourceType: z.string().nullable(),
831
+ lastActivityAt: z.string()
832
+ })
833
+
834
+ export const AcqListLineageSchema = z.object({
835
+ deals: z.object({
836
+ total: z.number().int().min(0),
837
+ refs: z.array(AcqListDealRefSchema),
838
+ truncated: z.boolean()
839
+ })
840
+ })
841
+
842
+ export const AcqListDetailResponseSchema = AcqListResponseSchema.extend({
843
+ lineage: AcqListLineageSchema.optional(),
844
+ progress: ListProgressResponseSchema.optional()
845
+ })
846
+
847
+ export const AcqListStatusListItemSchema = z.object({
848
+ listId: z.string(),
849
+ name: z.string(),
850
+ status: ListStatusSchema,
851
+ totalCompanies: z.number().int().min(0),
852
+ totalContacts: z.number().int().min(0),
853
+ totalDeals: z.number().int().min(0),
854
+ createdAt: z.string()
855
+ })
856
+
857
+ export const AcqListStatusResponseSchema = z.object({
858
+ totalLists: z.number().int().min(0),
859
+ totalCompanies: z.number().int().min(0),
860
+ totalContacts: z.number().int().min(0),
861
+ totalDeals: z.number().int().min(0),
862
+ byStatus: z.record(z.string(), z.number().int().min(0)),
863
+ lists: z.array(AcqListStatusListItemSchema)
864
+ })
865
+
764
866
  /**
765
867
  * Row from acq_list_executions joined with the execution summary,
766
868
  * shaped for the /lists/:id/executions response.
@@ -781,12 +883,6 @@ export const ListExecutionsResponseSchema = z.array(ListExecutionSummarySchema)
781
883
  // Company / Contact API Schemas
782
884
  // ---------------------------------------------------------------------------
783
885
 
784
- const QueryBooleanSchema = z.preprocess((value) => {
785
- if (value === 'true' || value === '1' || value === true) return true
786
- if (value === 'false' || value === '0' || value === false) return false
787
- return value
788
- }, z.boolean())
789
-
790
886
  export const AcqCompanyStatusSchema = z.enum(['active', 'invalid'])
791
887
  export const AcqContactStatusSchema = z.enum(['active', 'invalid'])
792
888
  export const AcqEmailValidSchema = z.enum(['VALID', 'INVALID', 'RISKY', 'UNKNOWN'])
@@ -831,6 +927,7 @@ export const ListContactsQuerySchema = z
831
927
  export const CreateCompanyRequestSchema = z
832
928
  .object({
833
929
  name: z.string().trim().min(1).max(255),
930
+ clientId: UuidSchema.nullable().optional(),
834
931
  domain: z.string().trim().min(1).max(255).optional(),
835
932
  linkedinUrl: z.string().trim().url().optional(),
836
933
  website: z.string().trim().url().optional(),
@@ -849,6 +946,7 @@ export const CreateCompanyRequestSchema = z
849
946
  export const UpdateCompanyRequestSchema = z
850
947
  .object({
851
948
  name: z.string().trim().min(1).max(255).optional(),
949
+ clientId: UuidSchema.nullable().optional(),
852
950
  domain: z.string().trim().min(1).max(255).optional(),
853
951
  linkedinUrl: z.string().trim().url().optional(),
854
952
  website: z.string().trim().url().optional(),
@@ -870,6 +968,7 @@ export const UpdateCompanyRequestSchema = z
870
968
  .refine(
871
969
  (data) =>
872
970
  data.name !== undefined ||
971
+ data.clientId !== undefined ||
873
972
  data.domain !== undefined ||
874
973
  data.linkedinUrl !== undefined ||
875
974
  data.website !== undefined ||
@@ -894,6 +993,7 @@ export const UpdateCompanyRequestSchema = z
894
993
  export const CreateContactRequestSchema = z
895
994
  .object({
896
995
  email: z.string().trim().email(),
996
+ clientId: UuidSchema.nullable().optional(),
897
997
  companyId: UuidSchema.optional(),
898
998
  firstName: z.string().trim().min(1).max(255).optional(),
899
999
  lastName: z.string().trim().min(1).max(255).optional(),
@@ -909,6 +1009,7 @@ export const CreateContactRequestSchema = z
909
1009
  export const UpdateContactRequestSchema = z
910
1010
  .object({
911
1011
  companyId: UuidSchema.optional(),
1012
+ clientId: UuidSchema.nullable().optional(),
912
1013
  emailValid: AcqEmailValidSchema.optional(),
913
1014
  firstName: z.string().trim().min(1).max(255).optional(),
914
1015
  lastName: z.string().trim().min(1).max(255).optional(),
@@ -926,6 +1027,7 @@ export const UpdateContactRequestSchema = z
926
1027
  .refine(
927
1028
  (data) =>
928
1029
  data.companyId !== undefined ||
1030
+ data.clientId !== undefined ||
929
1031
  data.emailValid !== undefined ||
930
1032
  data.firstName !== undefined ||
931
1033
  data.lastName !== undefined ||
@@ -946,6 +1048,7 @@ export const UpdateContactRequestSchema = z
946
1048
  export const AcqCompanyResponseSchema = z.object({
947
1049
  id: z.string(),
948
1050
  organizationId: z.string(),
1051
+ clientId: z.string().nullable().optional(),
949
1052
  name: z.string(),
950
1053
  domain: z.string().nullable(),
951
1054
  linkedinUrl: z.string().nullable(),
@@ -996,6 +1099,7 @@ export const AcqContactCompanySummarySchema = z.object({
996
1099
  export const AcqContactResponseSchema = z.object({
997
1100
  id: z.string(),
998
1101
  organizationId: z.string(),
1102
+ clientId: z.string().nullable().optional(),
999
1103
  companyId: z.string().nullable(),
1000
1104
  email: z.string(),
1001
1105
  emailValid: AcqEmailValidSchema.nullable(),
@@ -1290,13 +1394,15 @@ export const AcqListSchemas = {
1290
1394
  BuildPlanSnapshotStep: BuildPlanSnapshotStepSchema,
1291
1395
  AcqListMetadata: AcqListMetadataSchema,
1292
1396
  LeadGenStageKey: LeadGenStageKeySchema,
1293
- LeadGenCapabilityKey: LeadGenCapabilityKeySchema,
1397
+ LeadGenActionKey: LeadGenActionKeySchema,
1294
1398
  ProcessingStageStatus: ProcessingStageStatusSchema,
1295
1399
  ProcessingState: ProcessingStateSchema,
1296
1400
  ListStageCounts: ListStageCountsSchema,
1297
1401
  ListTelemetry: ListTelemetrySchema,
1298
1402
 
1299
1403
  // Requests
1404
+ ListReadQuery: ListReadQuerySchema,
1405
+ GetListQuery: GetListQuerySchema,
1300
1406
  CreateListRequest: CreateListRequestSchema,
1301
1407
  UpdateListRequest: UpdateListRequestSchema,
1302
1408
  UpdateListStatusRequest: UpdateListStatusRequestSchema,
@@ -1308,7 +1414,11 @@ export const AcqListSchemas = {
1308
1414
 
1309
1415
  // Responses
1310
1416
  AcqListResponse: AcqListResponseSchema,
1417
+ AcqListDetailResponse: AcqListDetailResponseSchema,
1311
1418
  AcqListListResponse: AcqListListResponseSchema,
1419
+ AcqListDealRef: AcqListDealRefSchema,
1420
+ AcqListLineage: AcqListLineageSchema,
1421
+ AcqListStatusResponse: AcqListStatusResponseSchema,
1312
1422
  ListTelemetryResponse: ListTelemetryResponseSchema,
1313
1423
  ListTelemetryListResponse: ListTelemetryListResponseSchema,
1314
1424
  ListExecutionsResponse: ListExecutionsResponseSchema,
@@ -1382,11 +1492,13 @@ export type PipelineConfig = z.infer<typeof PipelineConfigSchema>
1382
1492
  export type BuildPlanSnapshotStep = z.infer<typeof BuildPlanSnapshotStepSchema>
1383
1493
  export type BuildPlanSnapshot = z.infer<typeof BuildPlanSnapshotSchema>
1384
1494
  export type AcqListMetadata = z.infer<typeof AcqListMetadataSchema>
1385
- export type LeadGenCapabilityKey = z.infer<typeof LeadGenCapabilityKeySchema>
1495
+ export type LeadGenActionKey = z.infer<typeof LeadGenActionKeySchema>
1386
1496
  export type ProcessingStageStatus = z.infer<typeof ProcessingStageStatusSchema>
1387
1497
  export type ListStageCountsInput = z.infer<typeof ListStageCountsSchema>['stageCounts']
1388
1498
  export type ListTelemetryInput = z.infer<typeof ListTelemetrySchema>
1389
1499
  export type ListIdParams = z.infer<typeof ListIdParamsSchema>
1500
+ export type ListReadQuery = z.infer<typeof ListReadQuerySchema>
1501
+ export type GetListQuery = z.infer<typeof GetListQuerySchema>
1390
1502
  export type CreateListRequest = z.infer<typeof CreateListRequestSchema>
1391
1503
  export type UpdateListRequest = z.infer<typeof UpdateListRequestSchema>
1392
1504
  export type UpdateListStatusRequest = z.infer<typeof UpdateListStatusRequestSchema>
@@ -1396,7 +1508,11 @@ export type RemoveCompaniesFromListRequest = z.infer<typeof RemoveCompaniesFromL
1396
1508
  export type AddContactsToListRequest = z.infer<typeof AddContactsToListRequestSchema>
1397
1509
  export type RecordListExecutionRequest = z.infer<typeof RecordListExecutionRequestSchema>
1398
1510
  export type AcqListResponse = z.infer<typeof AcqListResponseSchema>
1511
+ export type AcqListDetailResponse = z.infer<typeof AcqListDetailResponseSchema>
1399
1512
  export type AcqListListResponse = z.infer<typeof AcqListListResponseSchema>
1513
+ export type AcqListDealRef = z.infer<typeof AcqListDealRefSchema>
1514
+ export type AcqListLineage = z.infer<typeof AcqListLineageSchema>
1515
+ export type AcqListStatusResponse = z.infer<typeof AcqListStatusResponseSchema>
1400
1516
  export type ListTelemetryResponse = z.infer<typeof ListTelemetryResponseSchema>
1401
1517
  export type ListTelemetryListResponse = z.infer<typeof ListTelemetryListResponseSchema>
1402
1518
  export type ListExecutionSummaryInput = z.infer<typeof ListExecutionSummarySchema>
@@ -88,7 +88,7 @@ describe('createBuildPlanSnapshotFromTemplateId — "local-services"', () => {
88
88
  expect(snapshot?.steps).toHaveLength(7)
89
89
  })
90
90
 
91
- it('every step has required fields: id, label, primaryEntity, outputs, stageKey, dependencyMode, capabilityKey', () => {
91
+ it('every step has required fields: id, label, primaryEntity, outputs, stageKey, dependencyMode, actionKey', () => {
92
92
  for (const step of snapshot?.steps ?? []) {
93
93
  expect(step.id).toBeTruthy()
94
94
  expect(step.label).toBeTruthy()
@@ -96,7 +96,7 @@ describe('createBuildPlanSnapshotFromTemplateId — "local-services"', () => {
96
96
  expect(step.outputs.length).toBeGreaterThanOrEqual(1)
97
97
  expect(step.stageKey).toBeTruthy()
98
98
  expect(step.dependencyMode).toBe('per-record-eligibility')
99
- expect(step.capabilityKey).toBeTruthy()
99
+ expect(step.actionKey).toBeTruthy()
100
100
  }
101
101
  })
102
102
 
@@ -149,7 +149,7 @@ describe('createBuildPlanSnapshotFromTemplateId — "dtc-subscription-apollo-cli
149
149
  expect(snapshot?.steps).toHaveLength(6)
150
150
  })
151
151
 
152
- it('every step has required fields: id, label, primaryEntity, outputs, stageKey, dependencyMode, capabilityKey', () => {
152
+ it('every step has required fields: id, label, primaryEntity, outputs, stageKey, dependencyMode, actionKey', () => {
153
153
  for (const step of snapshot?.steps ?? []) {
154
154
  expect(step.id).toBeTruthy()
155
155
  expect(step.label).toBeTruthy()
@@ -157,7 +157,7 @@ describe('createBuildPlanSnapshotFromTemplateId — "dtc-subscription-apollo-cli
157
157
  expect(step.outputs.length).toBeGreaterThanOrEqual(1)
158
158
  expect(step.stageKey).toBeTruthy()
159
159
  expect(step.dependencyMode).toBe('per-record-eligibility')
160
- expect(step.capabilityKey).toBeTruthy()
160
+ expect(step.actionKey).toBeTruthy()
161
161
  }
162
162
  })
163
163