@company-semantics/contracts 15.0.0 → 16.0.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@company-semantics/contracts",
3
- "version": "15.0.0",
3
+ "version": "16.0.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -109,7 +109,9 @@
109
109
  "generate:api-types": "openapi-typescript openapi/backend.yaml -o src/api/generated.ts",
110
110
  "generate:openapi-routes": "tsx scripts/generate-openapi-routes.ts",
111
111
  "generate:api-types:check": "openapi-typescript openapi/backend.yaml -o /tmp/cs-api-types-check.ts && diff -q src/api/generated.ts /tmp/cs-api-types-check.ts",
112
- "generate:current": "tsx ../company-semantics-ci/scripts/generate-current.ts"
112
+ "generate:current": "tsx ../company-semantics-ci/scripts/generate-current.ts",
113
+ "repo-map": "tsx ../company-semantics-ci/scripts/generate-repo-map.ts --roots src --name company-semantics-contracts --write",
114
+ "repo-map:check": "tsx ../company-semantics-ci/scripts/generate-repo-map.ts --roots src --name company-semantics-contracts --check"
113
115
  },
114
116
  "packageManager": "pnpm@10.25.0",
115
117
  "engines": {
@@ -1,3 +1,3 @@
1
1
  // AUTO-GENERATED — do not edit. Run pnpm generate:spec-hash to regenerate.
2
- export const SPEC_HASH = '16c3b86cc35a' as const;
3
- export const SPEC_HASH_FULL = '16c3b86cc35a3f329766b702414438de4950430991a603372f1335206c96b600' as const;
2
+ export const SPEC_HASH = 'bd74b6f7478d' as const;
3
+ export const SPEC_HASH_FULL = 'bd74b6f7478dcfb445d1e848ab3b65309f9b602b40c3fe2f0ce29b484e94943f' as const;
@@ -736,6 +736,23 @@ export interface paths {
736
736
  patch: operations["setMemberManager"];
737
737
  trace?: never;
738
738
  };
739
+ "/api/chat/interactive-tasks/submit": {
740
+ parameters: {
741
+ query?: never;
742
+ header?: never;
743
+ path?: never;
744
+ cookie?: never;
745
+ };
746
+ get?: never;
747
+ put?: never;
748
+ /** Submit a filled-in interactive chat task (creates + runs a governed execution) */
749
+ post: operations["submitInteractiveTask"];
750
+ delete?: never;
751
+ options?: never;
752
+ head?: never;
753
+ patch?: never;
754
+ trace?: never;
755
+ };
739
756
  "/api/rbac/roles": {
740
757
  parameters: {
741
758
  query?: never;
@@ -3398,7 +3415,7 @@ export interface components {
3398
3415
  email: string;
3399
3416
  avatarUrl?: string | null;
3400
3417
  jobTitle: string | null;
3401
- role: ("owner" | "leader" | "delegate" | "admin") | null;
3418
+ role: ("owner" | "unit_owner" | "delegate" | "admin") | null;
3402
3419
  roleNames: string[];
3403
3420
  joinedAt: string;
3404
3421
  lastActiveAt: string | null;
@@ -3410,11 +3427,11 @@ export interface components {
3410
3427
  /** @enum {string} */
3411
3428
  role: "owner" | "manager" | "member";
3412
3429
  }[];
3413
- manages: {
3430
+ unitDesignations: {
3414
3431
  unitId: string;
3415
3432
  unitName: string;
3416
3433
  /** @enum {string} */
3417
- designation: "whole_org" | "admin" | "leader" | "delegate" | "member";
3434
+ designation: "whole_org" | "admin" | "unit_owner" | "delegate" | "member";
3418
3435
  }[];
3419
3436
  unitMembershipsTruncated: boolean;
3420
3437
  inviteStatus: ("active" | "pending" | "expired") | null;
@@ -3593,7 +3610,7 @@ export interface components {
3593
3610
  email: string;
3594
3611
  avatarUrl?: string | null;
3595
3612
  jobTitle: string | null;
3596
- role: ("owner" | "leader" | "delegate" | "admin") | null;
3613
+ role: ("owner" | "unit_owner" | "delegate" | "admin") | null;
3597
3614
  roleNames: string[];
3598
3615
  joinedAt: string;
3599
3616
  lastActiveAt: string | null;
@@ -3605,11 +3622,11 @@ export interface components {
3605
3622
  /** @enum {string} */
3606
3623
  role: "owner" | "manager" | "member";
3607
3624
  }[];
3608
- manages: {
3625
+ unitDesignations: {
3609
3626
  unitId: string;
3610
3627
  unitName: string;
3611
3628
  /** @enum {string} */
3612
- designation: "whole_org" | "admin" | "leader" | "delegate" | "member";
3629
+ designation: "whole_org" | "admin" | "unit_owner" | "delegate" | "member";
3613
3630
  }[];
3614
3631
  unitMembershipsTruncated: boolean;
3615
3632
  inviteStatus: ("active" | "pending" | "expired") | null;
@@ -3650,6 +3667,21 @@ export interface components {
3650
3667
  /** Format: uuid */
3651
3668
  managerUserId: string;
3652
3669
  };
3670
+ SubmitInteractiveTaskResponse: {
3671
+ executionId: string;
3672
+ /** @enum {string} */
3673
+ status: "executing" | "completed" | "failed" | "pending_confirmation";
3674
+ };
3675
+ SubmitInteractiveTaskRequest: {
3676
+ /** Format: uuid */
3677
+ taskId: string;
3678
+ /** @constant */
3679
+ taskKind: "member.changeManager";
3680
+ /** Format: uuid */
3681
+ memberId: string;
3682
+ newManagerUserId: string | null;
3683
+ chatId: string;
3684
+ };
3653
3685
  RoleCatalogResponse: {
3654
3686
  roles: {
3655
3687
  name: string;
@@ -3666,7 +3698,7 @@ export interface components {
3666
3698
  orgId: string;
3667
3699
  orgName: string;
3668
3700
  orgSlug: string;
3669
- role: ("owner" | "leader" | "delegate" | "admin") | null;
3701
+ role: ("owner" | "unit_owner" | "delegate" | "admin") | null;
3670
3702
  joinedAt: string;
3671
3703
  isActive: boolean;
3672
3704
  /** @enum {string} */
@@ -3711,7 +3743,7 @@ export interface components {
3711
3743
  /** Format: uuid */
3712
3744
  homeUnitId?: string;
3713
3745
  /** @enum {string} */
3714
- homeUnitRole?: "member" | "leader";
3746
+ homeUnitRole?: "member" | "unit_owner";
3715
3747
  createdAt: string;
3716
3748
  expiresAt: string;
3717
3749
  acceptedAt?: string;
@@ -3725,7 +3757,7 @@ export interface components {
3725
3757
  /** Format: uuid */
3726
3758
  homeUnitId?: string;
3727
3759
  /** @enum {string} */
3728
- homeUnitRole?: "member" | "leader";
3760
+ homeUnitRole?: "member" | "unit_owner";
3729
3761
  };
3730
3762
  InviteListResponse: {
3731
3763
  id: string;
@@ -3742,7 +3774,7 @@ export interface components {
3742
3774
  /** Format: uuid */
3743
3775
  homeUnitId?: string;
3744
3776
  /** @enum {string} */
3745
- homeUnitRole?: "member" | "leader";
3777
+ homeUnitRole?: "member" | "unit_owner";
3746
3778
  createdAt: string;
3747
3779
  expiresAt: string;
3748
3780
  acceptedAt?: string;
@@ -3920,7 +3952,7 @@ export interface components {
3920
3952
  summary: {
3921
3953
  executionId: string;
3922
3954
  /** @enum {string} */
3923
- kind: "integration.connect" | "integration.disconnect" | "profile.update" | "slack.send" | "data.ingest" | "data.scope" | "system.cleanup";
3955
+ kind: "integration.connect" | "integration.disconnect" | "profile.update" | "slack.send" | "data.ingest" | "data.scope" | "system.cleanup" | "member.changeManager";
3924
3956
  target: {
3925
3957
  /** @constant */
3926
3958
  type: "slack";
@@ -4616,7 +4648,7 @@ export interface components {
4616
4648
  OrgUnitMyAuthorityResponse: {
4617
4649
  /** Format: uuid */
4618
4650
  unitId: string;
4619
- role: ("owner" | "leader" | "delegate" | "admin") | null;
4651
+ role: ("owner" | "unit_owner" | "delegate" | "admin") | null;
4620
4652
  canManageMembers: boolean;
4621
4653
  canAssignDelegate: boolean;
4622
4654
  canAssignAdmin: boolean;
@@ -6536,6 +6568,30 @@ export interface operations {
6536
6568
  };
6537
6569
  };
6538
6570
  };
6571
+ submitInteractiveTask: {
6572
+ parameters: {
6573
+ query?: never;
6574
+ header?: never;
6575
+ path?: never;
6576
+ cookie?: never;
6577
+ };
6578
+ requestBody: {
6579
+ content: {
6580
+ "application/json": components["schemas"]["SubmitInteractiveTaskRequest"];
6581
+ };
6582
+ };
6583
+ responses: {
6584
+ /** @description Execution created and run through the governance engine */
6585
+ 200: {
6586
+ headers: {
6587
+ [name: string]: unknown;
6588
+ };
6589
+ content: {
6590
+ "application/json": components["schemas"]["SubmitInteractiveTaskResponse"];
6591
+ };
6592
+ };
6593
+ };
6594
+ };
6539
6595
  getRbacRoles: {
6540
6596
  parameters: {
6541
6597
  query?: never;
@@ -7073,7 +7129,7 @@ export interface operations {
7073
7129
  query?: {
7074
7130
  cursor?: string;
7075
7131
  limit?: number;
7076
- kind?: "integration.connect" | "integration.disconnect" | "profile.update" | "slack.send" | "data.ingest" | "data.scope" | "system.cleanup";
7132
+ kind?: "integration.connect" | "integration.disconnect" | "profile.update" | "slack.send" | "data.ingest" | "data.scope" | "system.cleanup" | "member.changeManager";
7077
7133
  targetType?: string;
7078
7134
  periodStart?: string;
7079
7135
  periodEnd?: string;
@@ -7208,7 +7264,7 @@ export interface operations {
7208
7264
  query?: {
7209
7265
  limit?: number;
7210
7266
  offset?: number;
7211
- kind?: "integration.connect" | "integration.disconnect" | "profile.update" | "slack.send" | "data.ingest" | "data.scope" | "system.cleanup";
7267
+ kind?: "integration.connect" | "integration.disconnect" | "profile.update" | "slack.send" | "data.ingest" | "data.scope" | "system.cleanup" | "member.changeManager";
7212
7268
  kindPrefix?: string;
7213
7269
  };
7214
7270
  header?: never;
@@ -156,6 +156,28 @@ describe("EXECUTION_KINDS golden snapshot", () => {
156
156
  templateId: "system-cleanup",
157
157
  },
158
158
  },
159
+ "member.changeManager": {
160
+ kind: "member.changeManager",
161
+ domain: "organization",
162
+ display: {
163
+ label: "Change Reporting Manager",
164
+ pastTenseLabel: "Reporting manager changed",
165
+ icon: "pencil",
166
+ },
167
+ governance: {
168
+ visibility: "user",
169
+ requiresAdmin: false,
170
+ reversibleBy: "member.changeManager",
171
+ },
172
+ ui: {
173
+ showInAdmin: false,
174
+ showInTimeline: true,
175
+ confirmBeforeRun: true,
176
+ },
177
+ explanation: {
178
+ templateId: "member-change-manager",
179
+ },
180
+ },
159
181
  });
160
182
  });
161
183
  });
@@ -29,4 +29,5 @@ export type ExecutionKind =
29
29
  | "slack.send"
30
30
  | "data.ingest"
31
31
  | "data.scope"
32
- | "system.cleanup";
32
+ | "system.cleanup"
33
+ | "member.changeManager";
@@ -181,6 +181,29 @@ export const EXECUTION_KINDS = {
181
181
  templateId: "system-cleanup",
182
182
  },
183
183
  },
184
+ "member.changeManager": {
185
+ kind: "member.changeManager",
186
+ domain: "organization",
187
+ display: {
188
+ label: "Change Reporting Manager",
189
+ pastTenseLabel: "Reporting manager changed",
190
+ icon: "pencil",
191
+ },
192
+ governance: {
193
+ visibility: "user",
194
+ requiresAdmin: false,
195
+ // Reversible: re-applying the previous solid-line edge undoes the change.
196
+ reversibleBy: "member.changeManager",
197
+ },
198
+ ui: {
199
+ showInAdmin: false,
200
+ showInTimeline: true,
201
+ confirmBeforeRun: true,
202
+ },
203
+ explanation: {
204
+ templateId: "member-change-manager",
205
+ },
206
+ },
184
207
  } as const satisfies Record<ExecutionKind, ExecutionKindDefinition>;
185
208
 
186
209
  // =============================================================================
@@ -38,7 +38,8 @@ export type ExecutionDomain =
38
38
  | "data"
39
39
  | "system"
40
40
  | "profile"
41
- | "communication";
41
+ | "communication"
42
+ | "organization";
42
43
 
43
44
  // =============================================================================
44
45
  // Execution Kind Definition
@@ -11,6 +11,7 @@ export const openApiRoutes = {
11
11
  '/api/account/sessions/{sessionId}': ['DELETE'],
12
12
  '/api/auth/consent/grant': ['POST'],
13
13
  '/api/capabilities': ['GET'],
14
+ '/api/chat/interactive-tasks/submit': ['POST'],
14
15
  '/api/chats': ['GET', 'POST'],
15
16
  '/api/chats/by-interaction/{interactionId}': ['GET'],
16
17
  '/api/chats/events': ['GET'],
package/src/index.ts CHANGED
@@ -454,6 +454,15 @@ export type {
454
454
  ConfirmationData,
455
455
  ConfirmationResponseData,
456
456
  ConfirmationDataPart,
457
+ // Interactive task surface types (editable surfaces)
458
+ InteractiveTaskKind,
459
+ CandidateSource,
460
+ InteractiveFieldType,
461
+ InteractiveFieldDescriptor,
462
+ InteractiveTaskSubject,
463
+ InteractiveTaskData,
464
+ InteractiveTaskPart,
465
+ InteractiveTaskDataPart,
457
466
  // Execution result types (Phase 5)
458
467
  ExecutionArtifactStatus,
459
468
  ExecutionResultSummary,
@@ -119,6 +119,7 @@ describe("CONFIRMATION_LABELS", () => {
119
119
  "data.ingest": "Import Channel",
120
120
  "data.scope": "Update Scope",
121
121
  "system.cleanup": "Cleanup Connections",
122
+ "member.changeManager": "Change Reporting Manager",
122
123
  });
123
124
  });
124
125
  });
@@ -47,6 +47,7 @@ export const CONFIRMATION_LABELS: Record<ExecutionKind, string> = {
47
47
  "data.ingest": "Import Channel",
48
48
  "data.scope": "Update Scope",
49
49
  "system.cleanup": "Cleanup Connections",
50
+ "member.changeManager": "Change Reporting Manager",
50
51
  };
51
52
 
52
53
  /**
@@ -43,6 +43,18 @@ export type {
43
43
  // Confirmation runtime values
44
44
  export { CONFIRMATION_LABELS, getConfirmationLabel } from "./confirmation";
45
45
 
46
+ // Interactive task surface types
47
+ export type {
48
+ InteractiveTaskKind,
49
+ CandidateSource,
50
+ InteractiveFieldType,
51
+ InteractiveFieldDescriptor,
52
+ InteractiveTaskSubject,
53
+ InteractiveTaskData,
54
+ InteractiveTaskPart,
55
+ InteractiveTaskDataPart,
56
+ } from "./interactive";
57
+
46
58
  // Execution result types
47
59
  export type {
48
60
  ExecutionArtifactStatus,
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Interactive Task Surface Types
3
+ *
4
+ * Interactive surfaces are EDITABLE: the assistant emits a form the user fills
5
+ * out inline in chat (e.g. picking a new reporting manager), then submits. They
6
+ * are the third surface class alongside `preview` (read-only diff) and
7
+ * `confirmation` (Y/N). Unlike those, an interactive task is PRE-EXECUTION:
8
+ *
9
+ * INTERACTIVE TASK INVARIANTS:
10
+ * - An interactive task carries NO executionId — no execution exists yet. That
11
+ * absence is the structural marker distinguishing it from ConfirmationPart
12
+ * (which requires an executionId). The execution is born when the user submits.
13
+ * - The assistant emits an interactive task only when it lacks the parameters to
14
+ * produce an exactly-executable preview. Once parameters are known, a normal
15
+ * `preview` + `confirmation` flow is used instead.
16
+ * - The surface collects user input and POSTs it to `submitEndpoint`; the backend
17
+ * then runs the governance engine (create execution → execute), so the change
18
+ * is audited and reversible like every other chat action.
19
+ * - At most one GOVERNED surface (preview ∪ interactive) is active per turn.
20
+ *
21
+ * @see decisions/ADR-CONTRACTS-068.md for design rationale
22
+ */
23
+
24
+ import type { ConfirmationRiskLevel } from "./confirmation";
25
+
26
+ /**
27
+ * The set of editable tasks the assistant can present inline.
28
+ * Mirrors the `{domain}.{verb}` naming of ExecutionKind. Extensible union.
29
+ */
30
+ export type InteractiveTaskKind = "member.changeManager";
31
+
32
+ /**
33
+ * How the frontend sources candidate values for an editable field.
34
+ * - `inline`: the options are shipped with the part (small, bounded sets).
35
+ * - `search`: the frontend queries `endpoint` as the user types (large sets).
36
+ */
37
+ export type CandidateSource =
38
+ | {
39
+ kind: "inline";
40
+ options: Array<{ value: string; label: string; sublabel?: string }>;
41
+ }
42
+ | { kind: "search"; endpoint: string; minChars?: number };
43
+
44
+ /**
45
+ * The input shape of an editable field.
46
+ * - `member-ref`: a workspace member id (backed by a member picker).
47
+ * - `text`: free text.
48
+ * - `enum`: one of the field's inline candidate options.
49
+ */
50
+ export type InteractiveFieldType = "member-ref" | "text" | "enum";
51
+
52
+ /**
53
+ * One editable field within an interactive task.
54
+ */
55
+ export interface InteractiveFieldDescriptor {
56
+ /** Submit key, e.g. "newManagerUserId". */
57
+ name: string;
58
+ /** Display label, e.g. "Reports to". */
59
+ label: string;
60
+ /** Input shape. */
61
+ type: InteractiveFieldType;
62
+ /** Whether the field must be filled before submit is allowed. */
63
+ required: boolean;
64
+ /** Whether the field supports an explicit "clear"/empty submission (e.g. "No manager"). */
65
+ clearable?: boolean;
66
+ /** Current value (for the diff's "old" half); null when unset. */
67
+ currentValue?: string | null;
68
+ /** Human-readable current value (e.g. "Jordan Rivera") for display. */
69
+ currentLabel?: string | null;
70
+ /** How to source candidate values; omitted for free `text` fields. */
71
+ candidates?: CandidateSource;
72
+ }
73
+
74
+ /**
75
+ * Read-only subject the task acts upon (e.g. the member being edited).
76
+ */
77
+ export interface InteractiveTaskSubject {
78
+ /** Workspace member id (users.id) the task edits. */
79
+ memberId: string;
80
+ /** Display name for the surface header. */
81
+ displayName: string;
82
+ /** Arbitrary read-only context the surface may render. */
83
+ context?: Record<string, string>;
84
+ }
85
+
86
+ /**
87
+ * Interactive task surface data payload.
88
+ */
89
+ export interface InteractiveTaskData {
90
+ /** Stable id for this task; becomes the governance correlation key on submit. */
91
+ taskId: string;
92
+ /** Which editable task this is — selects the frontend renderer. */
93
+ taskKind: InteractiveTaskKind;
94
+ /** Human-readable summary of what the user is about to change. */
95
+ title: string;
96
+ /** Optional detail. */
97
+ description?: string;
98
+ /** What the task acts upon. */
99
+ subject: InteractiveTaskSubject;
100
+ /** The editable fields. */
101
+ fields: InteractiveFieldDescriptor[];
102
+ /** Endpoint the frontend POSTs the filled form to. */
103
+ submitEndpoint: string;
104
+ /** Risk level for UI styling; mirrors ConfirmationData.risk. */
105
+ risk: ConfirmationRiskLevel;
106
+ }
107
+
108
+ /**
109
+ * Interactive task message part (semantic type).
110
+ */
111
+ export interface InteractiveTaskPart {
112
+ type: "interactive";
113
+ data: InteractiveTaskData;
114
+ }
115
+
116
+ /**
117
+ * Interactive task data part (wire format).
118
+ * Uses AI SDK's data-{name} convention.
119
+ */
120
+ export interface InteractiveTaskDataPart {
121
+ type: "data-interactive-task";
122
+ data: InteractiveTaskData;
123
+ }
@@ -16,6 +16,7 @@
16
16
  import type { ToolListMessagePart } from "../mcp/index";
17
17
  import type { PreviewPart } from "./preview";
18
18
  import type { ConfirmationPart } from "./confirmation";
19
+ import type { InteractiveTaskPart } from "./interactive";
19
20
 
20
21
  // =============================================================================
21
22
  // Narrative Parts (Streamable)
@@ -118,7 +119,8 @@ export type SurfacePart =
118
119
  | ChartPart
119
120
  | TablePart
120
121
  | ConfirmationPart
121
- | PreviewPart;
122
+ | PreviewPart
123
+ | InteractiveTaskPart;
122
124
 
123
125
  /**
124
126
  * All assistant message part types.
@@ -13,6 +13,10 @@
13
13
  import type { MCPToolDescriptor, ToolListDataPart } from "../mcp/index";
14
14
  import type { PreviewDataPart, PreviewData } from "./preview";
15
15
  import type { ConfirmationData, ConfirmationDataPart } from "./confirmation";
16
+ import type {
17
+ InteractiveTaskData,
18
+ InteractiveTaskDataPart,
19
+ } from "./interactive";
16
20
  import type {
17
21
  ExecutionResultData,
18
22
  ExecutionResultDataPart,
@@ -87,6 +91,27 @@ export const WireSurfaceBuilder = {
87
91
  };
88
92
  },
89
93
 
94
+ /**
95
+ * Build an interactive task data part for streaming.
96
+ * Interactive tasks are EDITABLE forms the user fills in inline; unlike a
97
+ * preview they carry no executionId (no execution exists until the user
98
+ * submits the filled form).
99
+ *
100
+ * INVARIANTS:
101
+ * - taskId must be stable for governance correlation on submit
102
+ * - At most one governed surface (preview ∪ interactive) per turn
103
+ * - No execution is created when this part is emitted
104
+ *
105
+ * @param data - Interactive task data (subject, fields, submitEndpoint)
106
+ * @returns Wire-format interactive task part ready for stream
107
+ */
108
+ interactiveTask(data: InteractiveTaskData): InteractiveTaskDataPart {
109
+ return {
110
+ type: "data-interactive-task",
111
+ data,
112
+ };
113
+ },
114
+
90
115
  /**
91
116
  * Build an execution result data part for streaming.
92
117
  * Reports the outcome of an executed action.
package/src/org/index.ts CHANGED
@@ -141,8 +141,9 @@ export {
141
141
  WorkspaceOverviewSchema,
142
142
  WorkspaceMembersResponseSchema,
143
143
  WorkspaceMemberDetailSchema,
144
- WorkspaceMemberManagesEntrySchema,
144
+ WorkspaceMemberUnitDesignationEntrySchema,
145
145
  OrgUnitDesignationSchema,
146
+ HomeUnitRoleSchema,
146
147
  RoleCatalogEntrySchema,
147
148
  RoleCatalogResponseSchema,
148
149
  WorkspaceAuthConfigSchema,
@@ -157,6 +158,7 @@ export {
157
158
  RemoveMemberResponseSchema,
158
159
  ChangeMemberRoleResponseSchema,
159
160
  SetMemberManagerResponseSchema,
161
+ SubmitInteractiveTaskResponseSchema,
160
162
  UserOrgsResponseSchema,
161
163
  SetActiveOrgResponseSchema,
162
164
  LeaveOrgResponseSchema,
@@ -167,8 +169,9 @@ export type {
167
169
  WorkspaceAccessResponse,
168
170
  WorkspaceOverview as WorkspaceOverviewDto,
169
171
  WorkspaceMembersResponse,
170
- WorkspaceMemberManagesEntry,
172
+ WorkspaceMemberUnitDesignationEntry,
171
173
  OrgUnitDesignation,
174
+ HomeUnitRole,
172
175
  WorkspaceAuthConfig as WorkspaceAuthConfigDto,
173
176
  WorkspaceAuditEvent as WorkspaceAuditEventDto,
174
177
  WorkspaceResolvePathResponse,
@@ -180,6 +183,7 @@ export type {
180
183
  RemoveMemberResponse,
181
184
  ChangeMemberRoleResponse,
182
185
  SetMemberManagerResponse,
186
+ SubmitInteractiveTaskResponse,
183
187
  UserOrgsResponse,
184
188
  SetActiveOrgResponse,
185
189
  LeaveOrgResponse,
@@ -28,7 +28,7 @@ const WorkspaceMemberUnitSummarySchema = z.object({
28
28
  /**
29
29
  * Designation a member holds over a unit they manage (ADR-CTRL-112).
30
30
  *
31
- * Precedence, highest-first: whole_org > admin > leader > delegate > member.
31
+ * Precedence, highest-first: whole_org > admin > unit_owner > delegate > member.
32
32
  * The org-wide designations (`whole_org`, `admin`) anchor to the org root
33
33
  * unit. This vocabulary is DISPLAY-ONLY — it summarizes management reach for
34
34
  * UI surfaces and is NEVER an authorization input (authority resolution uses
@@ -37,19 +37,19 @@ const WorkspaceMemberUnitSummarySchema = z.object({
37
37
  export const OrgUnitDesignationSchema = z.enum([
38
38
  "whole_org",
39
39
  "admin",
40
- "leader",
40
+ "unit_owner",
41
41
  "delegate",
42
42
  "member",
43
43
  ]);
44
44
  export type OrgUnitDesignation = z.infer<typeof OrgUnitDesignationSchema>;
45
45
 
46
- export const WorkspaceMemberManagesEntrySchema = z.object({
46
+ export const WorkspaceMemberUnitDesignationEntrySchema = z.object({
47
47
  unitId: z.string(),
48
48
  unitName: z.string(),
49
49
  designation: OrgUnitDesignationSchema,
50
50
  });
51
- export type WorkspaceMemberManagesEntry = z.infer<
52
- typeof WorkspaceMemberManagesEntrySchema
51
+ export type WorkspaceMemberUnitDesignationEntry = z.infer<
52
+ typeof WorkspaceMemberUnitDesignationEntrySchema
53
53
  >;
54
54
 
55
55
  const WorkspaceMemberSchema = z.object({
@@ -87,11 +87,13 @@ const WorkspaceMemberSchema = z.object({
87
87
  /** OrgUnit memberships for this member, capped at a small number server-side. */
88
88
  unitMemberships: z.array(WorkspaceMemberUnitSummarySchema),
89
89
  /**
90
- * Per-unit org-chart designations the member holds where they manage
91
- * (ADR-CTRL-112). Display-only summary of management reach; never an
92
- * authorization input. Empty array when the member manages nothing.
90
+ * Per-unit org-chart designations the member holds (ADR-CTRL-112). Carries
91
+ * BOTH management-reach entries (whole_org/admin/unit_owner/delegate) and
92
+ * plain contributor entries (`member`); consumers split by designation.
93
+ * Display-only summary; never an authorization input. Empty array when the
94
+ * member holds no per-unit designation.
93
95
  */
94
- manages: z.array(WorkspaceMemberManagesEntrySchema),
96
+ unitDesignations: z.array(WorkspaceMemberUnitDesignationEntrySchema),
95
97
  /** True when server truncated `unitMemberships`; detail endpoint returns the full list. */
96
98
  unitMembershipsTruncated: z.boolean(),
97
99
  /** Invite lifecycle status. `null` for members without an invite record. */
@@ -501,6 +503,31 @@ export type SetMemberManagerResponse = z.infer<
501
503
  typeof SetMemberManagerResponseSchema
502
504
  >;
503
505
 
506
+ // ---------------------------------------------------------------------------
507
+ // POST /api/chat/interactive-tasks/submit
508
+ // ---------------------------------------------------------------------------
509
+
510
+ /**
511
+ * Response for submitting a filled-in interactive chat task surface (e.g. the
512
+ * editable "change reporting manager" form). The submit endpoint runs the
513
+ * Deterministic Execution & Governance Engine: it creates an execution and,
514
+ * when no further confirmation is required, drives it to execution in the same
515
+ * request. The frontend then drives the surface's lifecycle card off
516
+ * `executionId` (the execution-lifecycle stream), exactly like a confirmation.
517
+ *
518
+ * See ADR-CONTRACTS-068.
519
+ */
520
+ export const SubmitInteractiveTaskResponseSchema = z.object({
521
+ /** Lifecycle record id created for this submission. */
522
+ executionId: z.string(),
523
+ /** Coarse lifecycle status at the time the request returns. */
524
+ status: z.enum(["executing", "completed", "failed", "pending_confirmation"]),
525
+ });
526
+
527
+ export type SubmitInteractiveTaskResponse = z.infer<
528
+ typeof SubmitInteractiveTaskResponseSchema
529
+ >;
530
+
504
531
  // ---------------------------------------------------------------------------
505
532
  // GET /api/user/orgs
506
533
  // ---------------------------------------------------------------------------
@@ -570,6 +597,15 @@ export type ScopeCheckBatchResponse = z.infer<
570
597
  // Invite sub-schema
571
598
  // ---------------------------------------------------------------------------
572
599
 
600
+ /**
601
+ * Role the invitee takes in their home unit on acceptance. `unit_owner` is a
602
+ * deferred structural-leadership grant applied at accept time. Source of truth
603
+ * for the hand-mirrored `OrgInvite`/`CreateInviteRequest` interface unions in
604
+ * `org/types.ts` (enforced by the `schema-type-mirror` guard).
605
+ */
606
+ export const HomeUnitRoleSchema = z.enum(["member", "unit_owner"]);
607
+ export type HomeUnitRole = z.infer<typeof HomeUnitRoleSchema>;
608
+
573
609
  const OrgInviteSchema = z.object({
574
610
  id: z.string(),
575
611
  orgId: z.string(),
@@ -580,9 +616,10 @@ const OrgInviteSchema = z.object({
580
616
  // Home unit the invitee is placed in on acceptance (users.primary_unit_id).
581
617
  // Optional/nullable: legacy invites predate this field.
582
618
  homeUnitId: z.string().uuid().optional(),
583
- // Role the invitee takes in homeUnitId on acceptance ('leader' is a deferred
584
- // structural-leadership grant). Optional/'member' for legacy + unit-less invites.
585
- homeUnitRole: z.enum(["member", "leader"]).optional(),
619
+ // Role the invitee takes in homeUnitId on acceptance ('unit_owner' is a
620
+ // deferred structural-leadership grant). Optional/'member' for legacy +
621
+ // unit-less invites.
622
+ homeUnitRole: HomeUnitRoleSchema.optional(),
586
623
  createdAt: z.string(),
587
624
  expiresAt: z.string(),
588
625
  acceptedAt: z.string().optional(),
package/src/org/types.ts CHANGED
@@ -420,11 +420,11 @@ export interface OrgInvite {
420
420
  homeUnitId?: string;
421
421
  /**
422
422
  * Role the invitee takes in `homeUnitId` on acceptance — a plain team member,
423
- * or a structural leader of that unit (a *deferred* leadership grant applied
423
+ * or a unit owner of that unit (a *deferred* leadership grant applied
424
424
  * at acceptance time). Distinct from the org-level {@link role}. Optional:
425
425
  * legacy invites and unit-less invites have none (treated as `member`).
426
426
  */
427
- homeUnitRole?: "member" | "leader";
427
+ homeUnitRole?: "member" | "unit_owner";
428
428
  createdAt: string;
429
429
  expiresAt: string;
430
430
  acceptedAt?: string;
@@ -444,12 +444,12 @@ export interface CreateInviteRequest {
444
444
  homeUnitId?: string;
445
445
  /**
446
446
  * Role the invitee takes in `homeUnitId` on acceptance: a plain team member
447
- * (default), or a structural leader of that unit. `leader` is a *deferred*
447
+ * (default), or a unit owner of that unit. `unit_owner` is a *deferred*
448
448
  * grant — the invite is sent now and the leadership is assigned when the
449
449
  * invitee accepts. Only meaningful when `homeUnitId` is set; the backend
450
- * rejects `leader` without a home unit. Optional/`member` for older callers.
450
+ * rejects `unit_owner` without a home unit. Optional/`member` for older callers.
451
451
  */
452
- homeUnitRole?: "member" | "leader";
452
+ homeUnitRole?: "member" | "unit_owner";
453
453
  }
454
454
 
455
455
  /**
@@ -24,7 +24,7 @@ import { z } from "zod";
24
24
 
25
25
  export const ORG_CHART_ROLES = [
26
26
  "owner",
27
- "leader",
27
+ "unit_owner",
28
28
  "delegate",
29
29
  "admin",
30
30
  ] as const;
@@ -44,7 +44,7 @@ export const OrgChartRoleSchema = z.enum(ORG_CHART_ROLES);
44
44
  */
45
45
  export const ORG_CHART_ROLE_LABELS: Record<OrgChartRole, string> = {
46
46
  owner: "CEO",
47
- leader: "Unit owner",
47
+ unit_owner: "Unit owner",
48
48
  delegate: "Delegate",
49
49
  admin: "Admin",
50
50
  };