@company-semantics/contracts 13.15.0 → 13.16.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": "13.15.0",
3
+ "version": "13.16.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -67,6 +67,8 @@ export {
67
67
  PeopleOrgChartNodeSchema,
68
68
  PeopleOrgChartEdgeSchema,
69
69
  PeopleOrgChartOpenRoleSchema,
70
+ UnitHeadOriginSchema,
71
+ PeopleOrgChartUnitHeadSchema,
70
72
  PeopleOrgChartResponseSchema,
71
73
  } from "./people-org-chart";
72
74
  export type {
@@ -74,5 +76,7 @@ export type {
74
76
  PeopleOrgChartNode,
75
77
  PeopleOrgChartEdge,
76
78
  PeopleOrgChartOpenRole,
79
+ UnitHeadOrigin,
80
+ PeopleOrgChartUnitHead,
77
81
  PeopleOrgChartResponse,
78
82
  } from "./people-org-chart";
@@ -66,6 +66,29 @@ export type PeopleOrgChartOpenRole = z.infer<
66
66
  typeof PeopleOrgChartOpenRoleSchema
67
67
  >;
68
68
 
69
+ // ---------------------------------------------------------------------------
70
+ // Unit head — the person a unit (and its person-less children: empty-unit
71
+ // placeholders, pending-invite ghosts, open-role seats) anchors under in the
72
+ // people chart. A presentation/anchor "tether" (ADR-BE-283), NOT authority.
73
+ // `origin` distinguishes an explicit user choice from a system-inferred default
74
+ // so the UI can render "Pinned" vs "Auto" and offer revert-to-auto. The client
75
+ // prefers the head of a unit's PARENT when anchoring its person-less children,
76
+ // falling back to the render-time heuristic only when no head row exists.
77
+ // ---------------------------------------------------------------------------
78
+
79
+ export const UnitHeadOriginSchema = z.enum(["user", "inferred"]);
80
+ export type UnitHeadOrigin = z.infer<typeof UnitHeadOriginSchema>;
81
+
82
+ export const PeopleOrgChartUnitHeadSchema = z.object({
83
+ unitId: z.string().uuid(),
84
+ headUserId: z.string().uuid(),
85
+ origin: UnitHeadOriginSchema,
86
+ });
87
+
88
+ export type PeopleOrgChartUnitHead = z.infer<
89
+ typeof PeopleOrgChartUnitHeadSchema
90
+ >;
91
+
69
92
  // ---------------------------------------------------------------------------
70
93
  // GET /api/users/org-chart
71
94
  // ---------------------------------------------------------------------------
@@ -74,6 +97,7 @@ export const PeopleOrgChartResponseSchema = z.object({
74
97
  nodes: z.array(PeopleOrgChartNodeSchema),
75
98
  edges: z.array(PeopleOrgChartEdgeSchema),
76
99
  openRoles: z.array(PeopleOrgChartOpenRoleSchema),
100
+ unitHeads: z.array(PeopleOrgChartUnitHeadSchema),
77
101
  });
78
102
 
79
103
  export type PeopleOrgChartResponse = z.infer<
package/src/index.ts CHANGED
@@ -173,6 +173,8 @@ export {
173
173
  PeopleOrgChartNodeSchema,
174
174
  PeopleOrgChartEdgeSchema,
175
175
  PeopleOrgChartOpenRoleSchema,
176
+ UnitHeadOriginSchema,
177
+ PeopleOrgChartUnitHeadSchema,
176
178
  PeopleOrgChartResponseSchema,
177
179
  } from "./identity/index";
178
180
  export type {
@@ -180,6 +182,8 @@ export type {
180
182
  PeopleOrgChartNode,
181
183
  PeopleOrgChartEdge,
182
184
  PeopleOrgChartOpenRole,
185
+ UnitHeadOrigin,
186
+ PeopleOrgChartUnitHead,
183
187
  PeopleOrgChartResponse,
184
188
  } from "./identity/index";
185
189
 
@@ -98,6 +98,8 @@ describe("OrgUnitTreeNodeSchema", () => {
98
98
  memberCount: 5,
99
99
  openRoleCount: 1,
100
100
  missingAtNextLevel: null,
101
+ headUserId: null,
102
+ headOrigin: null,
101
103
  };
102
104
  expect(() => OrgUnitTreeNodeSchema.parse(base)).not.toThrow();
103
105
  expect(() => OrgUnitTreeNodeSchema.parse({ ...base, depth: 0 })).toThrow();
@@ -112,6 +114,8 @@ describe("OrgUnitTreeNodeSchema", () => {
112
114
  memberCount: 5,
113
115
  openRoleCount: 0,
114
116
  missingAtNextLevel: null,
117
+ headUserId: null,
118
+ headOrigin: null,
115
119
  };
116
120
  expect(() => OrgUnitTreeNodeSchema.parse(base)).not.toThrow();
117
121
  expect(() =>
@@ -947,6 +947,16 @@ export const OrgUnitTreeNodeSchema = OrgUnitSchema.extend({
947
947
  */
948
948
  openRoleCount: z.number().int().min(0),
949
949
  missingAtNextLevel: MissingAtNextLevelSchema.nullable(),
950
+ /**
951
+ * The unit head (ADR-BE-283): the person this unit (and its person-less
952
+ * children) anchors under in the people chart — a presentation "tether", NOT
953
+ * authority. `headUserId` is null when no head is resolved (e.g. an empty
954
+ * unit with no members). `headOrigin` is `'user'` for an explicit choice,
955
+ * `'inferred'` for a system default (so the management UI can show Pinned vs
956
+ * Auto and offer revert-to-auto), or null when there is no head.
957
+ */
958
+ headUserId: z.string().uuid().nullable(),
959
+ headOrigin: z.enum(["user", "inferred"]).nullable(),
950
960
  });
951
961
 
952
962
  export const OrgUnitMembershipSchema = z.object({