@company-semantics/contracts 27.3.0 → 27.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 +4 -4
- package/src/api/generated-spec-hash.ts +2 -2
- package/src/api/generated.ts +65 -14
- package/src/autotune.ts +1 -4
- package/src/ci-envelope/types.ts +1 -5
- package/src/ci-results/repo-ci-result.ts +1 -5
- package/src/content/schemas.ts +38 -0
- package/src/generated/openapi-routes.ts +1 -0
- package/src/guards/types.ts +1 -5
- package/src/index.ts +8 -0
- package/src/mcp/index.ts +1 -5
- package/src/message-parts/confirmation.ts +1 -4
- package/src/message-parts/interactive.ts +1 -2
- package/src/message-parts/lifecycle.ts +1 -3
- package/src/org/README.md +8 -0
- package/src/org/__tests__/transformation.test.ts +166 -0
- package/src/org/company-md.ts +41 -7
- package/src/org/index.ts +8 -0
- package/src/org/org-units.ts +4 -14
- package/src/org/sharing.ts +1 -4
- package/src/org/transformation.ts +149 -6
- package/src/org/types.ts +1 -4
- package/src/ralph/prd.ts +1 -5
- package/src/system/capabilities.ts +1 -7
- package/src/system/diagram.ts +1 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@company-semantics/contracts",
|
|
3
|
-
"version": "27.
|
|
3
|
+
"version": "27.5.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -123,12 +123,12 @@
|
|
|
123
123
|
"zod": "^4.4.3"
|
|
124
124
|
},
|
|
125
125
|
"devDependencies": {
|
|
126
|
-
"@types/node": "^
|
|
126
|
+
"@types/node": "^26.0.1",
|
|
127
127
|
"husky": "^9.1.7",
|
|
128
|
-
"lint-staged": "^17.0.
|
|
128
|
+
"lint-staged": "^17.0.8",
|
|
129
129
|
"markdownlint-cli2": "^0.22.1",
|
|
130
130
|
"openapi-typescript": "^7.13.0",
|
|
131
|
-
"prettier": "^3.
|
|
131
|
+
"prettier": "^3.9.4",
|
|
132
132
|
"tsx": "^4.22.4",
|
|
133
133
|
"typescript": "^5.8.3",
|
|
134
134
|
"vitest": "^4.1.9",
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// AUTO-GENERATED — do not edit. Run pnpm generate:spec-hash to regenerate.
|
|
2
|
-
export const SPEC_HASH = '
|
|
3
|
-
export const SPEC_HASH_FULL = '
|
|
2
|
+
export const SPEC_HASH = '511ebe19b2ad' as const;
|
|
3
|
+
export const SPEC_HASH_FULL = '511ebe19b2adea947b0bfbd6ad39a192a616cf10e2d30606dde9ef8517389eed' as const;
|
package/src/api/generated.ts
CHANGED
|
@@ -753,6 +753,23 @@ export interface paths {
|
|
|
753
753
|
patch?: never;
|
|
754
754
|
trace?: never;
|
|
755
755
|
};
|
|
756
|
+
"/api/reporting/move/preview": {
|
|
757
|
+
parameters: {
|
|
758
|
+
query?: never;
|
|
759
|
+
header?: never;
|
|
760
|
+
path?: never;
|
|
761
|
+
cookie?: never;
|
|
762
|
+
};
|
|
763
|
+
get?: never;
|
|
764
|
+
put?: never;
|
|
765
|
+
/** Preview an org-chart reporting move as a semantic transform */
|
|
766
|
+
post: operations["previewReportingMove"];
|
|
767
|
+
delete?: never;
|
|
768
|
+
options?: never;
|
|
769
|
+
head?: never;
|
|
770
|
+
patch?: never;
|
|
771
|
+
trace?: never;
|
|
772
|
+
};
|
|
756
773
|
"/api/chat/interactive-tasks/submit": {
|
|
757
774
|
parameters: {
|
|
758
775
|
query?: never;
|
|
@@ -3909,6 +3926,18 @@ export interface components {
|
|
|
3909
3926
|
};
|
|
3910
3927
|
idempotencyKey: string;
|
|
3911
3928
|
};
|
|
3929
|
+
MovePreviewRequest: {
|
|
3930
|
+
/**
|
|
3931
|
+
* Format: uuid
|
|
3932
|
+
* @description Workspace member (users.id) being moved in the chart
|
|
3933
|
+
*/
|
|
3934
|
+
memberId: string;
|
|
3935
|
+
/**
|
|
3936
|
+
* Format: uuid
|
|
3937
|
+
* @description The member (users.id) the dragged member should report to after the move
|
|
3938
|
+
*/
|
|
3939
|
+
newManagerUserId: string;
|
|
3940
|
+
};
|
|
3912
3941
|
SubmitInteractiveTaskResponse: {
|
|
3913
3942
|
executionId: string;
|
|
3914
3943
|
/** @enum {string} */
|
|
@@ -4440,6 +4469,13 @@ export interface components {
|
|
|
4440
4469
|
memberCount: number;
|
|
4441
4470
|
description?: string;
|
|
4442
4471
|
orderKey?: string;
|
|
4472
|
+
/** @enum {string} */
|
|
4473
|
+
discoverabilityPolicy: "org" | "owners";
|
|
4474
|
+
/** @enum {string} */
|
|
4475
|
+
classification: "public" | "internal" | "confidential" | "highly_confidential";
|
|
4476
|
+
/** @enum {string} */
|
|
4477
|
+
accessState?: "full" | "redacted_admin" | "locked_requestable";
|
|
4478
|
+
canRequestAccess?: boolean;
|
|
4443
4479
|
}[];
|
|
4444
4480
|
nextCursor: string | null;
|
|
4445
4481
|
hasMore: boolean;
|
|
@@ -4453,7 +4489,14 @@ export interface components {
|
|
|
4453
4489
|
content: string;
|
|
4454
4490
|
contentRedacted?: boolean;
|
|
4455
4491
|
/** @enum {string} */
|
|
4492
|
+
accessState?: "full" | "redacted_admin" | "locked_requestable";
|
|
4493
|
+
canRequestAccess?: boolean;
|
|
4494
|
+
/** @enum {string} */
|
|
4456
4495
|
visibility: "private" | "unit" | "org";
|
|
4496
|
+
/** @enum {string} */
|
|
4497
|
+
discoverabilityPolicy: "org" | "owners";
|
|
4498
|
+
/** @enum {string} */
|
|
4499
|
+
classification: "public" | "internal" | "confidential" | "highly_confidential";
|
|
4457
4500
|
parentId: string | null;
|
|
4458
4501
|
owningUnitId: string | null;
|
|
4459
4502
|
owner: {
|
|
@@ -7036,6 +7079,28 @@ export interface operations {
|
|
|
7036
7079
|
};
|
|
7037
7080
|
};
|
|
7038
7081
|
};
|
|
7082
|
+
previewReportingMove: {
|
|
7083
|
+
parameters: {
|
|
7084
|
+
query?: never;
|
|
7085
|
+
header?: never;
|
|
7086
|
+
path?: never;
|
|
7087
|
+
cookie?: never;
|
|
7088
|
+
};
|
|
7089
|
+
requestBody: {
|
|
7090
|
+
content: {
|
|
7091
|
+
"application/json": components["schemas"]["MovePreviewRequest"];
|
|
7092
|
+
};
|
|
7093
|
+
};
|
|
7094
|
+
responses: {
|
|
7095
|
+
/** @description Transformation preview plus the semantic.transform execution intent (mutations) the app confirms */
|
|
7096
|
+
200: {
|
|
7097
|
+
headers: {
|
|
7098
|
+
[name: string]: unknown;
|
|
7099
|
+
};
|
|
7100
|
+
content?: never;
|
|
7101
|
+
};
|
|
7102
|
+
};
|
|
7103
|
+
};
|
|
7039
7104
|
submitInteractiveTask: {
|
|
7040
7105
|
parameters: {
|
|
7041
7106
|
query?: never;
|
|
@@ -8467,13 +8532,6 @@ export interface operations {
|
|
|
8467
8532
|
};
|
|
8468
8533
|
content?: never;
|
|
8469
8534
|
};
|
|
8470
|
-
/** @description Requires org.view_company_md scope */
|
|
8471
|
-
403: {
|
|
8472
|
-
headers: {
|
|
8473
|
-
[name: string]: unknown;
|
|
8474
|
-
};
|
|
8475
|
-
content?: never;
|
|
8476
|
-
};
|
|
8477
8535
|
};
|
|
8478
8536
|
};
|
|
8479
8537
|
companyMdContextDocSuggestions: {
|
|
@@ -8503,13 +8561,6 @@ export interface operations {
|
|
|
8503
8561
|
};
|
|
8504
8562
|
content?: never;
|
|
8505
8563
|
};
|
|
8506
|
-
/** @description Requires org.view_company_md scope */
|
|
8507
|
-
403: {
|
|
8508
|
-
headers: {
|
|
8509
|
-
[name: string]: unknown;
|
|
8510
|
-
};
|
|
8511
|
-
content?: never;
|
|
8512
|
-
};
|
|
8513
8564
|
};
|
|
8514
8565
|
};
|
|
8515
8566
|
searchCompanyMd: {
|
package/src/autotune.ts
CHANGED
|
@@ -86,9 +86,6 @@ export type ControllerInput = {
|
|
|
86
86
|
export type ControllerOutput<Min extends number, Max extends number> = {
|
|
87
87
|
readonly value: Bounded<Min, Max>;
|
|
88
88
|
readonly reason:
|
|
89
|
-
| "
|
|
90
|
-
| "window-hold"
|
|
91
|
-
| "adjusted"
|
|
92
|
-
| "bounded-clamp";
|
|
89
|
+
"deadband-hold" | "window-hold" | "adjusted" | "bounded-clamp";
|
|
93
90
|
readonly adjustmentWindowId: string;
|
|
94
91
|
};
|
package/src/ci-envelope/types.ts
CHANGED
|
@@ -130,11 +130,7 @@ export type CIGuardPlan = {
|
|
|
130
130
|
* Note: Transition validation logic lives in CI repo, not here.
|
|
131
131
|
*/
|
|
132
132
|
export type CIEnvelopeStatus =
|
|
133
|
-
| "
|
|
134
|
-
| "validated"
|
|
135
|
-
| "blocked"
|
|
136
|
-
| "executing"
|
|
137
|
-
| "finalized";
|
|
133
|
+
"proposed" | "validated" | "blocked" | "executing" | "finalized";
|
|
138
134
|
|
|
139
135
|
// =============================================================================
|
|
140
136
|
// Outcome Types
|
|
@@ -6,11 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
export type GuardTier =
|
|
9
|
-
| "
|
|
10
|
-
| "behavioral"
|
|
11
|
-
| "invariants"
|
|
12
|
-
| "evolution"
|
|
13
|
-
| "meta";
|
|
9
|
+
"structural" | "behavioral" | "invariants" | "evolution" | "meta";
|
|
14
10
|
|
|
15
11
|
/**
|
|
16
12
|
* Minimal structural shape of a guard orchestrator result payload.
|
package/src/content/schemas.ts
CHANGED
|
@@ -59,6 +59,25 @@ const CompanyMdTreeNodeSchema = z.object({
|
|
|
59
59
|
description: z.string().optional(),
|
|
60
60
|
/** Fractional-index key for ordered entity wrappers (unit/context). */
|
|
61
61
|
orderKey: z.string().optional(),
|
|
62
|
+
// Governance + discovery projections of the node (ADR-BE-348 / ADR-CTRL-194).
|
|
63
|
+
// Present on the TS `CompanyMdNodeIdentity` since the projection split but only
|
|
64
|
+
// now promoted into the published response schema. `discoverabilityPolicy`
|
|
65
|
+
// governs who knows the node exists; `classification` is the governance label
|
|
66
|
+
// (drives no permission).
|
|
67
|
+
discoverabilityPolicy: z.enum(["org", "owners"]),
|
|
68
|
+
classification: z.enum([
|
|
69
|
+
"public",
|
|
70
|
+
"internal",
|
|
71
|
+
"confidential",
|
|
72
|
+
"highly_confidential",
|
|
73
|
+
]),
|
|
74
|
+
// Combined Authorization + Discovery read-state for the requesting actor
|
|
75
|
+
// (ADR-BE-348). Set on non-reader stubs the tree now surfaces; absent on
|
|
76
|
+
// full-read nodes (treat as `full`).
|
|
77
|
+
accessState: z
|
|
78
|
+
.enum(["full", "redacted_admin", "locked_requestable"])
|
|
79
|
+
.optional(),
|
|
80
|
+
canRequestAccess: z.boolean().optional(),
|
|
62
81
|
});
|
|
63
82
|
|
|
64
83
|
// ---------------------------------------------------------------------------
|
|
@@ -83,7 +102,26 @@ export const CompanyMdDocResponseSchema = z.object({
|
|
|
83
102
|
* its body (ADR-BE-245). Omitted/`false` on the normal full-content path.
|
|
84
103
|
*/
|
|
85
104
|
contentRedacted: z.boolean().optional(),
|
|
105
|
+
// Combined Authorization + Discovery read-state for the requesting actor
|
|
106
|
+
// (ADR-BE-348): `full` (reader), `redacted_admin` (inspectable metadata stub),
|
|
107
|
+
// `locked_requestable` (listed locked stub). Optional for back-compat with
|
|
108
|
+
// legacy paths that set only `contentRedacted`.
|
|
109
|
+
accessState: z
|
|
110
|
+
.enum(["full", "redacted_admin", "locked_requestable"])
|
|
111
|
+
.optional(),
|
|
112
|
+
/** Whether the requesting actor may request access (ADR-BE-348 / ADR-BE-338). */
|
|
113
|
+
canRequestAccess: z.boolean().optional(),
|
|
86
114
|
visibility: z.enum(["private", "unit", "org"]),
|
|
115
|
+
// Governance + discovery projections (ADR-BE-348 / ADR-CTRL-194). Present on
|
|
116
|
+
// the TS contract since the projection split; now promoted into the published
|
|
117
|
+
// response schema so consumers receive them typed.
|
|
118
|
+
discoverabilityPolicy: z.enum(["org", "owners"]),
|
|
119
|
+
classification: z.enum([
|
|
120
|
+
"public",
|
|
121
|
+
"internal",
|
|
122
|
+
"confidential",
|
|
123
|
+
"highly_confidential",
|
|
124
|
+
]),
|
|
87
125
|
parentId: z.string().nullable(),
|
|
88
126
|
owningUnitId: z.string().nullable(),
|
|
89
127
|
owner: CompanyMdPersonSchema.nullable(),
|
|
@@ -126,6 +126,7 @@ export const openApiRoutes = {
|
|
|
126
126
|
'/api/orgs/{orgId}/level-config': ['GET', 'PUT'],
|
|
127
127
|
'/api/rbac/roles': ['GET'],
|
|
128
128
|
'/api/reporting/bulk-reparent': ['POST'],
|
|
129
|
+
'/api/reporting/move/preview': ['POST'],
|
|
129
130
|
'/api/scope/check': ['GET'],
|
|
130
131
|
'/api/scope/check-batch': ['POST'],
|
|
131
132
|
'/api/shared/{token}': ['GET'],
|
package/src/guards/types.ts
CHANGED
|
@@ -59,11 +59,7 @@ export interface GuardTierResult {
|
|
|
59
59
|
* - meta: guards that protect the guard system itself (coverage correctness)
|
|
60
60
|
*/
|
|
61
61
|
export type GuardTier =
|
|
62
|
-
| "
|
|
63
|
-
| "behavioral"
|
|
64
|
-
| "invariants"
|
|
65
|
-
| "evolution"
|
|
66
|
-
| "meta";
|
|
62
|
+
"structural" | "behavioral" | "invariants" | "evolution" | "meta";
|
|
67
63
|
|
|
68
64
|
/**
|
|
69
65
|
* Full guard results, organized by tier.
|
package/src/index.ts
CHANGED
|
@@ -445,9 +445,13 @@ export {
|
|
|
445
445
|
OrgIntentSchema,
|
|
446
446
|
FactMutationSchema,
|
|
447
447
|
TransformationOriginSchema,
|
|
448
|
+
ProvenanceSchema,
|
|
449
|
+
ExecutionContextSchema,
|
|
448
450
|
TransformationRequestSchema,
|
|
449
451
|
ConstraintViolationSchema,
|
|
450
452
|
RecommendationSchema,
|
|
453
|
+
FindingSeveritySchema,
|
|
454
|
+
FindingSchema,
|
|
451
455
|
TransformStrategySchema,
|
|
452
456
|
SelectionRationaleSchema,
|
|
453
457
|
TransformationPreviewSchema,
|
|
@@ -456,9 +460,13 @@ export type {
|
|
|
456
460
|
OrgIntent,
|
|
457
461
|
FactMutation,
|
|
458
462
|
TransformationOrigin,
|
|
463
|
+
Provenance,
|
|
464
|
+
ExecutionContext,
|
|
459
465
|
TransformationRequest,
|
|
460
466
|
ConstraintViolation,
|
|
461
467
|
Recommendation,
|
|
468
|
+
FindingSeverity,
|
|
469
|
+
Finding,
|
|
462
470
|
TransformStrategy,
|
|
463
471
|
SelectionRationale,
|
|
464
472
|
TransformationPreview,
|
package/src/mcp/index.ts
CHANGED
|
@@ -27,11 +27,7 @@ export type { FailureContext, RecoveryAction } from "./failure-context";
|
|
|
27
27
|
* 'data' conflates discovery, ingestion, and coverage.
|
|
28
28
|
*/
|
|
29
29
|
export type ToolCategory =
|
|
30
|
-
| "
|
|
31
|
-
| "data"
|
|
32
|
-
| "connections"
|
|
33
|
-
| "automation"
|
|
34
|
-
| "developer";
|
|
30
|
+
"system" | "data" | "connections" | "automation" | "developer";
|
|
35
31
|
|
|
36
32
|
/**
|
|
37
33
|
* Tool domain taxonomy.
|
|
@@ -30,10 +30,7 @@ export type ConfirmationChoice = "confirm" | "cancel";
|
|
|
30
30
|
* 'irreversible' indicates destructive operations that cannot be undone.
|
|
31
31
|
*/
|
|
32
32
|
export type ConfirmationRiskLevel =
|
|
33
|
-
| "
|
|
34
|
-
| "moderate"
|
|
35
|
-
| "high"
|
|
36
|
-
| "irreversible";
|
|
33
|
+
"low" | "moderate" | "high" | "irreversible";
|
|
37
34
|
|
|
38
35
|
/**
|
|
39
36
|
* Human-readable confirmation dialog titles for each execution kind.
|
|
@@ -33,8 +33,7 @@ import type { ConfirmationRiskLevel } from "./confirmation";
|
|
|
33
33
|
* Mirrors the `{domain}.{verb}` naming of ExecutionKind. Extensible union.
|
|
34
34
|
*/
|
|
35
35
|
export type InteractiveTaskKind =
|
|
36
|
-
|
|
37
|
-
| "companyMd.importContextDoc";
|
|
36
|
+
"member.changeManager" | "companyMd.importContextDoc";
|
|
38
37
|
|
|
39
38
|
/**
|
|
40
39
|
* How the frontend sources candidate values for an editable field.
|
|
@@ -34,9 +34,7 @@ export type StreamPhase = "idle" | "streaming" | "complete";
|
|
|
34
34
|
* Lifecycle event type discriminator.
|
|
35
35
|
*/
|
|
36
36
|
export type MessageLifecycleEventType =
|
|
37
|
-
| "message.
|
|
38
|
-
| "message.delta"
|
|
39
|
-
| "message.complete";
|
|
37
|
+
"message.start" | "message.delta" | "message.complete";
|
|
40
38
|
|
|
41
39
|
/**
|
|
42
40
|
* Base interface for all message lifecycle events.
|
package/src/org/README.md
CHANGED
|
@@ -95,6 +95,8 @@ Shared type vocabulary for organization ownership, type classification, and tran
|
|
|
95
95
|
- `DomainVerificationMethod` _(type)_ — Method used to verify domain ownership. - 'dnstxt': DNS TXT record verification (primary method) - 'email'…
|
|
96
96
|
- `EffectiveAccess` _(type)_ — Effective access for a user on a document.
|
|
97
97
|
- `EvaluationStep` _(type)_ — Single step in the access evaluation trace.
|
|
98
|
+
- `ExecutionContext` _(type)_
|
|
99
|
+
- `ExecutionContextSchema` — ExecutionContext — the RUN in which an intent was produced or applied.
|
|
98
100
|
- `ExecutionScope` _(type)_ — Execution scope determines whose identity is used when executing actions. - 'self': Actions execute under the…
|
|
99
101
|
- `FACT_SOURCE_TIER_PRECEDENCE` — Truth hierarchy, highest precedence first.
|
|
100
102
|
- `FactMutation` _(type)_
|
|
@@ -107,6 +109,10 @@ Shared type vocabulary for organization ownership, type classification, and tran
|
|
|
107
109
|
- `FieldCapabilitySchema` — A mutable field's gate: editable, or locked with attribution (sso vs rbac).
|
|
108
110
|
- `FillOpenRoleRequest` _(type)_
|
|
109
111
|
- `FillOpenRoleRequestSchema` — Fill an open role by seating an existing org member (`userId`) or inviting a new person by email.
|
|
112
|
+
- `Finding` _(type)_
|
|
113
|
+
- `FindingSchema` — A single diagnostic the system emits about the org graph — the GENERAL model of which {@link…
|
|
114
|
+
- `FindingSeverity` _(type)_
|
|
115
|
+
- `FindingSeveritySchema` — Severity of a {@link FindingSchema}.
|
|
110
116
|
- `HomeAssignment` _(type)_
|
|
111
117
|
- `HomeAssignmentSchema` — A person's single structural home unit — at most one per person per org.
|
|
112
118
|
- `HomeUnitRole` _(type)_
|
|
@@ -246,6 +252,8 @@ Shared type vocabulary for organization ownership, type classification, and tran
|
|
|
246
252
|
- `PositionSchema`
|
|
247
253
|
- `PositionStatus` _(type)_
|
|
248
254
|
- `PositionStatusSchema` — Lifecycle of a seat's EXISTENCE — distinct from a hiring pipeline.
|
|
255
|
+
- `Provenance` _(type)_
|
|
256
|
+
- `ProvenanceSchema` — Provenance — WHO/WHAT generated an intent.
|
|
249
257
|
- `ProviderStatus` _(type)_ — Provider-level configuration lifecycle.
|
|
250
258
|
- `ProviderSuggestion` _(type)_ — MX-based provider suggestion for SSO setup.
|
|
251
259
|
- `Recommendation` _(type)_
|
|
@@ -3,9 +3,12 @@ import {
|
|
|
3
3
|
OrgIntentSchema,
|
|
4
4
|
FactMutationSchema,
|
|
5
5
|
TransformationOriginSchema,
|
|
6
|
+
ProvenanceSchema,
|
|
7
|
+
ExecutionContextSchema,
|
|
6
8
|
TransformationRequestSchema,
|
|
7
9
|
ConstraintViolationSchema,
|
|
8
10
|
RecommendationSchema,
|
|
11
|
+
FindingSchema,
|
|
9
12
|
TransformStrategySchema,
|
|
10
13
|
SelectionRationaleSchema,
|
|
11
14
|
TransformationPreviewSchema,
|
|
@@ -13,6 +16,9 @@ import {
|
|
|
13
16
|
|
|
14
17
|
const REPORT = "33333333-3333-4333-8333-333333333333";
|
|
15
18
|
const MANAGER = "44444444-4444-4444-8444-444444444444";
|
|
19
|
+
const UNIT = "55555555-5555-4555-8555-555555555555";
|
|
20
|
+
const PARENT_UNIT = "66666666-6666-4666-8666-666666666666";
|
|
21
|
+
const POSITION = "77777777-7777-4777-8777-777777777777";
|
|
16
22
|
|
|
17
23
|
const setManagerIntent = {
|
|
18
24
|
kind: "reporting.setManager" as const,
|
|
@@ -53,6 +59,53 @@ describe("OrgIntentSchema", () => {
|
|
|
53
59
|
}).success,
|
|
54
60
|
).toBe(false);
|
|
55
61
|
});
|
|
62
|
+
|
|
63
|
+
it("accepts a unit.setParent intent with a parent", () => {
|
|
64
|
+
const intent = {
|
|
65
|
+
kind: "unit.setParent" as const,
|
|
66
|
+
unitId: UNIT,
|
|
67
|
+
parentUnitId: PARENT_UNIT,
|
|
68
|
+
};
|
|
69
|
+
expect(OrgIntentSchema.parse(intent)).toEqual(intent);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("accepts a unit.setParent intent with a null parent (unit becomes a root)", () => {
|
|
73
|
+
const intent = {
|
|
74
|
+
kind: "unit.setParent" as const,
|
|
75
|
+
unitId: UNIT,
|
|
76
|
+
parentUnitId: null,
|
|
77
|
+
};
|
|
78
|
+
expect(OrgIntentSchema.parse(intent)).toEqual(intent);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("rejects a non-uuid parentUnitId", () => {
|
|
82
|
+
expect(
|
|
83
|
+
OrgIntentSchema.safeParse({
|
|
84
|
+
kind: "unit.setParent",
|
|
85
|
+
unitId: UNIT,
|
|
86
|
+
parentUnitId: "x",
|
|
87
|
+
}).success,
|
|
88
|
+
).toBe(false);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("accepts a position.setTitle intent", () => {
|
|
92
|
+
const intent = {
|
|
93
|
+
kind: "position.setTitle" as const,
|
|
94
|
+
positionId: POSITION,
|
|
95
|
+
title: "Staff Engineer",
|
|
96
|
+
};
|
|
97
|
+
expect(OrgIntentSchema.parse(intent)).toEqual(intent);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("rejects a position.setTitle intent with an empty title", () => {
|
|
101
|
+
expect(
|
|
102
|
+
OrgIntentSchema.safeParse({
|
|
103
|
+
kind: "position.setTitle",
|
|
104
|
+
positionId: POSITION,
|
|
105
|
+
title: "",
|
|
106
|
+
}).success,
|
|
107
|
+
).toBe(false);
|
|
108
|
+
});
|
|
56
109
|
});
|
|
57
110
|
|
|
58
111
|
describe("FactMutationSchema", () => {
|
|
@@ -77,6 +130,34 @@ describe("FactMutationSchema", () => {
|
|
|
77
130
|
.success,
|
|
78
131
|
).toBe(false);
|
|
79
132
|
});
|
|
133
|
+
|
|
134
|
+
it("accepts a unit.setParent mutation with a parent", () => {
|
|
135
|
+
const mutation = {
|
|
136
|
+
kind: "unit.setParent" as const,
|
|
137
|
+
unitId: UNIT,
|
|
138
|
+
parentUnitId: PARENT_UNIT,
|
|
139
|
+
};
|
|
140
|
+
expect(FactMutationSchema.parse(mutation)).toEqual(mutation);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("accepts a unit.setParent mutation with a null parent (unit becomes a root)", () => {
|
|
144
|
+
expect(
|
|
145
|
+
FactMutationSchema.safeParse({
|
|
146
|
+
kind: "unit.setParent",
|
|
147
|
+
unitId: UNIT,
|
|
148
|
+
parentUnitId: null,
|
|
149
|
+
}).success,
|
|
150
|
+
).toBe(true);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("accepts a position.setTitle mutation", () => {
|
|
154
|
+
const mutation = {
|
|
155
|
+
kind: "position.setTitle" as const,
|
|
156
|
+
positionId: POSITION,
|
|
157
|
+
title: "Principal Engineer",
|
|
158
|
+
};
|
|
159
|
+
expect(FactMutationSchema.parse(mutation)).toEqual(mutation);
|
|
160
|
+
});
|
|
80
161
|
});
|
|
81
162
|
|
|
82
163
|
describe("TransformationOriginSchema", () => {
|
|
@@ -126,6 +207,49 @@ describe("TransformationRequestSchema", () => {
|
|
|
126
207
|
.success,
|
|
127
208
|
).toBe(false);
|
|
128
209
|
});
|
|
210
|
+
|
|
211
|
+
it("accepts an optional executionContext", () => {
|
|
212
|
+
const withCtx = {
|
|
213
|
+
...request,
|
|
214
|
+
executionContext: { runId: "run-42", trigger: "scheduled_sync" },
|
|
215
|
+
};
|
|
216
|
+
expect(TransformationRequestSchema.parse(withCtx)).toEqual(withCtx);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
describe("ProvenanceSchema", () => {
|
|
221
|
+
it("accepts an origin plus optional sourceSystem", () => {
|
|
222
|
+
const provenance = {
|
|
223
|
+
origin: "business_event" as const,
|
|
224
|
+
sourceSystem: "hris",
|
|
225
|
+
};
|
|
226
|
+
expect(ProvenanceSchema.parse(provenance)).toEqual(provenance);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it("accepts an origin without a sourceSystem", () => {
|
|
230
|
+
expect(ProvenanceSchema.safeParse({ origin: "user_intent" }).success).toBe(
|
|
231
|
+
true,
|
|
232
|
+
);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it("rejects an unknown origin", () => {
|
|
236
|
+
expect(ProvenanceSchema.safeParse({ origin: "robot" }).success).toBe(false);
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
describe("ExecutionContextSchema", () => {
|
|
241
|
+
it("accepts runId and trigger", () => {
|
|
242
|
+
const ctx = { runId: "run-1", trigger: "webhook" };
|
|
243
|
+
expect(ExecutionContextSchema.parse(ctx)).toEqual(ctx);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it("accepts an empty context (both fields optional)", () => {
|
|
247
|
+
expect(ExecutionContextSchema.safeParse({}).success).toBe(true);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it("rejects a non-string runId", () => {
|
|
251
|
+
expect(ExecutionContextSchema.safeParse({ runId: 42 }).success).toBe(false);
|
|
252
|
+
});
|
|
129
253
|
});
|
|
130
254
|
|
|
131
255
|
describe("ConstraintViolationSchema", () => {
|
|
@@ -156,6 +280,48 @@ describe("ConstraintViolationSchema", () => {
|
|
|
156
280
|
});
|
|
157
281
|
});
|
|
158
282
|
|
|
283
|
+
describe("FindingSchema", () => {
|
|
284
|
+
it("accepts each severity level", () => {
|
|
285
|
+
for (const severity of ["error", "warning", "info"] as const) {
|
|
286
|
+
expect(
|
|
287
|
+
FindingSchema.safeParse({ code: "topology.ownerless", severity })
|
|
288
|
+
.success,
|
|
289
|
+
).toBe(true);
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it("accepts optional detail and recommendation", () => {
|
|
294
|
+
const finding = {
|
|
295
|
+
code: "reporting.cycle",
|
|
296
|
+
severity: "info" as const,
|
|
297
|
+
subject: REPORT,
|
|
298
|
+
detail: "This seat participates in a reporting loop.",
|
|
299
|
+
recommendation: {
|
|
300
|
+
label: "Move report to new manager",
|
|
301
|
+
mutations: [setManagerMutation],
|
|
302
|
+
cost: 1,
|
|
303
|
+
explanation: ["Breaks the cycle by re-parenting the report."],
|
|
304
|
+
},
|
|
305
|
+
};
|
|
306
|
+
expect(FindingSchema.parse(finding)).toEqual(finding);
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it("rejects an unknown severity", () => {
|
|
310
|
+
expect(
|
|
311
|
+
FindingSchema.safeParse({ code: "c", severity: "fatal" }).success,
|
|
312
|
+
).toBe(false);
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it("parses every ConstraintViolation value (structural superset)", () => {
|
|
316
|
+
const violation = ConstraintViolationSchema.parse({
|
|
317
|
+
code: "reporting.cycle",
|
|
318
|
+
severity: "error",
|
|
319
|
+
subject: REPORT,
|
|
320
|
+
});
|
|
321
|
+
expect(FindingSchema.parse(violation)).toEqual(violation);
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
|
|
159
325
|
describe("RecommendationSchema / TransformStrategySchema", () => {
|
|
160
326
|
const recommendation = {
|
|
161
327
|
label: "Reassign report",
|
package/src/org/company-md.ts
CHANGED
|
@@ -39,15 +39,29 @@ export type CompanyMdDiscoverabilityPolicy = "org" | "owners";
|
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* Information classification for a Company.md node — *what the document is*, for
|
|
42
|
-
* governance, NOT permissions (ADR-CTRL-194 / ADR-BE-338).
|
|
43
|
-
*
|
|
44
|
-
*
|
|
42
|
+
* governance, NOT permissions (ADR-CTRL-194 / ADR-BE-338 / ADR-BE-348). It is the
|
|
43
|
+
* input to the Governance projection and NEVER participates in authorization or
|
|
44
|
+
* discovery (ADR-BE-348 invariant 4).
|
|
45
|
+
*
|
|
46
|
+
* The value is now emitted on the published response schemas (tree + doc) so a
|
|
47
|
+
* consumer can read it. Enforcement behaviors remain deferred — each is named
|
|
48
|
+
* with the concrete trigger that promotes it from decorative to enforced:
|
|
49
|
+
*
|
|
50
|
+
* - **Export watermarking** — wire when a doc-export/download surface ships
|
|
51
|
+
* (`confidential`+ stamps the exporter identity + timestamp).
|
|
52
|
+
* - **Share-approval friction** — wire when external/cross-org sharing exists
|
|
53
|
+
* (`highly_confidential` requires a second approver before an ACL grant lands).
|
|
54
|
+
* - **Retrieval rules** — wire when agent browsing / RAG over knowledge nodes is
|
|
55
|
+
* on (`confidential`+ excluded from un-attributed retrieval contexts).
|
|
56
|
+
* - **Audit verbosity** — wire when the audit sink supports per-class verbosity
|
|
57
|
+
* (`highly_confidential` reads emit a full access record, not a sampled one).
|
|
58
|
+
*
|
|
59
|
+
* Until those surfaces exist there is nothing to gate, so classification is
|
|
60
|
+
* carried, not enforced — a deliberate "named now, enforced on trigger" deferral,
|
|
61
|
+
* not an omission.
|
|
45
62
|
*/
|
|
46
63
|
export type CompanyMdClassification =
|
|
47
|
-
| "
|
|
48
|
-
| "internal"
|
|
49
|
-
| "confidential"
|
|
50
|
-
| "highly_confidential";
|
|
64
|
+
"public" | "internal" | "confidential" | "highly_confidential";
|
|
51
65
|
|
|
52
66
|
/**
|
|
53
67
|
* @deprecated Since 1.12.0. `CompanyMdDocLevel` is superseded by `CompanyMdDocKind` + `depth`.
|
|
@@ -159,6 +173,26 @@ export interface CompanyMdTreeNode extends CompanyMdNodeIdentity {
|
|
|
159
173
|
* unordered types.
|
|
160
174
|
*/
|
|
161
175
|
readonly orderKey?: string;
|
|
176
|
+
/**
|
|
177
|
+
* Combined Authorization + Discovery read-state of this tree node for the
|
|
178
|
+
* requesting actor (ADR-BE-348). The tree now surfaces discoverable nodes a
|
|
179
|
+
* non-reader cannot read, as stubs:
|
|
180
|
+
* - `full`: actor holds a read grant — the normal, fully-navigable node.
|
|
181
|
+
* - `redacted_admin`: non-reader at Discovery `inspectable` (oversight/owner) —
|
|
182
|
+
* a metadata stub.
|
|
183
|
+
* - `locked_requestable`: non-reader at Discovery `listed` — a locked stub.
|
|
184
|
+
* Discovery `hidden` nodes are omitted from the tree entirely (no leak).
|
|
185
|
+
* Omitted on legacy/full-content nodes that predate the stub surface; treat an
|
|
186
|
+
* absent value as `full`.
|
|
187
|
+
*/
|
|
188
|
+
readonly accessState?: "full" | "redacted_admin" | "locked_requestable";
|
|
189
|
+
/**
|
|
190
|
+
* Whether the requesting actor may request access to this node — the same
|
|
191
|
+
* resolver the read affordance uses (ADR-BE-348). Set on non-reader stubs so
|
|
192
|
+
* the tree can render a "Request access" affordance; absent/`false` on nodes
|
|
193
|
+
* the actor already reads.
|
|
194
|
+
*/
|
|
195
|
+
readonly canRequestAccess?: boolean;
|
|
162
196
|
}
|
|
163
197
|
|
|
164
198
|
export interface CompanyMdDocCore extends CompanyMdNodeIdentity {
|
package/src/org/index.ts
CHANGED
|
@@ -157,9 +157,13 @@ export {
|
|
|
157
157
|
OrgIntentSchema,
|
|
158
158
|
FactMutationSchema,
|
|
159
159
|
TransformationOriginSchema,
|
|
160
|
+
ProvenanceSchema,
|
|
161
|
+
ExecutionContextSchema,
|
|
160
162
|
TransformationRequestSchema,
|
|
161
163
|
ConstraintViolationSchema,
|
|
162
164
|
RecommendationSchema,
|
|
165
|
+
FindingSeveritySchema,
|
|
166
|
+
FindingSchema,
|
|
163
167
|
TransformStrategySchema,
|
|
164
168
|
SelectionRationaleSchema,
|
|
165
169
|
TransformationPreviewSchema,
|
|
@@ -168,9 +172,13 @@ export type {
|
|
|
168
172
|
OrgIntent,
|
|
169
173
|
FactMutation,
|
|
170
174
|
TransformationOrigin,
|
|
175
|
+
Provenance,
|
|
176
|
+
ExecutionContext,
|
|
171
177
|
TransformationRequest,
|
|
172
178
|
ConstraintViolation,
|
|
173
179
|
Recommendation,
|
|
180
|
+
FindingSeverity,
|
|
181
|
+
Finding,
|
|
174
182
|
TransformStrategy,
|
|
175
183
|
SelectionRationale,
|
|
176
184
|
TransformationPreview,
|
package/src/org/org-units.ts
CHANGED
|
@@ -23,25 +23,18 @@
|
|
|
23
23
|
|
|
24
24
|
/** Semantic classification — projection-only, never drives traversal. */
|
|
25
25
|
export type OrgUnitClassification =
|
|
26
|
-
| "
|
|
27
|
-
| "org_container"
|
|
28
|
-
| "custom";
|
|
26
|
+
"execution_unit" | "org_container" | "custom";
|
|
29
27
|
|
|
30
28
|
/** External directory reconciliation policy for a unit. */
|
|
31
29
|
export type OrgUnitSyncMode =
|
|
32
|
-
| "
|
|
33
|
-
| "synced_readonly"
|
|
34
|
-
| "synced_with_overrides";
|
|
30
|
+
"manual_only" | "synced_readonly" | "synced_with_overrides";
|
|
35
31
|
|
|
36
32
|
/** Default visibility inherited by new docs under this unit. */
|
|
37
33
|
export type OrgUnitVisibility = "public" | "private" | "restricted";
|
|
38
34
|
|
|
39
35
|
/** Edge classification for `org_unit_relationships`. Graph-only; never structural. */
|
|
40
36
|
export type OrgUnitRelationshipType =
|
|
41
|
-
| "
|
|
42
|
-
| "reports_to"
|
|
43
|
-
| "depends_on"
|
|
44
|
-
| "custom";
|
|
37
|
+
"collaborates_with" | "reports_to" | "depends_on" | "custom";
|
|
45
38
|
|
|
46
39
|
/** Edge role — refines the collaboration nature on a graph edge. */
|
|
47
40
|
export type OrgUnitRelationshipRole = "owner" | "participant" | "supporting";
|
|
@@ -51,10 +44,7 @@ export type OrgUnitMembershipStatus = "active" | "pending" | "removed";
|
|
|
51
44
|
|
|
52
45
|
/** External directory origin of a membership row. */
|
|
53
46
|
export type OrgUnitMembershipSource =
|
|
54
|
-
| "
|
|
55
|
-
| "google_groups"
|
|
56
|
-
| "scim"
|
|
57
|
-
| "hris";
|
|
47
|
+
"manual" | "google_groups" | "scim" | "hris";
|
|
58
48
|
|
|
59
49
|
/**
|
|
60
50
|
* Hiring lifecycle of an open role — a persisted placeholder for the person
|
package/src/org/sharing.ts
CHANGED
|
@@ -12,10 +12,7 @@ export type AccessLevel = "viewer" | "commenter" | "editor";
|
|
|
12
12
|
* - org_edit: All org members can edit (does NOT imply canShare)
|
|
13
13
|
*/
|
|
14
14
|
export type SharePolicy =
|
|
15
|
-
| "
|
|
16
|
-
| "org_read"
|
|
17
|
-
| "org_comment"
|
|
18
|
-
| "org_edit";
|
|
15
|
+
"restricted" | "org_read" | "org_comment" | "org_edit";
|
|
19
16
|
|
|
20
17
|
export interface AclEntry {
|
|
21
18
|
readonly principalType: "user" | "unit";
|
|
@@ -11,9 +11,12 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Layers, smallest → largest:
|
|
13
13
|
* - {@link OrgIntentSchema} — WHAT the operator wants, as a discriminated union
|
|
14
|
-
* on `kind
|
|
14
|
+
* on `kind`: `reporting.setManager` (point a seat at a manager),
|
|
15
|
+
* `unit.setParent` (re-parent an org unit, null parent → root), and
|
|
16
|
+
* `position.setTitle` (relabel a seat). Shaped so further kinds
|
|
15
17
|
* (home.setUnit, unit.move, position.open, position.close) append without
|
|
16
|
-
* breaking existing consumers.
|
|
18
|
+
* breaking existing consumers. Any consumer that exhaustively switches on
|
|
19
|
+
* `kind` (an `assertNever` default arm) MUST add an arm for each new kind.
|
|
17
20
|
* - {@link FactMutationSchema} — the typed ATOMIC fact change the engine applies
|
|
18
21
|
* to the live graph. Distinct from intent: an intent may expand into several
|
|
19
22
|
* mutations, and a mutation can express un-setting (a null target) that an
|
|
@@ -47,12 +50,30 @@ import { z } from "zod";
|
|
|
47
50
|
|
|
48
51
|
/**
|
|
49
52
|
* A requested org-graph change expressed as intent. Discriminated on `kind`, a
|
|
50
|
-
* dotted string naming the affected relation and verb
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
53
|
+
* dotted string naming the affected relation and verb:
|
|
54
|
+
* - `reporting.setManager` — point a reporting seat at a (non-null) manager seat.
|
|
55
|
+
* - `unit.setParent` — re-parent an org unit; `parentUnitId` null means the unit
|
|
56
|
+
* becomes a root (level-1) unit, which is a meaningful intent, not an un-set.
|
|
57
|
+
* - `position.setTitle` — relabel a seat's human-facing title.
|
|
58
|
+
*
|
|
59
|
+
* These are the intents the reasoning pipeline's NestOrgUnit (→ `unit.setParent`)
|
|
60
|
+
* and NormalizeRole (→ `position.setTitle`) inferences resolve into, after
|
|
61
|
+
* external→canonical id resolution, so every id here is a canonical uuid.
|
|
62
|
+
*
|
|
63
|
+
* Further kinds (`home.setUnit`, `unit.move`, `position.open`, `position.close`)
|
|
64
|
+
* append as new union members without breaking consumers. Appending is
|
|
65
|
+
* backward-compatible for producers and for consumers that do not exhaustively
|
|
66
|
+
* switch on `kind`; any consumer that DOES exhaustively switch (an `assertNever`
|
|
67
|
+
* default arm on `OrgIntent.kind`) MUST add an arm for each new kind.
|
|
54
68
|
*/
|
|
55
69
|
export const OrgIntentSchema = z.discriminatedUnion("kind", [
|
|
70
|
+
// reporting.setManager — UNCHANGED from the shipped PRD-00823 vocabulary. This
|
|
71
|
+
// PRD (00827) is purely additive: it appends unit.setParent and
|
|
72
|
+
// position.setTitle below and touches neither this arm's fields nor its types.
|
|
73
|
+
// Its `managerPositionId` is intentionally NON-NULLABLE here (an intent points
|
|
74
|
+
// a seat AT a manager); the corresponding FactMutation arm keeps it nullable so
|
|
75
|
+
// a mutation can un-set the edge. That Intent-vs-Mutation asymmetry is the
|
|
76
|
+
// original by-design shape, not something this PRD introduced or altered.
|
|
56
77
|
z.object({
|
|
57
78
|
kind: z.literal("reporting.setManager"),
|
|
58
79
|
/** The reporting (subordinate) seat whose manager is being set. */
|
|
@@ -60,6 +81,20 @@ export const OrgIntentSchema = z.discriminatedUnion("kind", [
|
|
|
60
81
|
/** The manager seat to report to. Non-null on an intent (un-setting is a mutation concern). */
|
|
61
82
|
managerPositionId: z.string().uuid(),
|
|
62
83
|
}),
|
|
84
|
+
z.object({
|
|
85
|
+
kind: z.literal("unit.setParent"),
|
|
86
|
+
/** The org unit being re-parented. */
|
|
87
|
+
unitId: z.string().uuid(),
|
|
88
|
+
/** The new parent unit, or `null` to make the unit a root (level-1) unit. */
|
|
89
|
+
parentUnitId: z.string().uuid().nullable(),
|
|
90
|
+
}),
|
|
91
|
+
z.object({
|
|
92
|
+
kind: z.literal("position.setTitle"),
|
|
93
|
+
/** The seat whose title is being set. */
|
|
94
|
+
positionId: z.string().uuid(),
|
|
95
|
+
/** The new human-facing title for the seat (non-empty, matching PositionSchema.title). */
|
|
96
|
+
title: z.string().min(1),
|
|
97
|
+
}),
|
|
63
98
|
]);
|
|
64
99
|
export type OrgIntent = z.infer<typeof OrgIntentSchema>;
|
|
65
100
|
|
|
@@ -72,8 +107,19 @@ export type OrgIntent = z.infer<typeof OrgIntentSchema>;
|
|
|
72
107
|
* Discriminated on `kind`, mirroring {@link OrgIntentSchema}. Unlike an intent,
|
|
73
108
|
* a mutation can express UN-SETTING: `reporting.setManager` with a null
|
|
74
109
|
* `managerPositionId` clears the seat's manager edge entirely.
|
|
110
|
+
*
|
|
111
|
+
* `unit.setParent` and `position.setTitle` mirror their intent counterparts.
|
|
112
|
+
* `unit.setParent.parentUnitId` is nullable here for the SAME reason it is on the
|
|
113
|
+
* intent — null means "root", a meaningful target — not because a mutation
|
|
114
|
+
* un-sets it. Any consumer that exhaustively switches on `FactMutation.kind`
|
|
115
|
+
* (an `assertNever` default arm) MUST add an arm for each new kind.
|
|
75
116
|
*/
|
|
76
117
|
export const FactMutationSchema = z.discriminatedUnion("kind", [
|
|
118
|
+
// reporting.setManager — UNCHANGED from the shipped PRD-00823 vocabulary; this
|
|
119
|
+
// PRD (00827) only appends unit.setParent and position.setTitle below. Its
|
|
120
|
+
// `managerPositionId` stays NULLABLE (a mutation can un-set the edge), which is
|
|
121
|
+
// deliberately broader than the OrgIntent arm's non-nullable field — the
|
|
122
|
+
// original, intentional Intent-vs-Mutation asymmetry, preserved as-is.
|
|
77
123
|
z.object({
|
|
78
124
|
kind: z.literal("reporting.setManager"),
|
|
79
125
|
/** The reporting (subordinate) seat whose manager edge is being written. */
|
|
@@ -81,6 +127,20 @@ export const FactMutationSchema = z.discriminatedUnion("kind", [
|
|
|
81
127
|
/** The new manager seat, or `null` to un-set (clear) the manager edge. */
|
|
82
128
|
managerPositionId: z.string().uuid().nullable(),
|
|
83
129
|
}),
|
|
130
|
+
z.object({
|
|
131
|
+
kind: z.literal("unit.setParent"),
|
|
132
|
+
/** The org unit whose parent edge is being written. */
|
|
133
|
+
unitId: z.string().uuid(),
|
|
134
|
+
/** The new parent unit, or `null` to make the unit a root (level-1) unit. */
|
|
135
|
+
parentUnitId: z.string().uuid().nullable(),
|
|
136
|
+
}),
|
|
137
|
+
z.object({
|
|
138
|
+
kind: z.literal("position.setTitle"),
|
|
139
|
+
/** The seat whose title is being written. */
|
|
140
|
+
positionId: z.string().uuid(),
|
|
141
|
+
/** The new human-facing title for the seat (non-empty, matching PositionSchema.title). */
|
|
142
|
+
title: z.string().min(1),
|
|
143
|
+
}),
|
|
84
144
|
]);
|
|
85
145
|
export type FactMutation = z.infer<typeof FactMutationSchema>;
|
|
86
146
|
|
|
@@ -100,6 +160,37 @@ export const TransformationOriginSchema = z.enum([
|
|
|
100
160
|
]);
|
|
101
161
|
export type TransformationOrigin = z.infer<typeof TransformationOriginSchema>;
|
|
102
162
|
|
|
163
|
+
/**
|
|
164
|
+
* Provenance — WHO/WHAT generated an intent. Distinct from motivation (the
|
|
165
|
+
* free-text {@link TransformationRequestSchema} `reason`, which records *why*)
|
|
166
|
+
* and from {@link ExecutionContextSchema} (the *run* the intent happened in).
|
|
167
|
+
* `origin` reuses the closed {@link TransformationOriginSchema} enum; the
|
|
168
|
+
* optional `sourceSystem` names the concrete system or actor that emitted it
|
|
169
|
+
* (e.g. an HRIS connector id) for machine-originated intents.
|
|
170
|
+
*/
|
|
171
|
+
export const ProvenanceSchema = z.object({
|
|
172
|
+
/** Provenance class of the intent — reuses the closed origin enum. */
|
|
173
|
+
origin: TransformationOriginSchema,
|
|
174
|
+
/** Optional concrete system/actor that emitted the intent. */
|
|
175
|
+
sourceSystem: z.string().optional(),
|
|
176
|
+
});
|
|
177
|
+
export type Provenance = z.infer<typeof ProvenanceSchema>;
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* ExecutionContext — the RUN in which an intent was produced or applied. Kept
|
|
181
|
+
* separate from {@link ProvenanceSchema} (who/what generated it) and from
|
|
182
|
+
* motivation ({@link TransformationRequestSchema} `reason`). Both fields are
|
|
183
|
+
* optional: `runId` correlates the intent to a batch/job, `trigger` names what
|
|
184
|
+
* kicked off that run (e.g. a webhook or scheduled sync).
|
|
185
|
+
*/
|
|
186
|
+
export const ExecutionContextSchema = z.object({
|
|
187
|
+
/** Optional id correlating the intent to a batch/job run. */
|
|
188
|
+
runId: z.string().optional(),
|
|
189
|
+
/** Optional label for what kicked off the run (e.g. "scheduled_sync"). */
|
|
190
|
+
trigger: z.string().optional(),
|
|
191
|
+
});
|
|
192
|
+
export type ExecutionContext = z.infer<typeof ExecutionContextSchema>;
|
|
193
|
+
|
|
103
194
|
export const TransformationRequestSchema = z.object({
|
|
104
195
|
/** Provenance class of the request — drives how much scrutiny it gets. */
|
|
105
196
|
origin: TransformationOriginSchema,
|
|
@@ -112,6 +203,12 @@ export const TransformationRequestSchema = z.object({
|
|
|
112
203
|
* change was requested, NOT who may make it (ADR-CTRL-180).
|
|
113
204
|
*/
|
|
114
205
|
reason: z.string().max(2000).nullable().optional(),
|
|
206
|
+
/**
|
|
207
|
+
* Optional {@link ExecutionContextSchema} — the run this intent was produced
|
|
208
|
+
* in. Additive and distinct from `origin` (provenance class) and `reason`
|
|
209
|
+
* (motivation); absent for ad-hoc requests. (ADR-CONTRACTS-074)
|
|
210
|
+
*/
|
|
211
|
+
executionContext: ExecutionContextSchema.optional(),
|
|
115
212
|
});
|
|
116
213
|
export type TransformationRequest = z.infer<typeof TransformationRequestSchema>;
|
|
117
214
|
|
|
@@ -153,6 +250,52 @@ export const RecommendationSchema = z.object({
|
|
|
153
250
|
});
|
|
154
251
|
export type Recommendation = z.infer<typeof RecommendationSchema>;
|
|
155
252
|
|
|
253
|
+
// ---------------------------------------------------------------------------
|
|
254
|
+
// Finding — the general diagnostic model (superset of ConstraintViolation)
|
|
255
|
+
// ---------------------------------------------------------------------------
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Severity of a {@link FindingSchema}. Broader than
|
|
259
|
+
* {@link ConstraintViolationSchema}'s `error | warning`: `info` is the added
|
|
260
|
+
* non-blocking, non-cautionary level a diagnostic-only (Observation) producer
|
|
261
|
+
* emits. `error` blocks a change; `warning` allows it but flags a caution;
|
|
262
|
+
* `info` is purely descriptive.
|
|
263
|
+
*/
|
|
264
|
+
export const FindingSeveritySchema = z.enum(["error", "warning", "info"]);
|
|
265
|
+
export type FindingSeverity = z.infer<typeof FindingSeveritySchema>;
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* A single diagnostic the system emits about the org graph — the GENERAL model
|
|
269
|
+
* of which {@link ConstraintViolationSchema} is the error-severity subtype.
|
|
270
|
+
*
|
|
271
|
+
* Finding is a structural SUPERSET of ConstraintViolation: it carries the same
|
|
272
|
+
* `code` / `severity` / `subject` fields, widens `severity` to include `info`
|
|
273
|
+
* (via {@link FindingSeveritySchema}), and adds an optional human-readable
|
|
274
|
+
* `detail` and an optional {@link RecommendationSchema} pointing at a suggested
|
|
275
|
+
* fix. Every ConstraintViolation value therefore parses as a Finding.
|
|
276
|
+
*
|
|
277
|
+
* The Constraint Engine emits the error-severity Findings today, modeled as
|
|
278
|
+
* {@link ConstraintViolationSchema} (which stays unchanged). A future
|
|
279
|
+
* Observation Engine produces the broader `info`/`warning` Findings — advisory
|
|
280
|
+
* diagnostics that describe the graph without blocking a change.
|
|
281
|
+
*
|
|
282
|
+
* @see ConstraintViolationSchema — the unchanged error-severity subtype
|
|
283
|
+
* @see ADR-CONTRACTS-074 for the org mutation / diagnostic vocabulary decision
|
|
284
|
+
*/
|
|
285
|
+
export const FindingSchema = z.object({
|
|
286
|
+
/** Open string naming the finding (e.g. "reporting.cycle", "span.wide"). */
|
|
287
|
+
code: z.string().min(1),
|
|
288
|
+
/** `error` blocks; `warning` cautions; `info` is purely descriptive. */
|
|
289
|
+
severity: FindingSeveritySchema,
|
|
290
|
+
/** Optional id of the entity the finding concerns. */
|
|
291
|
+
subject: z.string().optional(),
|
|
292
|
+
/** Optional human-readable elaboration of the finding. */
|
|
293
|
+
detail: z.string().optional(),
|
|
294
|
+
/** Optional suggested fix for the finding. */
|
|
295
|
+
recommendation: RecommendationSchema.optional(),
|
|
296
|
+
});
|
|
297
|
+
export type Finding = z.infer<typeof FindingSchema>;
|
|
298
|
+
|
|
156
299
|
// ---------------------------------------------------------------------------
|
|
157
300
|
// TransformStrategy — a scored set of recommendations
|
|
158
301
|
// ---------------------------------------------------------------------------
|
package/src/org/types.ts
CHANGED
|
@@ -292,10 +292,7 @@ export interface OidcValidationResult {
|
|
|
292
292
|
authorizationEndpoint?: string;
|
|
293
293
|
error?: string;
|
|
294
294
|
errorCode?:
|
|
295
|
-
| "
|
|
296
|
-
| "INVALID_DOCUMENT"
|
|
297
|
-
| "MISSING_FIELDS"
|
|
298
|
-
| "SSRF_BLOCKED";
|
|
295
|
+
"UNREACHABLE" | "INVALID_DOCUMENT" | "MISSING_FIELDS" | "SSRF_BLOCKED";
|
|
299
296
|
}
|
|
300
297
|
|
|
301
298
|
/** Initiation payload for a test SSO login attempt. */
|
package/src/ralph/prd.ts
CHANGED
|
@@ -48,11 +48,7 @@ export type AllowedRepo = (typeof REPO_PRECEDENCE)[number];
|
|
|
48
48
|
* Used for prioritization and verification strategy selection.
|
|
49
49
|
*/
|
|
50
50
|
export type RalphPRDCategory =
|
|
51
|
-
| "
|
|
52
|
-
| "architectural"
|
|
53
|
-
| "integration"
|
|
54
|
-
| "polish"
|
|
55
|
-
| "validation";
|
|
51
|
+
"functional" | "architectural" | "integration" | "polish" | "validation";
|
|
56
52
|
|
|
57
53
|
/**
|
|
58
54
|
* Priority level for feature ordering.
|
|
@@ -26,13 +26,7 @@ import type { DiagramNode, FlowStage } from "./index";
|
|
|
26
26
|
* Add new repos here as the system grows.
|
|
27
27
|
*/
|
|
28
28
|
export type RepoId =
|
|
29
|
-
| "
|
|
30
|
-
| "edge"
|
|
31
|
-
| "app"
|
|
32
|
-
| "site"
|
|
33
|
-
| "ci"
|
|
34
|
-
| "contracts"
|
|
35
|
-
| "control";
|
|
29
|
+
"backend" | "edge" | "app" | "site" | "ci" | "contracts" | "control";
|
|
36
30
|
|
|
37
31
|
/**
|
|
38
32
|
* Semantic invariants for a capability.
|
package/src/system/diagram.ts
CHANGED
|
@@ -59,12 +59,7 @@ export type DiagramNodeKind = "repo" | "group" | "feature" | "artifact";
|
|
|
59
59
|
* - feedback: Bidirectional loop
|
|
60
60
|
*/
|
|
61
61
|
export type DiagramEdgeRelation =
|
|
62
|
-
| "
|
|
63
|
-
| "emits"
|
|
64
|
-
| "authorizes"
|
|
65
|
-
| "reads"
|
|
66
|
-
| "depends_on"
|
|
67
|
-
| "feedback";
|
|
62
|
+
"invokes" | "emits" | "authorizes" | "reads" | "depends_on" | "feedback";
|
|
68
63
|
|
|
69
64
|
/**
|
|
70
65
|
* Edge direction semantics.
|