@company-semantics/contracts 63.3.0 → 63.5.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": "63.3.0",
3
+ "version": "63.5.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,3 +1,3 @@
1
1
  // AUTO-GENERATED — do not edit. Run pnpm generate:spec-hash to regenerate.
2
- export const SPEC_HASH = '191634e28786' as const;
3
- export const SPEC_HASH_FULL = '191634e28786b02448431968a7b8f6f3fbbcd5f5cadc9f48e3067511a790c38b' as const;
2
+ export const SPEC_HASH = '0d2acd64eacb' as const;
3
+ export const SPEC_HASH_FULL = '0d2acd64eacb1b9c0e7433170aa68300d2ad9197870f35b3b420f55d9e597abf' as const;
@@ -264,6 +264,23 @@ export interface paths {
264
264
  patch?: never;
265
265
  trace?: never;
266
266
  };
267
+ "/api/chats/mentionable": {
268
+ parameters: {
269
+ query?: never;
270
+ header?: never;
271
+ path?: never;
272
+ cookie?: never;
273
+ };
274
+ /** List the principals the chat composer may mention */
275
+ get: operations["listChatMentionable"];
276
+ put?: never;
277
+ post?: never;
278
+ delete?: never;
279
+ options?: never;
280
+ head?: never;
281
+ patch?: never;
282
+ trace?: never;
283
+ };
267
284
  "/api/chats/{id}": {
268
285
  parameters: {
269
286
  query?: never;
@@ -4087,6 +4104,20 @@ export interface components {
4087
4104
  ChatByInteractionResponse: {
4088
4105
  chatId: string;
4089
4106
  };
4107
+ ChatMentionableResponse: {
4108
+ items: {
4109
+ principal: {
4110
+ /** @constant */
4111
+ kind: "user";
4112
+ userId: string;
4113
+ } | {
4114
+ /** @constant */
4115
+ kind: "agent";
4116
+ };
4117
+ displayName: string;
4118
+ avatarUrl: string | null;
4119
+ }[];
4120
+ };
4090
4121
  GetChatResponse: {
4091
4122
  chat: {
4092
4123
  id: string;
@@ -4324,6 +4355,19 @@ export interface components {
4324
4355
  role: "user";
4325
4356
  parts: unknown[];
4326
4357
  };
4358
+ mentions?: ({
4359
+ /** @constant */
4360
+ kind: "user";
4361
+ /** Format: uuid */
4362
+ userId: string;
4363
+ startOffset: number;
4364
+ endOffset: number;
4365
+ } | {
4366
+ /** @constant */
4367
+ kind: "agent";
4368
+ startOffset: number;
4369
+ endOffset: number;
4370
+ })[];
4327
4371
  messages?: unknown;
4328
4372
  runtimeProfile?: string;
4329
4373
  pageContext?: {
@@ -5377,6 +5421,7 @@ export interface components {
5377
5421
  };
5378
5422
  };
5379
5423
  };
5424
+ chatMentions: boolean;
5380
5425
  };
5381
5426
  OrgStructureReviewQueue: {
5382
5427
  items: {
@@ -5972,7 +6017,7 @@ export interface components {
5972
6017
  /** Format: uuid */
5973
6018
  userId: string;
5974
6019
  /** @enum {string} */
5975
- membershipRole: "member" | "l1_unit_owner" | "l2_unit_owner" | "l3_unit_owner" | "l4_unit_owner" | "l5_unit_owner";
6020
+ membershipRole: "member" | "l1_unit_owner" | "l2_unit_owner" | "l3_unit_owner" | "l4_unit_owner" | "l5_unit_owner" | "l6_unit_owner" | "l7_unit_owner" | "l8_unit_owner" | "l9_unit_owner" | "l10_unit_owner" | "l11_unit_owner" | "l12_unit_owner" | "l13_unit_owner" | "l14_unit_owner" | "l15_unit_owner" | "l16_unit_owner" | "l17_unit_owner" | "l18_unit_owner" | "l19_unit_owner" | "l20_unit_owner";
5976
6021
  /** Format: uuid */
5977
6022
  inheritedFromUnitId: string;
5978
6023
  inheritedFromUnitName: string;
@@ -6108,7 +6153,7 @@ export interface components {
6108
6153
  /** Format: uuid */
6109
6154
  userId: string;
6110
6155
  /** @enum {string} */
6111
- membershipRole: "member" | "l1_unit_owner" | "l2_unit_owner" | "l3_unit_owner" | "l4_unit_owner" | "l5_unit_owner";
6156
+ membershipRole: "member" | "l1_unit_owner" | "l2_unit_owner" | "l3_unit_owner" | "l4_unit_owner" | "l5_unit_owner" | "l6_unit_owner" | "l7_unit_owner" | "l8_unit_owner" | "l9_unit_owner" | "l10_unit_owner" | "l11_unit_owner" | "l12_unit_owner" | "l13_unit_owner" | "l14_unit_owner" | "l15_unit_owner" | "l16_unit_owner" | "l17_unit_owner" | "l18_unit_owner" | "l19_unit_owner" | "l20_unit_owner";
6112
6157
  /** @enum {string} */
6113
6158
  status: "active" | "pending" | "removed";
6114
6159
  /** @enum {string} */
@@ -6129,7 +6174,7 @@ export interface components {
6129
6174
  /** Format: uuid */
6130
6175
  userId: string;
6131
6176
  /** @enum {string} */
6132
- membershipRole: "member" | "l1_unit_owner" | "l2_unit_owner" | "l3_unit_owner" | "l4_unit_owner" | "l5_unit_owner";
6177
+ membershipRole: "member" | "l1_unit_owner" | "l2_unit_owner" | "l3_unit_owner" | "l4_unit_owner" | "l5_unit_owner" | "l6_unit_owner" | "l7_unit_owner" | "l8_unit_owner" | "l9_unit_owner" | "l10_unit_owner" | "l11_unit_owner" | "l12_unit_owner" | "l13_unit_owner" | "l14_unit_owner" | "l15_unit_owner" | "l16_unit_owner" | "l17_unit_owner" | "l18_unit_owner" | "l19_unit_owner" | "l20_unit_owner";
6133
6178
  /** @enum {string} */
6134
6179
  status: "active" | "pending" | "removed";
6135
6180
  /** @enum {string} */
@@ -7781,6 +7826,28 @@ export interface operations {
7781
7826
  };
7782
7827
  };
7783
7828
  };
7829
+ listChatMentionable: {
7830
+ parameters: {
7831
+ query?: {
7832
+ q?: string;
7833
+ };
7834
+ header?: never;
7835
+ path?: never;
7836
+ cookie?: never;
7837
+ };
7838
+ requestBody?: never;
7839
+ responses: {
7840
+ /** @description The mention candidates the composer may offer */
7841
+ 200: {
7842
+ headers: {
7843
+ [name: string]: unknown;
7844
+ };
7845
+ content: {
7846
+ "application/json": components["schemas"]["ChatMentionableResponse"];
7847
+ };
7848
+ };
7849
+ };
7850
+ };
7784
7851
  getChat: {
7785
7852
  parameters: {
7786
7853
  query?: never;
@@ -11521,7 +11588,7 @@ export interface operations {
11521
11588
  /** Format: uuid */
11522
11589
  userId: string;
11523
11590
  /** @enum {string} */
11524
- role?: "member" | "l1_unit_owner" | "l2_unit_owner" | "l3_unit_owner" | "l4_unit_owner" | "l5_unit_owner";
11591
+ role?: "member" | "l1_unit_owner" | "l2_unit_owner" | "l3_unit_owner" | "l4_unit_owner" | "l5_unit_owner" | "l6_unit_owner" | "l7_unit_owner" | "l8_unit_owner" | "l9_unit_owner" | "l10_unit_owner" | "l11_unit_owner" | "l12_unit_owner" | "l13_unit_owner" | "l14_unit_owner" | "l15_unit_owner" | "l16_unit_owner" | "l17_unit_owner" | "l18_unit_owner" | "l19_unit_owner" | "l20_unit_owner";
11525
11592
  };
11526
11593
  };
11527
11594
  };
@@ -11551,7 +11618,7 @@ export interface operations {
11551
11618
  content: {
11552
11619
  "application/json": {
11553
11620
  /** @enum {string} */
11554
- role: "member" | "l1_unit_owner" | "l2_unit_owner" | "l3_unit_owner" | "l4_unit_owner" | "l5_unit_owner";
11621
+ role: "member" | "l1_unit_owner" | "l2_unit_owner" | "l3_unit_owner" | "l4_unit_owner" | "l5_unit_owner" | "l6_unit_owner" | "l7_unit_owner" | "l8_unit_owner" | "l9_unit_owner" | "l10_unit_owner" | "l11_unit_owner" | "l12_unit_owner" | "l13_unit_owner" | "l14_unit_owner" | "l15_unit_owner" | "l16_unit_owner" | "l17_unit_owner" | "l18_unit_owner" | "l19_unit_owner" | "l20_unit_owner";
11555
11622
  };
11556
11623
  };
11557
11624
  };
@@ -15,6 +15,7 @@ export const openApiRoutes = {
15
15
  '/api/chats': ['GET', 'POST'],
16
16
  '/api/chats/by-interaction/{interactionId}': ['GET'],
17
17
  '/api/chats/events': ['GET'],
18
+ '/api/chats/mentionable': ['GET'],
18
19
  '/api/chats/proactive/{eventId}': ['GET'],
19
20
  '/api/chats/{chatId}/shares': ['GET', 'POST'],
20
21
  '/api/chats/{id}': ['DELETE', 'GET', 'PATCH'],
package/src/index.ts CHANGED
@@ -683,6 +683,8 @@ export {
683
683
  getViewScope,
684
684
  TRANSFER_RESPONSIBILITIES,
685
685
  IDENTITY_TRUST_LEVEL_LABELS,
686
+ ORG_UNIT_DESIGNED_MAX_DEPTH,
687
+ ORG_UNIT_ABSOLUTE_MAX_DEPTH,
686
688
  } from "./org/index";
687
689
 
688
690
  // View authorization types (Phase 5 - ADR-APP-013)
package/src/org/README.md CHANGED
@@ -193,6 +193,8 @@ Shared type vocabulary for organization ownership, type classification, and tran
193
193
  - `MissingAtNextLevel` _(type)_
194
194
  - `MissingAtNextLevelSchema` — Active users home directly at this unit who have no level-(depth+1) home assignment within its subtree.
195
195
  - `ORG_UNITS_ROUTES` — Canonical route path constants for the `/api/org-units` surface.
196
+ - `ORG_UNIT_ABSOLUTE_MAX_DEPTH` — Hard ceiling mirrored by the `org_units_depth_max` CHECK; ingest-only past designed.
197
+ - `ORG_UNIT_DESIGNED_MAX_DEPTH` — Depth a human may build from scratch; the UI ceiling for a fresh org.
196
198
  - `Occupancy` _(type)_
197
199
  - `OccupancySchema`
198
200
  - `OccupancyStatus` _(type)_
@@ -0,0 +1,64 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import {
3
+ ORG_UNIT_ABSOLUTE_MAX_DEPTH,
4
+ ORG_UNIT_DESIGNED_MAX_DEPTH,
5
+ } from "../../index.js";
6
+ import {
7
+ OrgLevelConfigSchema,
8
+ OrgUnitTreeNodeSchema,
9
+ UnitMembershipRoleSchema,
10
+ } from "../schemas.js";
11
+
12
+ const UUID_A = "11111111-1111-4111-8111-111111111111";
13
+
14
+ describe("org-unit depth ceilings", () => {
15
+ it("designed stays below absolute and both reach the package root", () => {
16
+ expect(ORG_UNIT_DESIGNED_MAX_DEPTH).toBe(5);
17
+ expect(ORG_UNIT_ABSOLUTE_MAX_DEPTH).toBe(20);
18
+ expect(ORG_UNIT_DESIGNED_MAX_DEPTH).toBeLessThan(
19
+ ORG_UNIT_ABSOLUTE_MAX_DEPTH,
20
+ );
21
+ });
22
+
23
+ it("OrgLevelConfigSchema accepts every depth up to the absolute ceiling", () => {
24
+ const row = (depth: number) => ({
25
+ orgId: UUID_A,
26
+ depth,
27
+ label: "Pod",
28
+ labelPlural: "Pods",
29
+ icon: "users",
30
+ createdAt: "2026-01-01T00:00:00.000Z",
31
+ updatedAt: "2026-01-01T00:00:00.000Z",
32
+ });
33
+ expect(
34
+ OrgLevelConfigSchema.safeParse(row(ORG_UNIT_DESIGNED_MAX_DEPTH + 1))
35
+ .success,
36
+ ).toBe(true);
37
+ expect(
38
+ OrgLevelConfigSchema.safeParse(row(ORG_UNIT_ABSOLUTE_MAX_DEPTH)).success,
39
+ ).toBe(true);
40
+ expect(
41
+ OrgLevelConfigSchema.safeParse(row(ORG_UNIT_ABSOLUTE_MAX_DEPTH + 1))
42
+ .success,
43
+ ).toBe(false);
44
+ });
45
+
46
+ it("OrgUnitTreeNodeSchema bounds depth by the absolute ceiling, not the designed one", () => {
47
+ const shape = OrgUnitTreeNodeSchema.shape.depth;
48
+ expect(shape.safeParse(ORG_UNIT_DESIGNED_MAX_DEPTH + 1).success).toBe(true);
49
+ expect(shape.safeParse(ORG_UNIT_ABSOLUTE_MAX_DEPTH).success).toBe(true);
50
+ expect(shape.safeParse(ORG_UNIT_ABSOLUTE_MAX_DEPTH + 1).success).toBe(
51
+ false,
52
+ );
53
+ });
54
+
55
+ it("carries one unit-owner membership role per depth up to the absolute ceiling", () => {
56
+ const owners = UnitMembershipRoleSchema.options.filter(
57
+ (r) => r !== "member",
58
+ );
59
+ expect(owners).toHaveLength(ORG_UNIT_ABSOLUTE_MAX_DEPTH);
60
+ for (let depth = 1; depth <= ORG_UNIT_ABSOLUTE_MAX_DEPTH; depth++) {
61
+ expect(owners).toContain(`l${depth}_unit_owner`);
62
+ }
63
+ });
64
+ });
@@ -90,7 +90,7 @@ describe("OrgUnitSchema", () => {
90
90
  });
91
91
 
92
92
  describe("OrgUnitTreeNodeSchema", () => {
93
- it("requires depth 1..5", () => {
93
+ it("requires depth 1..20 (absolute ceiling)", () => {
94
94
  const base = {
95
95
  ...makeUnit(),
96
96
  depth: 3,
@@ -102,7 +102,10 @@ describe("OrgUnitTreeNodeSchema", () => {
102
102
  };
103
103
  expect(() => OrgUnitTreeNodeSchema.parse(base)).not.toThrow();
104
104
  expect(() => OrgUnitTreeNodeSchema.parse({ ...base, depth: 0 })).toThrow();
105
- expect(() => OrgUnitTreeNodeSchema.parse({ ...base, depth: 6 })).toThrow();
105
+ expect(() =>
106
+ OrgUnitTreeNodeSchema.parse({ ...base, depth: 6 }),
107
+ ).not.toThrow();
108
+ expect(() => OrgUnitTreeNodeSchema.parse({ ...base, depth: 21 })).toThrow();
106
109
  });
107
110
 
108
111
  it("requires a non-negative openRoleCount", () => {
@@ -277,7 +280,7 @@ describe("OrgUnitRelationshipSchema", () => {
277
280
  });
278
281
 
279
282
  describe("OrgLevelConfigSchema", () => {
280
- it("enforces depth 1..5, non-empty-when-present label/labelPlural, and icon enum", () => {
283
+ it("enforces depth 1..20, non-empty-when-present label/labelPlural, and icon enum", () => {
281
284
  const entry = {
282
285
  orgId: UUID_B,
283
286
  depth: 2,
@@ -296,7 +299,10 @@ describe("OrgLevelConfigSchema", () => {
296
299
  icon: null,
297
300
  }),
298
301
  ).not.toThrow();
299
- expect(() => OrgLevelConfigSchema.parse({ ...entry, depth: 6 })).toThrow();
302
+ expect(() =>
303
+ OrgLevelConfigSchema.parse({ ...entry, depth: 6 }),
304
+ ).not.toThrow();
305
+ expect(() => OrgLevelConfigSchema.parse({ ...entry, depth: 21 })).toThrow();
300
306
  expect(() => OrgLevelConfigSchema.parse({ ...entry, label: "" })).toThrow();
301
307
  expect(() =>
302
308
  OrgLevelConfigSchema.parse({ ...entry, labelPlural: "" }),
@@ -144,9 +144,9 @@ export interface CompanyMdNodeIdentity {
144
144
  * docs/goals/sources/maps that are not owned by a unit).
145
145
  *
146
146
  * Prefer this over `level` for structural reasoning. `level` is retained for
147
- * backward compatibility and is @deprecated.
147
+ * backward compatibility and is @deprecated. Bounded 1..`ORG_UNIT_ABSOLUTE_MAX_DEPTH`.
148
148
  */
149
- readonly depth: 1 | 2 | 3 | 4 | 5 | null;
149
+ readonly depth: number | null;
150
150
  readonly parentId: string | null;
151
151
  readonly visibility: CompanyMdVisibility;
152
152
  /**
package/src/org/index.ts CHANGED
@@ -498,6 +498,10 @@ export type {
498
498
  OrgTreeResponse,
499
499
  } from "./org-units";
500
500
  export { ORG_UNITS_ROUTES } from "./org-units";
501
+ export {
502
+ ORG_UNIT_DESIGNED_MAX_DEPTH,
503
+ ORG_UNIT_ABSOLUTE_MAX_DEPTH,
504
+ } from "./org-depth";
501
505
  export {
502
506
  OrgUnitClassificationSchema,
503
507
  OrgUnitSyncModeSchema,
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Org-unit tree depth ceilings.
3
+ *
4
+ * Depth counts the org root as 1 (`nlevel(org_units.path)`). Two ceilings,
5
+ * deliberately distinct (backend ADR: org-unit depth, designed vs absolute):
6
+ *
7
+ * - {@link ORG_UNIT_DESIGNED_MAX_DEPTH} is the depth a human can build from
8
+ * scratch. The UI's "+ New child", "Add level" and drag-reparent, and the
9
+ * server's default (`designed`) depth policy, never deepen an org past
10
+ * `max(DESIGNED, the org's current deepest unit)`.
11
+ * - {@link ORG_UNIT_ABSOLUTE_MAX_DEPTH} mirrors the database CHECK
12
+ * (`org_units_depth_max`). Only ingest (structure inference apply, HRIS sync,
13
+ * org-chart import) runs under the `absolute` policy and may deepen an org
14
+ * past the designed depth, up to this bound. Nothing exceeds it.
15
+ *
16
+ * Both are compile-time constants, not per-org configuration.
17
+ */
18
+
19
+ /** Depth a human may build from scratch; the UI ceiling for a fresh org. */
20
+ export const ORG_UNIT_DESIGNED_MAX_DEPTH = 5;
21
+
22
+ /** Hard ceiling mirrored by the `org_units_depth_max` CHECK; ingest-only past designed. */
23
+ export const ORG_UNIT_ABSOLUTE_MAX_DEPTH = 20;
24
+
25
+ /**
26
+ * The positional unit-owner membership roles, one per depth 1..absolute. Spelled
27
+ * out rather than generated so each member stays a string literal type; the
28
+ * schema that consumes it (`UnitMembershipRoleSchema`) adds `member` in front.
29
+ */
30
+ export const UNIT_OWNER_MEMBERSHIP_ROLES = [
31
+ "l1_unit_owner",
32
+ "l2_unit_owner",
33
+ "l3_unit_owner",
34
+ "l4_unit_owner",
35
+ "l5_unit_owner",
36
+ "l6_unit_owner",
37
+ "l7_unit_owner",
38
+ "l8_unit_owner",
39
+ "l9_unit_owner",
40
+ "l10_unit_owner",
41
+ "l11_unit_owner",
42
+ "l12_unit_owner",
43
+ "l13_unit_owner",
44
+ "l14_unit_owner",
45
+ "l15_unit_owner",
46
+ "l16_unit_owner",
47
+ "l17_unit_owner",
48
+ "l18_unit_owner",
49
+ "l19_unit_owner",
50
+ "l20_unit_owner",
51
+ ] as const;
@@ -18,7 +18,8 @@
18
18
  * - `path` is an ltree string maintained by a DB trigger; never written from
19
19
  * application code.
20
20
  * - Depth is derived from `path`. `OrgLevelConfig.depth` is only a key for
21
- * per-depth labels and policy — not authoritative structure.
21
+ * per-depth labels and policy — not authoritative structure. Ceilings live in
22
+ * `./org-depth` (designed 5, absolute 20; ingest-only past designed).
22
23
  */
23
24
 
24
25
  /** Semantic classification — projection-only, never drives traversal. */
@@ -113,7 +114,7 @@ export type { OrgUnitTreeResponse as OrgTreeResponse } from "./schemas";
113
114
  export type OrgUnitErrorCode =
114
115
  /** newParent.path contains unit.path — would create a cycle. */
115
116
  | "CYCLE_BLOCKED"
116
- /** Reparent would push subtree above depth 5. */
117
+ /** Create/reparent would push the subtree past the effective depth ceiling (`./org-depth`). */
117
118
  | "DEPTH_EXCEEDED"
118
119
  /** Target parent is archived; reparenting into archived subtrees is forbidden. */
119
120
  | "TARGET_ARCHIVED"
@@ -14,6 +14,10 @@ import { z } from "zod";
14
14
  import { CursorPageSchema, IsoDateTime } from "../api/primitives";
15
15
  import { OrgChartRoleSchema } from "../permissions/orgchart-roles";
16
16
  import { PositionRefSchema } from "../identity/position-ref";
17
+ import {
18
+ ORG_UNIT_ABSOLUTE_MAX_DEPTH,
19
+ UNIT_OWNER_MEMBERSHIP_ROLES,
20
+ } from "./org-depth";
17
21
 
18
22
  // ---------------------------------------------------------------------------
19
23
  // Sub-schemas
@@ -1496,15 +1500,12 @@ export const OrgUnitRelationshipRoleSchema = z.enum([
1496
1500
  /**
1497
1501
  * Positional slot a member holds in the org-unit tree. ORTHOGONAL to the
1498
1502
  * `OrgChartRole` policy vocabulary (this is an INPUT to authority resolution,
1499
- * not the derived policy role). Level is encoded in the value (l1…l5).
1503
+ * not the derived policy role). Level is encoded in the value (l1…l20, one
1504
+ * per depth up to `ORG_UNIT_ABSOLUTE_MAX_DEPTH`).
1500
1505
  */
1501
1506
  export const UnitMembershipRoleSchema = z.enum([
1502
1507
  "member",
1503
- "l1_unit_owner",
1504
- "l2_unit_owner",
1505
- "l3_unit_owner",
1506
- "l4_unit_owner",
1507
- "l5_unit_owner",
1508
+ ...UNIT_OWNER_MEMBERSHIP_ROLES,
1508
1509
  ]);
1509
1510
 
1510
1511
  export type UnitMembershipRole = z.infer<typeof UnitMembershipRoleSchema>;
@@ -1579,7 +1580,7 @@ export const MissingAtNextLevelSchema = z.object({
1579
1580
  });
1580
1581
 
1581
1582
  export const OrgUnitTreeNodeSchema = OrgUnitSchema.extend({
1582
- depth: z.number().int().min(1).max(5),
1583
+ depth: z.number().int().min(1).max(ORG_UNIT_ABSOLUTE_MAX_DEPTH),
1583
1584
  hasChildren: z.boolean(),
1584
1585
  /**
1585
1586
  * WHAT it counts is the `.describe()` below — the single field-level
@@ -1871,7 +1872,7 @@ export const OrgLevelIconSchema = z.enum([
1871
1872
 
1872
1873
  export const OrgLevelConfigSchema = z.object({
1873
1874
  orgId: z.string().uuid(),
1874
- depth: z.number().int().min(1).max(5),
1875
+ depth: z.number().int().min(1).max(ORG_UNIT_ABSOLUTE_MAX_DEPTH),
1875
1876
  label: z.string().min(1).nullable(),
1876
1877
  labelPlural: z.string().min(1).nullable(),
1877
1878
  icon: OrgLevelIconSchema.nullable(),
@@ -2132,6 +2133,11 @@ export const CapabilitiesResponseSchema = z.object({
2132
2133
  .optional(),
2133
2134
  })
2134
2135
  .optional(),
2136
+ // Gates the chat composer's mention affordance (PRD-00988). Optional for the
2137
+ // same rollout symmetry as the action sub-objects above: a backend that does
2138
+ // not yet derive the flag must still validate its own response, and the spec
2139
+ // already carried the field before this schema did.
2140
+ chatMentions: z.boolean().optional(),
2135
2141
  });
2136
2142
 
2137
2143
  export type FieldCapability = z.infer<typeof FieldCapabilitySchema>;