@company-semantics/contracts 9.0.0 → 9.2.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 (141) hide show
  1. package/package.json +6 -3
  2. package/src/__tests__/resource-keys.test.ts +30 -23
  3. package/src/admin/authz-simulate.ts +4 -4
  4. package/src/admin/direct-grants.ts +2 -2
  5. package/src/api/generated-spec-hash.ts +2 -2
  6. package/src/api/generated.ts +97 -0
  7. package/src/api/http/routes/ai-chat.ts +3 -3
  8. package/src/api/http/utils/resource-response.ts +5 -2
  9. package/src/api/index.ts +4 -4
  10. package/src/api/primitives.ts +6 -2
  11. package/src/auth/README.md +1 -0
  12. package/src/auth/index.ts +12 -5
  13. package/src/autotune.ts +5 -1
  14. package/src/billing/index.ts +1 -1
  15. package/src/billing/types.ts +1 -1
  16. package/src/chat/README.md +3 -0
  17. package/src/chat/__tests__/runtime-profile.test.ts +68 -48
  18. package/src/chat/index.ts +10 -4
  19. package/src/chat/runtime-profile.ts +25 -10
  20. package/src/chat/schemas.ts +49 -41
  21. package/src/chat/types.ts +48 -42
  22. package/src/ci-envelope/README.md +2 -0
  23. package/src/ci-envelope/__tests__/transitions.test.ts +56 -56
  24. package/src/ci-envelope/index.ts +2 -2
  25. package/src/ci-envelope/types.ts +20 -20
  26. package/src/ci-results/index.ts +2 -2
  27. package/src/ci-results/repo-ci-result.ts +15 -12
  28. package/src/compatibility.ts +6 -6
  29. package/src/content/index.ts +10 -4
  30. package/src/content/schemas.ts +42 -24
  31. package/src/dispatch/index.ts +18 -15
  32. package/src/email/__tests__/registry.test.ts +81 -77
  33. package/src/email/index.ts +3 -3
  34. package/src/email/registry.ts +25 -25
  35. package/src/email/types.ts +43 -43
  36. package/src/errors/index.ts +8 -8
  37. package/src/execution/__tests__/events.test.ts +42 -42
  38. package/src/execution/__tests__/lifecycle.test.ts +192 -190
  39. package/src/execution/__tests__/registry.test.ts +114 -114
  40. package/src/execution/audit-export.ts +4 -4
  41. package/src/execution/errors.ts +7 -7
  42. package/src/execution/event-metadata.ts +4 -4
  43. package/src/execution/events.ts +23 -21
  44. package/src/execution/expiry.ts +5 -5
  45. package/src/execution/hash-chain.ts +2 -2
  46. package/src/execution/index.ts +19 -28
  47. package/src/execution/kinds.ts +7 -7
  48. package/src/execution/lifecycle.ts +33 -33
  49. package/src/execution/registry.ts +63 -63
  50. package/src/execution/schemas.ts +31 -23
  51. package/src/execution/status.ts +45 -26
  52. package/src/execution/summary.ts +16 -17
  53. package/src/execution/timeline-ui.ts +9 -9
  54. package/src/execution/types.ts +31 -25
  55. package/src/generated/openapi-routes.ts +2 -0
  56. package/src/guards/config.ts +22 -18
  57. package/src/guards/index.ts +4 -4
  58. package/src/guards/types.ts +32 -24
  59. package/src/identity/__tests__/avatar.test.ts +68 -59
  60. package/src/identity/avatar.ts +8 -8
  61. package/src/identity/display-name.ts +3 -3
  62. package/src/identity/index.ts +8 -8
  63. package/src/identity/people-org-chart.ts +8 -4
  64. package/src/identity/schemas.ts +28 -18
  65. package/src/identity/types.ts +5 -5
  66. package/src/impersonation/index.ts +5 -5
  67. package/src/impersonation/schemas.ts +15 -9
  68. package/src/impersonation-events.ts +21 -21
  69. package/src/impersonation.ts +25 -24
  70. package/src/index.ts +118 -90
  71. package/src/interfaces/mcp/tools/help.ts +19 -19
  72. package/src/internal-admin.ts +6 -6
  73. package/src/mcp/README.md +2 -0
  74. package/src/mcp/__tests__/capability-graph.test.ts +290 -290
  75. package/src/mcp/capability-graph.ts +42 -40
  76. package/src/mcp/failure-context.ts +1 -3
  77. package/src/mcp/index.ts +69 -56
  78. package/src/mcp/resources.ts +9 -9
  79. package/src/meetings/index.ts +2 -2
  80. package/src/meetings/schemas.ts +51 -34
  81. package/src/message-parts/README.md +2 -0
  82. package/src/message-parts/__tests__/builder.test.ts +142 -142
  83. package/src/message-parts/__tests__/confirmation.test.ts +100 -86
  84. package/src/message-parts/__tests__/preview.test.ts +63 -63
  85. package/src/message-parts/__tests__/wire.test.ts +130 -124
  86. package/src/message-parts/builder.ts +23 -23
  87. package/src/message-parts/confirmation.ts +17 -14
  88. package/src/message-parts/execution.ts +7 -7
  89. package/src/message-parts/index.ts +10 -10
  90. package/src/message-parts/lifecycle.ts +25 -25
  91. package/src/message-parts/preview.ts +30 -30
  92. package/src/message-parts/types.ts +27 -27
  93. package/src/message-parts/wire.ts +24 -24
  94. package/src/mutations.ts +2 -2
  95. package/src/observability.ts +23 -11
  96. package/src/org/__tests__/org-units.test.ts +131 -96
  97. package/src/org/__tests__/tree-ordering.test.ts +57 -37
  98. package/src/org/__tests__/view-scopes.test.ts +40 -40
  99. package/src/org/domain.ts +9 -9
  100. package/src/org/index.ts +31 -21
  101. package/src/org/org-units.ts +34 -20
  102. package/src/org/schemas.ts +261 -124
  103. package/src/org/sharing.ts +17 -13
  104. package/src/org/tree-ordering.ts +3 -1
  105. package/src/org/types.ts +54 -47
  106. package/src/org/view-scopes.ts +9 -9
  107. package/src/permissions/access-levels.ts +7 -2
  108. package/src/permissions/access-source.ts +6 -6
  109. package/src/permissions/index.ts +5 -5
  110. package/src/permissions/orgchart-roles.ts +7 -7
  111. package/src/permissions/permission-introspection.ts +7 -5
  112. package/src/permissions/share-api.ts +19 -9
  113. package/src/pressure.ts +4 -4
  114. package/src/queryIntent.ts +21 -21
  115. package/src/ralph/__tests__/prd-groups.test.ts +159 -159
  116. package/src/ralph/__tests__/prd.test.ts +30 -30
  117. package/src/ralph/index.ts +3 -8
  118. package/src/ralph/prd.ts +33 -33
  119. package/src/ralph/progress.ts +1 -1
  120. package/src/rate-limit/README.md +4 -4
  121. package/src/rate-limit/index.ts +3 -3
  122. package/src/requests.ts +36 -8
  123. package/src/resource-keys.ts +207 -124
  124. package/src/resource-registry.ts +5 -5
  125. package/src/route-builder.ts +3 -3
  126. package/src/safe-mode.ts +2 -2
  127. package/src/security/index.ts +4 -4
  128. package/src/security/org-secrets.ts +13 -9
  129. package/src/security/secret.ts +3 -3
  130. package/src/sse.ts +3 -1
  131. package/src/system/README.md +3 -0
  132. package/src/system/capabilities.ts +22 -23
  133. package/src/system/diagram.ts +45 -45
  134. package/src/system/index.ts +14 -14
  135. package/src/tiers.ts +1 -1
  136. package/src/timeouts.ts +1 -1
  137. package/src/tracing.ts +30 -30
  138. package/src/types/analytics.ts +2 -2
  139. package/src/usage/README.md +3 -0
  140. package/src/usage/execution-types.ts +69 -69
  141. package/src/usage/types.ts +7 -3
