@company-semantics/contracts 61.0.0 → 62.1.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": "61.0.0",
3
+ "version": "62.1.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 = '4ee1bc3befbf' as const;
3
- export const SPEC_HASH_FULL = '4ee1bc3befbf8bb865b4bdad38b892c59f198fec45acdcdde93a067a678516b3' as const;
2
+ export const SPEC_HASH = '8e4ad15ffd00' as const;
3
+ export const SPEC_HASH_FULL = '8e4ad15ffd00b9b83f7adb26bd7bfdff0c03994756b3022b9dbc27f3ba9f7852' as const;
@@ -4263,8 +4263,28 @@ export interface components {
4263
4263
  reason: "external-mutation" | "bulk-operation" | "sync-required";
4264
4264
  };
4265
4265
  AiChatRequest: {
4266
+ /**
4267
+ * @default submit-message
4268
+ * @constant
4269
+ */
4270
+ trigger: "submit-message";
4271
+ id?: string;
4272
+ messageId?: string;
4273
+ message?: {
4274
+ id: string;
4275
+ /** @constant */
4276
+ role: "user";
4277
+ parts: unknown[];
4278
+ };
4266
4279
  messages: unknown[];
4280
+ runtimeProfile?: string;
4281
+ } | {
4282
+ /** @constant */
4283
+ trigger: "regenerate-message";
4267
4284
  id?: string;
4285
+ messageId?: string;
4286
+ message?: unknown;
4287
+ messages: unknown[];
4268
4288
  runtimeProfile?: string;
4269
4289
  };