@@ -10,9 +10,9 @@
10
10
  * - user-orgs.ts (GET /api/user/orgs, POST /api/user/active-org, /leave)
11
11
  * - scope-check.ts (GET /api/scope/check, POST /api/scope/check-batch)
12
12
  */
13
- import { z } from 'zod';
14
- import { CursorPageSchema } from '../api/primitives';
15
- import { OrgChartRoleSchema } from '../permissions/orgchart-roles';
13
+ import { z } from "zod";
14
+ import { CursorPageSchema } from "../api/primitives";
15
+ import { OrgChartRoleSchema } from "../permissions/orgchart-roles";
16
16
 
17
17
  // ---------------------------------------------------------------------------
18
18
  // Sub-schemas
@@ -22,7 +22,7 @@ const WorkspaceMemberUnitSummarySchema = z.object({
22
22
  unitId: z.string(),
23
23
  unitName: z.string(),
24
24
  unitPath: z.string(),
25
- role: z.enum(['owner', 'manager', 'member']),
25
+ role: z.enum(["owner", "manager", "member"]),
26
26
  });
27
27
 
28
28
  /**
@@ -35,11 +35,11 @@ const WorkspaceMemberUnitSummarySchema = z.object({
35
35
  * the orthogonal membership/delegation axes, not this enum).
36
36
  */
37
37
  export const OrgUnitDesignationSchema = z.enum([
38
- 'whole_org',
39
- 'admin',
40
- 'leader',
41
- 'delegate',
42
- 'member',
38
+ "whole_org",
39
+ "admin",
40
+ "leader",
41
+ "delegate",
42
+ "member",
43
43
  ]);
44
44
  export type OrgUnitDesignation = z.infer<typeof OrgUnitDesignationSchema>;
45
45
 
@@ -48,7 +48,9 @@ export const WorkspaceMemberManagesEntrySchema = z.object({
48
48
  unitName: z.string(),
49
49
  designation: OrgUnitDesignationSchema,
50
50
  });
51
- export type WorkspaceMemberManagesEntry = z.infer<typeof WorkspaceMemberManagesEntrySchema>;
51
+ export type WorkspaceMemberManagesEntry = z.infer<
52
+ typeof WorkspaceMemberManagesEntrySchema
53
+ >;
52
54
 
53
55
  const WorkspaceMemberSchema = z.object({
54
56
  id: z.string(),
@@ -93,7 +95,7 @@ const WorkspaceMemberSchema = z.object({
93
95
  /** True when server truncated `unitMemberships`; detail endpoint returns the full list. */
94
96
  unitMembershipsTruncated: z.boolean(),
95
97
  /** Invite lifecycle status. `null` for members without an invite record. */
96
- inviteStatus: z.enum(['active', 'pending', 'expired']).nullable(),
98
+ inviteStatus: z.enum(["active", "pending", "expired"]).nullable(),
97
99
  });
98
100
 
99
101
  const MemberRecentActionSchema = z.object({
@@ -123,7 +125,7 @@ export type WorkspaceMemberDetail = z.infer<typeof WorkspaceMemberDetailSchema>;
123
125
 
124
126
  export const RoleCatalogEntrySchema = z.object({
125
127
  name: z.string(),
126
- type: z.enum(['system', 'custom']),
128
+ type: z.enum(["system", "custom"]),
127
129
  description: z.string(),
128
130
  scopes: z.array(z.string()),
129
131
  memberCount: z.number().int().nonnegative(),
@@ -147,7 +149,9 @@ export const WorkspaceAccessResponseSchema = z.object({
147
149
  hasAccess: z.boolean(),
148
150
  });
149
151
 
150
- export type WorkspaceAccessResponse = z.infer<typeof WorkspaceAccessResponseSchema>;
152
+ export type WorkspaceAccessResponse = z.infer<
153
+ typeof WorkspaceAccessResponseSchema
154
+ >;
151
155
 
152
156
  // ---------------------------------------------------------------------------
153
157
  // GET /api/workspace
@@ -158,7 +162,7 @@ export const WorkspaceOverviewSchema = z.object({
158
162
  id: z.string(),
159
163
  name: z.string(),
160
164
  slug: z.string(),
161
- type: z.enum(['personal', 'shared']),
165
+ type: z.enum(["personal", "shared"]),
162
166
  logoUrl: z.string().nullable(),
163
167
  owner: WorkspaceOwnerSchema,
164
168
  createdAt: z.string(),
@@ -172,9 +176,13 @@ export type WorkspaceOverview = z.infer<typeof WorkspaceOverviewSchema>;
172
176
  // GET /api/workspace/members
173
177
  // ---------------------------------------------------------------------------
174
178
 
175
- export const WorkspaceMembersResponseSchema = CursorPageSchema(WorkspaceMemberSchema);
179
+ export const WorkspaceMembersResponseSchema = CursorPageSchema(
180
+ WorkspaceMemberSchema,
181
+ );
176
182
 
177
- export type WorkspaceMembersResponse = z.infer<typeof WorkspaceMembersResponseSchema>;
183
+ export type WorkspaceMembersResponse = z.infer<
184
+ typeof WorkspaceMembersResponseSchema
185
+ >;
178
186
 
179
187
  // ---------------------------------------------------------------------------
180
188
  // GET /api/workspace/auth
@@ -185,7 +193,9 @@ const OidcValidationResultSchema = z.object({
185
193
  issuer: z.string().optional(),
186
194
  authorizationEndpoint: z.string().optional(),
187
195
  error: z.string().optional(),
188
- errorCode: z.enum(['UNREACHABLE', 'INVALID_DOCUMENT', 'MISSING_FIELDS', 'SSRF_BLOCKED']).optional(),
196
+ errorCode: z
197
+ .enum(["UNREACHABLE", "INVALID_DOCUMENT", "MISSING_FIELDS", "SSRF_BLOCKED"])
198
+ .optional(),
189
199
  });
190
200
 
191
201
  const SsoDiscoveryConfigSchema = z.object({
@@ -201,14 +211,14 @@ const SsoCredentialStatusSchema = z.object({
201
211
  });
202
212
 
203
213
  const ProviderStatusSchema = z.enum([
204
- 'NOT_CONFIGURED',
205
- 'CONFIG_SAVED',
206
- 'CONFIG_VALID',
207
- 'TEST_SUCCESS',
208
- 'ENABLED',
214
+ "NOT_CONFIGURED",
215
+ "CONFIG_SAVED",
216
+ "CONFIG_VALID",
217
+ "TEST_SUCCESS",
218
+ "ENABLED",
209
219
  ]);
210
220
 
211
- const SsoStepperStepSchema = z.enum(['configure', 'test', 'enable', 'enforce']);
221
+ const SsoStepperStepSchema = z.enum(["configure", "test", "enable", "enforce"]);
212
222
 
213
223
  const SsoOperationalStateSchema = z.object({
214
224
  providerStatus: ProviderStatusSchema,
@@ -221,9 +231,9 @@ const SsoOperationalStateSchema = z.object({
221
231
  lastTestSuccessProvider: z.string().optional(),
222
232
  });
223
233
 
224
- const SsoSetupInfoSchema = SsoDiscoveryConfigSchema.merge(SsoCredentialStatusSchema).merge(
225
- SsoOperationalStateSchema
226
- );
234
+ const SsoSetupInfoSchema = SsoDiscoveryConfigSchema.merge(
235
+ SsoCredentialStatusSchema,
236
+ ).merge(SsoOperationalStateSchema);
227
237
 
228
238
  const SsoReadinessCheckSchema = z.object({
229
239
  code: z.string(),
@@ -253,8 +263,8 @@ const OwnerIdentityInfoSchema = z.object({
253
263
  });
254
264
 
255
265
  const ProviderSuggestionSchema = z.object({
256
- suggestedProvider: z.enum(['google', 'microsoft']).nullable(),
257
- confidence: z.enum(['high', 'low']),
266
+ suggestedProvider: z.enum(["google", "microsoft"]).nullable(),
267
+ confidence: z.enum(["high", "low"]),
258
268
  reason: z.string(),
259
269
  detectedDomain: z.string().optional(),
260
270
  });
@@ -276,7 +286,9 @@ export const WorkspaceAuthConfigSchema = z.object({
276
286
  ssoSetup: SsoSetupInfoSchema.optional(),
277
287
  ssoReadiness: SsoReadinessSchema.optional(),
278
288
  ssoEnforcement: SsoEnforcementStatusSchema.optional(),
279
- workspaceSsoState: z.enum(['SSO_DISABLED', 'SSO_ENABLED', 'SSO_ENFORCED']).optional(),
289
+ workspaceSsoState: z
290
+ .enum(["SSO_DISABLED", "SSO_ENABLED", "SSO_ENFORCED"])
291
+ .optional(),
280
292
  ownerIdentities: z.array(OwnerIdentityInfoSchema).optional(),
281
293
  providerSuggestion: ProviderSuggestionSchema.optional(),
282
294
  });
@@ -293,7 +305,7 @@ export const WorkspaceAuditEventSchema = z.object({
293
305
  actor: z.object({
294
306
  id: z.string(),
295
307
  name: z.string(),
296
- type: z.enum(['user', 'system']),
308
+ type: z.enum(["user", "system"]),
297
309
  }),
298
310
  action: z.string(),
299
311
  summary: z.string(),
@@ -316,15 +328,20 @@ const ResolvedDeptEntitySchema = z.object({
316
328
 
317
329
  export const WorkspaceResolvePathResponseSchema = z.object({
318
330
  layers: z.array(
319
- z.discriminatedUnion('type', [
320
- z.object({ type: z.literal('dept'), entity: ResolvedDeptEntitySchema }),
321
- z.object({ type: z.literal('team'), entity: ResolvedDeptEntitySchema }),
322
- z.object({ type: z.literal('members'), scope: z.enum(['org', 'dept', 'team']) }),
323
- ])
331
+ z.discriminatedUnion("type", [
332
+ z.object({ type: z.literal("dept"), entity: ResolvedDeptEntitySchema }),
333
+ z.object({ type: z.literal("team"), entity: ResolvedDeptEntitySchema }),
334
+ z.object({
335
+ type: z.literal("members"),
336
+ scope: z.enum(["org", "dept", "team"]),
337
+ }),
338
+ ]),
324
339
  ),
325
340
  });
326
341
 
327
- export type WorkspaceResolvePathResponse = z.infer<typeof WorkspaceResolvePathResponseSchema>;
342
+ export type WorkspaceResolvePathResponse = z.infer<
343
+ typeof WorkspaceResolvePathResponseSchema
344
+ >;
328
345
 
329
346
  // ---------------------------------------------------------------------------
330
347
  // PATCH /api/workspace/auth-policy
@@ -354,7 +371,9 @@ export const WorkspaceResyncSlackLogoResponseSchema = z.object({
354
371
  logoUrl: z.string().nullable(),
355
372
  });
356
373
 
357
- export type WorkspaceResyncSlackLogoResponse = z.infer<typeof WorkspaceResyncSlackLogoResponseSchema>;
374
+ export type WorkspaceResyncSlackLogoResponse = z.infer<
375
+ typeof WorkspaceResyncSlackLogoResponseSchema
376
+ >;
358
377
 
359
378
  // ---------------------------------------------------------------------------
360
379
  // POST /api/workspace/auth-policy/test-sso
@@ -372,7 +391,7 @@ export type TestSsoInitiation = z.infer<typeof TestSsoInitiationSchema>;
372
391
  // ---------------------------------------------------------------------------
373
392
 
374
393
  export const TestSsoResultSchema = z.object({
375
- status: z.enum(['pending', 'success', 'failed', 'expired']),
394
+ status: z.enum(["pending", "success", "failed", "expired"]),
376
395
  claims: z
377
396
  .object({
378
397
  sub: z.string(),
@@ -384,7 +403,12 @@ export const TestSsoResultSchema = z.object({
384
403
  identityLinked: z.boolean().optional(),
385
404
  error: z.string().optional(),
386
405
  errorCode: z
387
- .enum(['IDENTITY_CONFLICT', 'DOMAIN_MISMATCH', 'ISSUER_MISMATCH', 'CALLBACK_ERROR'])
406
+ .enum([
407
+ "IDENTITY_CONFLICT",
408
+ "DOMAIN_MISMATCH",
409
+ "ISSUER_MISMATCH",
410
+ "CALLBACK_ERROR",
411
+ ])
388
412
  .optional(),
389
413
  });
390
414
 
@@ -416,7 +440,9 @@ export const ChangeMemberRoleResponseSchema = z.object({
416
440
  message: z.string(),
417
441
  });
418
442
 
419
- export type ChangeMemberRoleResponse = z.infer<typeof ChangeMemberRoleResponseSchema>;
443
+ export type ChangeMemberRoleResponse = z.infer<
444
+ typeof ChangeMemberRoleResponseSchema
445
+ >;
420
446
 
421
447
  // ---------------------------------------------------------------------------
422
448
  // GET /api/user/orgs
@@ -430,7 +456,7 @@ const UserOrgMembershipSchema = z.object({
430
456
  role: OrgChartRoleSchema.nullable(),
431
457
  joinedAt: z.string(),
432
458
  isActive: z.boolean(),
433
- orgType: z.enum(['personal', 'shared']),
459
+ orgType: z.enum(["personal", "shared"]),
434
460
  });
435
461
 
436
462
  export const UserOrgsResponseSchema = z.object({
@@ -479,7 +505,9 @@ export const ScopeCheckBatchResponseSchema = z.object({
479
505
  results: z.record(z.string(), z.object({ hasAccess: z.boolean() })),
480
506
  });
481
507
 
482
- export type ScopeCheckBatchResponse = z.infer<typeof ScopeCheckBatchResponseSchema>;
508
+ export type ScopeCheckBatchResponse = z.infer<
509
+ typeof ScopeCheckBatchResponseSchema
510
+ >;
483
511
 
484
512
  // ---------------------------------------------------------------------------
485
513
  // Invite sub-schema
@@ -489,9 +517,9 @@ const OrgInviteSchema = z.object({
489
517
  id: z.string(),
490
518
  orgId: z.string(),
491
519
  email: z.string(),
492
- role: z.enum(['admin', 'member']),
520
+ role: z.enum(["admin", "member"]),
493
521
  invitedBy: z.object({ id: z.string(), name: z.string() }),
494
- status: z.enum(['pending', 'accepted', 'expired', 'revoked']),
522
+ status: z.enum(["pending", "accepted", "expired", "revoked"]),
495
523
  createdAt: z.string(),
496
524
  expiresAt: z.string(),
497
525
  acceptedAt: z.string().optional(),
@@ -523,12 +551,14 @@ const OrgDomainSchema = z.object({
523
551
  id: z.string(),
524
552
  orgId: z.string(),
525
553
  domain: z.string(),
526
- status: z.enum(['pending', 'verified']),
527
- verificationMethod: z.enum(['dns_txt', 'email', 'idp']),
554
+ status: z.enum(["pending", "verified"]),
555
+ verificationMethod: z.enum(["dns_txt", "email", "idp"]),
528
556
  verificationToken: z.string().optional(),
529
557
  verifiedAt: z.string().nullable(),
530
558
  createdAt: z.string(),
531
- verifiedBy: z.object({ id: z.string(), name: z.string(), email: z.string() }).optional(),
559
+ verifiedBy: z
560
+ .object({ id: z.string(), name: z.string(), email: z.string() })
561
+ .optional(),
532
562
  });
533
563
 
534
564
  // ---------------------------------------------------------------------------
@@ -554,7 +584,7 @@ export type DomainListResponse = z.infer<typeof DomainListResponseSchema>;
554
584
 
555
585
  export const OrgBillingResponseSchema = z.object({
556
586
  planName: z.string(),
557
- planStatus: z.enum(['active', 'trialing', 'past_due', 'canceled']),
587
+ planStatus: z.enum(["active", "trialing", "past_due", "canceled"]),
558
588
  billingCadence: z.string(),
559
589
  seatCount: z.number(),
560
590
  seatLimit: z.number(),
@@ -570,7 +600,7 @@ export type OrgBillingResponse = z.infer<typeof OrgBillingResponseSchema>;
570
600
  const MemberClassificationSchema = z.object({
571
601
  userId: z.string(),
572
602
  email: z.string(),
573
- suggestedFate: z.enum(['REMOVE_FROM_ORG', 'DELETE_ACCOUNT', 'BLOCKED']),
603
+ suggestedFate: z.enum(["REMOVE_FROM_ORG", "DELETE_ACCOUNT", "BLOCKED"]),
574
604
  reason: z.string(),
575
605
  });
576
606
 
@@ -595,7 +625,9 @@ export const OwnershipTransferResponseSchema = z.object({
595
625
  message: z.string(),
596
626
  });
597
627
 
598
- export type OwnershipTransferResponse = z.infer<typeof OwnershipTransferResponseSchema>;
628
+ export type OwnershipTransferResponse = z.infer<
629
+ typeof OwnershipTransferResponseSchema
630
+ >;
599
631
 
600
632
  // ---------------------------------------------------------------------------
601
633
  // POST /api/org/transfer-ownership/preview
@@ -610,7 +642,9 @@ export const OwnershipTransferPreviewSchema = z.object({
610
642
  token: z.string(),
611
643
  });
612
644
 
613
- export type OwnershipTransferPreview = z.infer<typeof OwnershipTransferPreviewSchema>;
645
+ export type OwnershipTransferPreview = z.infer<
646
+ typeof OwnershipTransferPreviewSchema
647
+ >;
614
648
 
615
649
  // ---------------------------------------------------------------------------
616
650
  // GET /api/org/system-events
@@ -637,7 +671,9 @@ export const AcknowledgeSystemEventResponseSchema = z.object({
637
671
  success: z.literal(true),
638
672
  });
639
673
 
640
- export type AcknowledgeSystemEventResponse = z.infer<typeof AcknowledgeSystemEventResponseSchema>;
674
+ export type AcknowledgeSystemEventResponse = z.infer<
675
+ typeof AcknowledgeSystemEventResponseSchema
676
+ >;
641
677
 
642
678
  // ---------------------------------------------------------------------------
643
679
  // GET /api/orgs/:orgId/budget-config
@@ -723,28 +759,36 @@ export type OrgUsageResponse = z.infer<typeof OrgUsageResponseSchema>;
723
759
  // ---------------------------------------------------------------------------
724
760
 
725
761
  export const OrgUnitClassificationSchema = z.enum([
726
- 'execution_unit',
727
- 'org_container',
728
- 'leadership',
729
- 'custom',
762
+ "execution_unit",
763
+ "org_container",
764
+ "leadership",
765
+ "custom",
730
766
  ]);
731
767
 
732
768
  export const OrgUnitSyncModeSchema = z.enum([
733
- 'manual_only',
734
- 'synced_readonly',
735
- 'synced_with_overrides',
769
+ "manual_only",
770
+ "synced_readonly",
771
+ "synced_with_overrides",
736
772
  ]);
737
773
 
738
- export const OrgUnitVisibilitySchema = z.enum(['public', 'private', 'restricted']);
774
+ export const OrgUnitVisibilitySchema = z.enum([
775
+ "public",
776
+ "private",
777
+ "restricted",
778
+ ]);
739
779
 
740
780
  export const OrgUnitRelationshipTypeSchema = z.enum([
741
- 'collaborates_with',
742
- 'reports_to',
743
- 'depends_on',
744
- 'custom',
781
+ "collaborates_with",
782
+ "reports_to",
783
+ "depends_on",
784
+ "custom",
745
785
  ]);
746
786
 
747
- export const OrgUnitRelationshipRoleSchema = z.enum(['owner', 'participant', 'supporting']);
787
+ export const OrgUnitRelationshipRoleSchema = z.enum([
788
+ "owner",
789
+ "participant",
790
+ "supporting",
791
+ ]);
748
792
 
749
793
  /**
750
794
  * Positional slot a member holds in the org-unit tree. ORTHOGONAL to the
@@ -752,36 +796,40 @@ export const OrgUnitRelationshipRoleSchema = z.enum(['owner', 'participant', 'su
752
796
  * not the derived policy role). Level is encoded in the value (l1…l5).
753
797
  */
754
798
  export const UnitMembershipRoleSchema = z.enum([
755
- 'member',
756
- 'l1_unit_owner',
757
- 'l2_unit_owner',
758
- 'l3_unit_owner',
759
- 'l4_unit_owner',
760
- 'l5_unit_owner',
799
+ "member",
800
+ "l1_unit_owner",
801
+ "l2_unit_owner",
802
+ "l3_unit_owner",
803
+ "l4_unit_owner",
804
+ "l5_unit_owner",
761
805
  ]);
762
806
 
763
807
  export type UnitMembershipRole = z.infer<typeof UnitMembershipRoleSchema>;
764
808
 
765
- export const OrgUnitMembershipStatusSchema = z.enum(['active', 'pending', 'removed']);
809
+ export const OrgUnitMembershipStatusSchema = z.enum([
810
+ "active",
811
+ "pending",
812
+ "removed",
813
+ ]);
766
814
 
767
815
  export const OrgUnitMembershipSourceSchema = z.enum([
768
- 'manual',
769
- 'google_groups',
770
- 'scim',
771
- 'hris',
816
+ "manual",
817
+ "google_groups",
818
+ "scim",
819
+ "hris",
772
820
  ]);
773
821
 
774
822
  export const OrgUnitErrorCodeSchema = z.enum([
775
- 'CYCLE_BLOCKED',
776
- 'DEPTH_EXCEEDED',
777
- 'TARGET_ARCHIVED',
778
- 'ROOT_HAS_NO_PARENT',
779
- 'PARENT_ARCHIVED',
780
- 'SLUG_TAKEN',
781
- 'CROSS_ORG_REPARENT',
782
- 'ORDERKEY_CONFLICT',
783
- 'SIBLING_NOT_FOUND',
784
- 'SIBLINGS_DIFFERENT_PARENT',
823
+ "CYCLE_BLOCKED",
824
+ "DEPTH_EXCEEDED",
825
+ "TARGET_ARCHIVED",
826
+ "ROOT_HAS_NO_PARENT",
827
+ "PARENT_ARCHIVED",
828
+ "SLUG_TAKEN",
829
+ "CROSS_ORG_REPARENT",
830
+ "ORDERKEY_CONFLICT",
831
+ "SIBLING_NOT_FOUND",
832
+ "SIBLINGS_DIFFERENT_PARENT",
785
833
  ]);
786
834
 
787
835
  export const OrgUnitSchema = z.object({
@@ -853,32 +901,32 @@ export const OrgUnitMembershipSchema = z.object({
853
901
  * canonicalized onto delegations.
854
902
  */
855
903
  export const AuthoritySourceSchema = z.enum([
856
- 'structural',
857
- 'delegated',
858
- 'org_admin',
904
+ "structural",
905
+ "delegated",
906
+ "org_admin",
859
907
  ]);
860
908
  export type AuthoritySource = z.infer<typeof AuthoritySourceSchema>;
861
909
 
862
910
  export const AuthorityOriginSchema = z.enum([
863
- 'topology',
864
- 'delegation',
865
- 'administrative_override',
911
+ "topology",
912
+ "delegation",
913
+ "administrative_override",
866
914
  ]);
867
915
  export type AuthorityOrigin = z.infer<typeof AuthorityOriginSchema>;
868
916
 
869
- export const AuthorityConfidenceSchema = z.enum(['authoritative', 'inferred']);
917
+ export const AuthorityConfidenceSchema = z.enum(["authoritative", "inferred"]);
870
918
  export type AuthorityConfidence = z.infer<typeof AuthorityConfidenceSchema>;
871
919
 
872
920
  /** How the authority arose. */
873
921
  export const AuthorityMechanismSchema = z.enum([
874
- 'structural',
875
- 'delegated',
876
- 'rbac',
922
+ "structural",
923
+ "delegated",
924
+ "rbac",
877
925
  ]);
878
926
  export type AuthorityMechanism = z.infer<typeof AuthorityMechanismSchema>;
879
927
 
880
928
  /** Whether the grant lives on the target unit or is inherited from an ancestor. */
881
- export const AuthorityLocalitySchema = z.enum(['local', 'inherited']);
929
+ export const AuthorityLocalitySchema = z.enum(["local", "inherited"]);
882
930
  export type AuthorityLocality = z.infer<typeof AuthorityLocalitySchema>;
883
931
 
884
932
  /**
@@ -886,7 +934,7 @@ export type AuthorityLocality = z.infer<typeof AuthorityLocalitySchema>;
886
934
  * - `derived`: change the upstream source instead (the org chart, RBAC roles).
887
935
  * - `user_managed`: removable from this UI.
888
936
  */
889
- export const AuthorityMutabilitySchema = z.enum(['derived', 'user_managed']);
937
+ export const AuthorityMutabilitySchema = z.enum(["derived", "user_managed"]);
890
938
  export type AuthorityMutability = z.infer<typeof AuthorityMutabilitySchema>;
891
939
 
892
940
  export const OwnerAuthoritySchema = z.object({
@@ -953,10 +1001,10 @@ const uniqueByUserId = (arr: ReadonlyArray<{ userId: string }>): boolean =>
953
1001
  export const OrgUnitOwnersResponseSchema = z.object({
954
1002
  owners: z
955
1003
  .array(OrgUnitOwnerSchema)
956
- .refine(uniqueByUserId, { message: 'duplicate userId in owners' }),
1004
+ .refine(uniqueByUserId, { message: "duplicate userId in owners" }),
957
1005
  inherited: z
958
1006
  .array(OrgUnitOwnerSchema)
959
- .refine(uniqueByUserId, { message: 'duplicate userId in inherited' })
1007
+ .refine(uniqueByUserId, { message: "duplicate userId in inherited" })
960
1008
  .optional(),
961
1009
  });
962
1010
  export type OrgUnitOwnersResponse = z.infer<typeof OrgUnitOwnersResponseSchema>;
@@ -969,7 +1017,7 @@ export const DelegationSchema = z.object({
969
1017
  grantedBy: z.string().uuid().nullable(),
970
1018
  grantedAt: z.string(),
971
1019
  revokedAt: z.string().nullable(),
972
- status: z.enum(['active', 'revoked']),
1020
+ status: z.enum(["active", "revoked"]),
973
1021
  note: z.string().nullable(),
974
1022
  /**
975
1023
  * ISO-8601 timestamp at which the delegation stops conferring authority, or
@@ -997,7 +1045,9 @@ export const CreateDelegationRequestSchema = z.object({
997
1045
  */
998
1046
  notify: z.boolean().optional(),
999
1047
  });
1000
- export type CreateDelegationRequest = z.infer<typeof CreateDelegationRequestSchema>;
1048
+ export type CreateDelegationRequest = z.infer<
1049
+ typeof CreateDelegationRequestSchema
1050
+ >;
1001
1051
 
1002
1052
  /**
1003
1053
  * Change a delegation's expiry without revoking it: extend, shorten, or clear
@@ -1007,12 +1057,16 @@ export type CreateDelegationRequest = z.infer<typeof CreateDelegationRequestSche
1007
1057
  export const UpdateDelegationRequestSchema = z.object({
1008
1058
  expiresAt: z.string().datetime().nullable(),
1009
1059
  });
1010
- export type UpdateDelegationRequest = z.infer<typeof UpdateDelegationRequestSchema>;
1060
+ export type UpdateDelegationRequest = z.infer<
1061
+ typeof UpdateDelegationRequestSchema
1062
+ >;
1011
1063
 
1012
1064
  export const DelegationListResponseSchema = z.object({
1013
1065
  delegations: z.array(DelegationSchema),
1014
1066
  });
1015
- export type DelegationListResponse = z.infer<typeof DelegationListResponseSchema>;
1067
+ export type DelegationListResponse = z.infer<
1068
+ typeof DelegationListResponseSchema
1069
+ >;
1016
1070
 
1017
1071
  export const OrgUnitRelationshipSchema = z.object({
1018
1072
  id: z.string().uuid(),
@@ -1027,11 +1081,11 @@ export const OrgUnitRelationshipSchema = z.object({
1027
1081
  });
1028
1082
 
1029
1083
  export const OrgLevelIconSchema = z.enum([
1030
- 'city',
1031
- 'buildings',
1032
- 'users-four',
1033
- 'users-three',
1034
- 'users',
1084
+ "city",
1085
+ "buildings",
1086
+ "users-four",
1087
+ "users-three",
1088
+ "users",
1035
1089
  ]);
1036
1090
 
1037
1091
  export const OrgLevelConfigSchema = z.object({
@@ -1116,12 +1170,14 @@ export const ListOrgUnitPermissionsResponseSchema = z.object({
1116
1170
  // consumers must satisfy.
1117
1171
  // ---------------------------------------------------------------------------
1118
1172
 
1119
- export const UpdateOrgUnitRequestSchema = z.object({
1120
- name: z.string().min(1).max(255).optional(),
1121
- description: z.string().max(2000).nullable().optional(),
1122
- }).refine((v) => v.name !== undefined || v.description !== undefined, {
1123
- message: 'at least one of name or description must be provided',
1124
- });
1173
+ export const UpdateOrgUnitRequestSchema = z
1174
+ .object({
1175
+ name: z.string().min(1).max(255).optional(),
1176
+ description: z.string().max(2000).nullable().optional(),
1177
+ })
1178
+ .refine((v) => v.name !== undefined || v.description !== undefined, {
1179
+ message: "at least one of name or description must be provided",
1180
+ });
1125
1181
 
1126
1182
  export const UpdateOrgUnitResponseSchema = z.object({ unit: OrgUnitSchema });
1127
1183
 
@@ -1136,14 +1192,95 @@ export type OrgLevelIcon = z.infer<typeof OrgLevelIconSchema>;
1136
1192
  export type OrgUnitResponse = z.infer<typeof OrgUnitResponseSchema>;
1137
1193
  export type OrgUnitTreeResponse = z.infer<typeof OrgUnitTreeResponseSchema>;
1138
1194
  export type MissingAtNextLevel = z.infer<typeof MissingAtNextLevelSchema>;
1139
- export type OrgUnitChildrenResponse = z.infer<typeof OrgUnitChildrenResponseSchema>;
1140
- export type OrgUnitAncestorsResponse = z.infer<typeof OrgUnitAncestorsResponseSchema>;
1141
- export type OrgUnitDescendantsResponse = z.infer<typeof OrgUnitDescendantsResponseSchema>;
1142
- export type OrgUnitRelationshipsResponse = z.infer<typeof OrgUnitRelationshipsResponseSchema>;
1143
- export type OrgLevelConfigResponse = z.infer<typeof OrgLevelConfigResponseSchema>;
1144
- export type OrgUnitMembershipResponse = z.infer<typeof OrgUnitMembershipResponseSchema>;
1145
- export type OrgUnitMembershipListResponse = z.infer<typeof OrgUnitMembershipListResponseSchema>;
1146
- export type OrgUnitPermissionsEntry = z.infer<typeof OrgUnitPermissionsEntrySchema>;
1147
- export type ListOrgUnitPermissionsResponse = z.infer<typeof ListOrgUnitPermissionsResponseSchema>;
1195
+ export type OrgUnitChildrenResponse = z.infer<
1196
+ typeof OrgUnitChildrenResponseSchema
1197
+ >;
1198
+ export type OrgUnitAncestorsResponse = z.infer<
1199
+ typeof OrgUnitAncestorsResponseSchema
1200
+ >;
1201
+ export type OrgUnitDescendantsResponse = z.infer<
1202
+ typeof OrgUnitDescendantsResponseSchema
1203
+ >;
1204
+ export type OrgUnitRelationshipsResponse = z.infer<
1205
+ typeof OrgUnitRelationshipsResponseSchema
1206
+ >;
1207
+ export type OrgLevelConfigResponse = z.infer<
1208
+ typeof OrgLevelConfigResponseSchema
1209
+ >;
1210
+ export type OrgUnitMembershipResponse = z.infer<
1211
+ typeof OrgUnitMembershipResponseSchema
1212
+ >;
1213
+ export type OrgUnitMembershipListResponse = z.infer<
1214
+ typeof OrgUnitMembershipListResponseSchema
1215
+ >;
1216
+ export type OrgUnitPermissionsEntry = z.infer<
1217
+ typeof OrgUnitPermissionsEntrySchema
1218
+ >;
1219
+ export type ListOrgUnitPermissionsResponse = z.infer<
1220
+ typeof ListOrgUnitPermissionsResponseSchema
1221
+ >;
1148
1222
  export type UpdateOrgUnitRequest = z.infer<typeof UpdateOrgUnitRequestSchema>;
1149
1223
  export type UpdateOrgUnitResponse = z.infer<typeof UpdateOrgUnitResponseSchema>;
1224
+
1225
+ // =============================================================================
1226
+ // Mutation Capabilities (GET /api/capabilities) — ADR-BE-241 / PRD-00707 F4
1227
+ // =============================================================================
1228
+ // Canonical home for the viewer's resolved mutation-capability projection. The
1229
+ // backend derives it (src/capabilities/derive.ts) and validates the response
1230
+ // against CapabilitiesResponseSchema via sendValidated; the frontend reads the
1231
+ // inferred types to render lock/allow affordances. Previously duplicated as a
1232
+ // backend-local Zod + hand-written frontend interfaces — unified here.
1233
+
1234
+ /** Scope identifiers are dot-namespaced strings (see backend trust/scopes.ts). */
1235
+ const RequiredScopeSchema = z.string();
1236
+
1237
+ /** A mutable field's gate: editable, or locked with attribution (sso vs rbac). */
1238
+ export const FieldCapabilitySchema = z.object({
1239
+ state: z.enum(["editable", "locked"]),
1240
+ reason: z.enum(["sso", "rbac"]).optional(),
1241
+ requiredScope: RequiredScopeSchema.optional(),
1242
+ });
1243
+
1244
+ /** An action's gate: allowed, or blocked with the scope that would unlock it. */
1245
+ export const ActionCapabilitySchema = z.object({
1246
+ state: z.enum(["allowed", "blocked"]),
1247
+ requiredScope: RequiredScopeSchema.optional(),
1248
+ });
1249
+
1250
+ /**
1251
+ * The single validated capability surface the UI reads. Every sub-object is
1252
+ * optional, matching the partial derivation in deriveCapabilities() (actions/org
1253
+ * are present only when scopes resolved).
1254
+ */
1255
+ export const CapabilitiesResponseSchema = z.object({
1256
+ profile: z
1257
+ .object({
1258
+ fullName: FieldCapabilitySchema,
1259
+ preferredName: FieldCapabilitySchema,
1260
+ })
1261
+ .optional(),
1262
+ org: z
1263
+ .object({
1264
+ name: FieldCapabilitySchema,
1265
+ })
1266
+ .optional(),
1267
+ actions: z
1268
+ .object({
1269
+ members: z.object({
1270
+ invite: ActionCapabilitySchema,
1271
+ remove: ActionCapabilitySchema,
1272
+ changeRole: ActionCapabilitySchema,
1273
+ }),
1274
+ orgAdmins: z.object({
1275
+ manage: ActionCapabilitySchema,
1276
+ }),
1277
+ orgUnit: z.object({
1278
+ manage: ActionCapabilitySchema,
1279
+ }),
1280
+ })
1281
+ .optional(),
1282
+ });
1283
+
1284
+ export type FieldCapability = z.infer<typeof FieldCapabilitySchema>;
1285
+ export type ActionCapability = z.infer<typeof ActionCapabilitySchema>;
1286
+ export type CapabilitiesResponse = z.infer<typeof CapabilitiesResponseSchema>;