4270
4290
  ProactiveChatResolution: {
@@ -5626,8 +5646,12 @@ export interface components {
5626
5646
  updatedAt: string;
5627
5647
  depth: number;
5628
5648
  hasChildren: boolean;
5649
+ /** @description Accounts with a home assignment, rolled up over this unit's subtree. Legitimately 0 for a fully staffed department in an HRIS-imported org, where almost nobody has signed in — use placedPeopleCount for headcount. */
5629
5650
  memberCount: number;
5651
+ /** @description Active open roles (`open` + `hiring`) rolled up over this unit's subtree. Vacant seats only — an HRIS-imported seat is `lifecycle_owner='import:hris'` and is counted by neither this nor memberCount. */
5630
5652
  openRoleCount: number;
5653
+ /** @description Distinct people holding a live canonical seat in this unit's subtree, whether or not they have an account. Deliberately does NOT filter positions.status: an occupied `closed` seat still draws a card on the org chart, so a filter here would disagree with it. */
5654
+ placedPeopleCount: number;
5631
5655
  missingAtNextLevel: {
5632
5656
  count: number;
5633
5657
  userIds: string[];
@@ -5774,8 +5798,12 @@ export interface components {
5774
5798
  updatedAt: string;
5775
5799
  depth: number;
5776
5800
  hasChildren: boolean;
5801
+ /** @description Accounts with a home assignment, rolled up over this unit's subtree. Legitimately 0 for a fully staffed department in an HRIS-imported org, where almost nobody has signed in — use placedPeopleCount for headcount. */
5777
5802
  memberCount: number;
5803
+ /** @description Active open roles (`open` + `hiring`) rolled up over this unit's subtree. Vacant seats only — an HRIS-imported seat is `lifecycle_owner='import:hris'` and is counted by neither this nor memberCount. */
5778
5804
  openRoleCount: number;
5805
+ /** @description Distinct people holding a live canonical seat in this unit's subtree, whether or not they have an account. Deliberately does NOT filter positions.status: an occupied `closed` seat still draws a card on the org chart, so a filter here would disagree with it. */
5806
+ placedPeopleCount: number;
5779
5807
  missingAtNextLevel: {
5780
5808
  count: number;
5781
5809
  userIds: string[];
@@ -97,6 +97,7 @@ describe("OrgUnitTreeNodeSchema", () => {
97
97
  hasChildren: true,
98
98
  memberCount: 5,
99
99
  openRoleCount: 1,
100
+ placedPeopleCount: 5,
100
101
  missingAtNextLevel: null,
101
102
  };
102
103
  expect(() => OrgUnitTreeNodeSchema.parse(base)).not.toThrow();
@@ -111,6 +112,7 @@ describe("OrgUnitTreeNodeSchema", () => {
111
112
  hasChildren: true,
112
113
  memberCount: 5,
113
114
  openRoleCount: 0,
115
+ placedPeopleCount: 5,
114
116
  missingAtNextLevel: null,
115
117
  };
116
118
  expect(() => OrgUnitTreeNodeSchema.parse(base)).not.toThrow();
@@ -118,6 +120,30 @@ describe("OrgUnitTreeNodeSchema", () => {
118
120
  OrgUnitTreeNodeSchema.parse({ ...base, openRoleCount: -1 }),
119
121
  ).toThrow();
120
122
  });
123
+
124
+ it("requires placedPeopleCount, and lets it disagree with memberCount", () => {
125
+ const base = {
126
+ ...makeUnit(),
127
+ depth: 3,
128
+ hasChildren: false,
129
+ // The HRIS shape: nobody in this department has an account, so the
130
+ // account-keyed rollup is 0 while 22 people hold seats in it. Both are
131
+ // correct; they answer different questions (ADR-CONTRACTS-150).
132
+ memberCount: 0,
133
+ openRoleCount: 0,
134
+ placedPeopleCount: 22,
135
+ missingAtNextLevel: null,
136
+ };
137
+ expect(() => OrgUnitTreeNodeSchema.parse(base)).not.toThrow();
138
+
139
+ // Required, not optional — pre-launch there is no back-compat window, and
140
+ // an absent count would be indistinguishable from an empty unit.
141
+ const { placedPeopleCount: _omitted, ...withoutIt } = base;
142
+ expect(() => OrgUnitTreeNodeSchema.parse(withoutIt)).toThrow();
143
+ expect(() =>
144
+ OrgUnitTreeNodeSchema.parse({ ...base, placedPeopleCount: -1 }),
145
+ ).toThrow();
146
+ });
121
147
  });
122
148
 
123
149
  describe("OpenRoleSchema", () => {
@@ -1581,13 +1581,49 @@ export const MissingAtNextLevelSchema = z.object({
1581
1581
  export const OrgUnitTreeNodeSchema = OrgUnitSchema.extend({
1582
1582
  depth: z.number().int().min(1).max(5),
1583
1583
  hasChildren: z.boolean(),
1584
- memberCount: z.number().int().min(0),
1585
1584
  /**
1586
- * Active open roles (`open` + `hiring`) rolled up over this unit's subtree,
1587
- * the same way `memberCount` rolls up real members. Drives the "(N + M open)"
1588
- * count split in the people surfaces. `memberCount` stays real-members-only.
1585
+ * WHAT it counts is the `.describe()` below the single field-level
1586
+ * description, which reaches `openapi/backend.yaml` and the generated API
1587
+ * types. This comment carries only WHY, so the two cannot drift into
1588
+ * disagreeing.
1589
+ *
1590
+ * Why accounts: it is the right population for anything that needs an account
1591
+ * to act on — the share dialog's fanout, the unit-scoped members table. It is
1592
+ * backed by `home_assignments`, whose `user_id` is NOT NULL, so an accountless
1593
+ * person structurally cannot appear in it. Deliberately NOT redefined and NOT
1594
+ * deprecated; {@link placedPeopleCount} answers the headcount question, and the
1595
+ * two legitimately disagree (ADR-CONTRACTS-150, ADR-BE-657).
1596
+ */
1597
+ memberCount: z
1598
+ .number()
1599
+ .int()
1600
+ .min(0)
1601
+ .describe(
1602
+ "Accounts with a home assignment, rolled up over this unit's subtree. Legitimately 0 for a fully staffed department in an HRIS-imported org, where almost nobody has signed in — use placedPeopleCount for headcount.",
1603
+ ),
1604
+ /** Drives the "(N + M open)" count split in the people surfaces. */
1605
+ openRoleCount: z
1606
+ .number()
1607
+ .int()
1608
+ .min(0)
1609
+ .describe(
1610
+ "Active open roles (`open` + `hiring`) rolled up over this unit's subtree. Vacant seats only — an HRIS-imported seat is `lifecycle_owner='import:hris'` and is counted by neither this nor memberCount.",
1611
+ ),
1612
+ /**
1613
+ * Predicate: `placement_role='canonical'`, `status <> 'ended'`, keyed by
1614
+ * `positions.unit_id`. Placement and home are independent graphs
1615
+ * (ADR-CTRL-159), so a person seated here may be homed elsewhere and vice
1616
+ * versa. The `positions.status` non-filter stated in the `.describe()` below
1617
+ * is deliberate and load-bearing — the backend pins it with a test whose name
1618
+ * says so (ADR-BE-657).
1589
1619
  */
1590
- openRoleCount: z.number().int().min(0),
1620
+ placedPeopleCount: z
1621
+ .number()
1622
+ .int()
1623
+ .min(0)
1624
+ .describe(
1625
+ "Distinct people holding a live canonical seat in this unit's subtree, whether or not they have an account. Deliberately does NOT filter positions.status: an occupied `closed` seat still draws a card on the org chart, so a filter here would disagree with it.",
1626
+ ),
1591
1627
  missingAtNextLevel: MissingAtNextLevelSchema.nullable(),
1592
1628
  });
1593
1629