@company-semantics/contracts 90.0.0 → 91.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 +2 -2
- package/src/affordances/README.md +65 -0
- package/src/affordances/__tests__/README.md +30 -0
- package/src/affordances/__tests__/affordances.test.ts +251 -0
- package/src/affordances/affordance.ts +124 -0
- package/src/affordances/args.ts +59 -0
- package/src/affordances/availability.ts +78 -0
- package/src/affordances/ids.ts +45 -0
- package/src/affordances/index.ts +39 -0
- package/src/api/generated-spec-hash.ts +2 -2
- package/src/api/generated.ts +458 -2
- package/src/generated/openapi-routes.ts +4 -0
- package/src/proactive/README.md +26 -4
- package/src/proactive/__tests__/README.md +10 -0
- package/src/proactive/__tests__/chat-templates.test.ts +8 -0
- package/src/proactive/__tests__/vocabulary.test.ts +11 -0
- package/src/proactive/__tests__/workflow-attention-fixtures.ts +49 -0
- package/src/proactive/__tests__/workflow-attention.test.ts +146 -0
- package/src/proactive/composer.ts +8 -0
- package/src/proactive/facts.ts +36 -0
- package/src/proactive/index.ts +2 -0
- package/src/proactive/kinds.ts +29 -0
- package/src/proactive/registry.ts +22 -0
- package/src/proactive/surfaces.ts +2 -0
- package/src/proactive/templates/README.md +9 -1
- package/src/proactive/templates/index.ts +2 -0
- package/src/proactive/templates/workflow-needs-attention.ts +35 -0
- package/src/root-exports/README.md +1 -0
- package/src/root-exports/delivery.ts +69 -1
- package/src/user-notifications/README.md +8 -0
- package/src/user-notifications/kinds.ts +13 -0
- package/src/user-notifications/lifecycle-registry.ts +10 -0
- package/src/workflows/README.md +44 -6
- package/src/workflows/__tests__/README.md +21 -2
- package/src/workflows/__tests__/affordances-of-outcome.test.ts +96 -0
- package/src/workflows/__tests__/deferred-route.test.ts +167 -0
- package/src/workflows/__tests__/outcome.test.ts +68 -3
- package/src/workflows/affordances-of-outcome.ts +64 -0
- package/src/workflows/deferred-route.ts +242 -0
- package/src/workflows/index.ts +51 -11
- package/src/workflows/outcome-reasons.ts +244 -0
- package/src/workflows/outcome.ts +50 -148
package/src/workflows/outcome.ts
CHANGED
|
@@ -16,12 +16,18 @@
|
|
|
16
16
|
* record: a renderer that switches on `reason` is exhaustive, and a new fact is
|
|
17
17
|
* a schema change, not a new spelling.
|
|
18
18
|
* - KIND IS A FUNCTION OF REASON. `kind` is carried for consumers that only care
|
|
19
|
-
* about the shape of the ending, but it is fixed by the per-type table
|
|
20
|
-
* (`*_OUTCOME_KIND_OF_REASON`) and the schema
|
|
19
|
+
* about the shape of the ending, but it is fixed by the per-type table
|
|
20
|
+
* (`*_OUTCOME_KIND_OF_REASON` in `./outcome-reasons.ts`) and the schema
|
|
21
|
+
* refuses any other pairing.
|
|
21
22
|
* - DISPOSITION IS EXPLICIT. `review` names the input request a person decides
|
|
22
23
|
* on; `narrate` means the ending is told, not reviewed. `produced` does not
|
|
23
24
|
* imply a review surface, and only a `produced` or `partial` outcome may carry
|
|
24
25
|
* `review`.
|
|
26
|
+
* - THE OFFER IS A FUNCTION OF REASON. `affordances` is the ordered list of
|
|
27
|
+
* next steps the ending offers (control ADR affordance-system), fixed by the
|
|
28
|
+
* per-type `*_AFFORDANCES_OF_REASON` table and frozen with the outcome. The
|
|
29
|
+
* schema refuses any other list. A projected affordance (`review.open`) is
|
|
30
|
+
* never stored here: it is derived from the `review` disposition.
|
|
25
31
|
* - `unknown` IS A SAFETY VALVE for a terminal transition the classifier did not
|
|
26
32
|
* recognize. It is never used for a failure to OBSERVE a workflow: a workflow
|
|
27
33
|
* whose state cannot be read has no outcome yet.
|
|
@@ -32,27 +38,26 @@
|
|
|
32
38
|
*/
|
|
33
39
|
import { z } from "zod";
|
|
34
40
|
|
|
41
|
+
import {
|
|
42
|
+
MAX_OFFERED_AFFORDANCES,
|
|
43
|
+
OfferedAffordanceSchema,
|
|
44
|
+
sameAffordances,
|
|
45
|
+
type OfferedAffordance,
|
|
46
|
+
} from "../affordances/affordance";
|
|
35
47
|
import { INPUT_REQUEST_TYPES } from "../input-requests/types";
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
/** The run went silent and the reconciler closed it. */
|
|
50
|
-
"abandoned",
|
|
51
|
-
/** A terminal transition the classifier did not recognize. */
|
|
52
|
-
"unknown",
|
|
53
|
-
] as const;
|
|
54
|
-
|
|
55
|
-
export type WorkflowOutcomeKind = (typeof WORKFLOW_OUTCOME_KINDS)[number];
|
|
48
|
+
import {
|
|
49
|
+
DISCOVER_AFFORDANCES_OF_REASON,
|
|
50
|
+
DISCOVER_OUTCOME_KIND_OF_REASON,
|
|
51
|
+
DiscoverOutcomeFactsSchema,
|
|
52
|
+
ORG_STRUCTURE_AFFORDANCES_OF_REASON,
|
|
53
|
+
ORG_STRUCTURE_OUTCOME_KIND_OF_REASON,
|
|
54
|
+
OrgStructureOutcomeFactsSchema,
|
|
55
|
+
SYNTHESIZE_AFFORDANCES_OF_REASON,
|
|
56
|
+
SYNTHESIZE_OUTCOME_KIND_OF_REASON,
|
|
57
|
+
SynthesizeOutcomeFactsSchema,
|
|
58
|
+
WORKFLOW_OUTCOME_KINDS,
|
|
59
|
+
type WorkflowOutcomeKind,
|
|
60
|
+
} from "./outcome-reasons";
|
|
56
61
|
|
|
57
62
|
const KindSchema = z.enum(WORKFLOW_OUTCOME_KINDS);
|
|
58
63
|
|
|
@@ -74,131 +79,6 @@ export type WorkflowOutcomeDisposition = z.infer<
|
|
|
74
79
|
|
|
75
80
|
const Count = z.number().int().nonnegative();
|
|
76
81
|
|
|
77
|
-
// ---------------------------------------------------------------------------
|
|
78
|
-
// source-sync/discover
|
|
79
|
-
// ---------------------------------------------------------------------------
|
|
80
|
-
|
|
81
|
-
/** Why a Drive discovery run ended the way it did. */
|
|
82
|
-
export const DISCOVER_OUTCOME_KIND_OF_REASON = {
|
|
83
|
-
candidates_found: "produced",
|
|
84
|
-
nothing_found: "empty",
|
|
85
|
-
nothing_relevant: "empty",
|
|
86
|
-
budget_exhausted: "partial",
|
|
87
|
-
file_ceiling: "partial",
|
|
88
|
-
stopped_by_user: "stopped",
|
|
89
|
-
plan_coverage_refused: "failed",
|
|
90
|
-
billing_refused: "failed",
|
|
91
|
-
drive_auth: "failed",
|
|
92
|
-
drive_unavailable: "failed",
|
|
93
|
-
no_connection: "failed",
|
|
94
|
-
source_sync_off: "failed",
|
|
95
|
-
internal_error: "failed",
|
|
96
|
-
abandoned: "abandoned",
|
|
97
|
-
unrecognized_terminal_state: "unknown",
|
|
98
|
-
} as const satisfies Record<string, WorkflowOutcomeKind>;
|
|
99
|
-
|
|
100
|
-
export type DiscoverOutcomeReason =
|
|
101
|
-
keyof typeof DISCOVER_OUTCOME_KIND_OF_REASON;
|
|
102
|
-
|
|
103
|
-
/** The counts a discovery run reports at its end. */
|
|
104
|
-
export const DiscoverOutcomeFactsSchema = z
|
|
105
|
-
.object({
|
|
106
|
-
probesTotal: Count,
|
|
107
|
-
probesDone: Count,
|
|
108
|
-
filesSeen: Count,
|
|
109
|
-
filesShown: Count,
|
|
110
|
-
filesHidden: Count,
|
|
111
|
-
filesDropped: Count,
|
|
112
|
-
coveragePercent: z.number().min(0).max(100).nullable(),
|
|
113
|
-
})
|
|
114
|
-
.strict();
|
|
115
|
-
|
|
116
|
-
export type DiscoverOutcomeFacts = z.infer<typeof DiscoverOutcomeFactsSchema>;
|
|
117
|
-
|
|
118
|
-
// ---------------------------------------------------------------------------
|
|
119
|
-
// source-sync/synthesize
|
|
120
|
-
// ---------------------------------------------------------------------------
|
|
121
|
-
|
|
122
|
-
/** Why a synthesis (landing then drafting) run ended the way it did. */
|
|
123
|
-
export const SYNTHESIZE_OUTCOME_KIND_OF_REASON = {
|
|
124
|
-
updates_ready: "produced",
|
|
125
|
-
updates_applied: "produced",
|
|
126
|
-
stopped_by_user: "stopped",
|
|
127
|
-
paused_billing: "failed",
|
|
128
|
-
synthesis_incomplete: "failed",
|
|
129
|
-
approval_mismatch: "failed",
|
|
130
|
-
landing_refused: "failed",
|
|
131
|
-
standing_order_refused: "failed",
|
|
132
|
-
no_connection: "failed",
|
|
133
|
-
source_sync_off: "failed",
|
|
134
|
-
internal_error: "failed",
|
|
135
|
-
abandoned: "abandoned",
|
|
136
|
-
unrecognized_terminal_state: "unknown",
|
|
137
|
-
} as const satisfies Record<string, WorkflowOutcomeKind>;
|
|
138
|
-
|
|
139
|
-
export type SynthesizeOutcomeReason =
|
|
140
|
-
keyof typeof SYNTHESIZE_OUTCOME_KIND_OF_REASON;
|
|
141
|
-
|
|
142
|
-
/** The counts a synthesis run reports at its end. */
|
|
143
|
-
export const SynthesizeOutcomeFactsSchema = z
|
|
144
|
-
.object({
|
|
145
|
-
/** Approved scopes the run read. */
|
|
146
|
-
scopeCount: Count,
|
|
147
|
-
/** Authority or size violations that left the batch incomplete. */
|
|
148
|
-
violationCount: Count,
|
|
149
|
-
})
|
|
150
|
-
.strict();
|
|
151
|
-
|
|
152
|
-
export type SynthesizeOutcomeFacts = z.infer<
|
|
153
|
-
typeof SynthesizeOutcomeFactsSchema
|
|
154
|
-
>;
|
|
155
|
-
|
|
156
|
-
// ---------------------------------------------------------------------------
|
|
157
|
-
// org-structure/hris-connect and org-structure/reanalyze
|
|
158
|
-
// ---------------------------------------------------------------------------
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Why an org-structure analysis ended the way it did. Shared by both
|
|
162
|
-
* org-structure workflow types: they run the same analysis. The directory-only
|
|
163
|
-
* endings (`directory_synced`, `analysis_already_running`, `sync_failed`) occur
|
|
164
|
-
* only on `org-structure/hris-connect`, which syncs the directory first.
|
|
165
|
-
*/
|
|
166
|
-
export const ORG_STRUCTURE_OUTCOME_KIND_OF_REASON = {
|
|
167
|
-
proposal_ready: "produced",
|
|
168
|
-
directory_synced: "produced",
|
|
169
|
-
analysis_already_running: "produced",
|
|
170
|
-
proposal_blocked: "failed",
|
|
171
|
-
no_sync_run: "empty",
|
|
172
|
-
no_persons: "empty",
|
|
173
|
-
reporting_not_keyed: "empty",
|
|
174
|
-
stopped_by_user: "stopped",
|
|
175
|
-
sync_failed: "failed",
|
|
176
|
-
snapshot_too_large: "failed",
|
|
177
|
-
model_failed: "failed",
|
|
178
|
-
run_too_large: "failed",
|
|
179
|
-
placement_failed: "failed",
|
|
180
|
-
internal_error: "failed",
|
|
181
|
-
abandoned: "abandoned",
|
|
182
|
-
unrecognized_terminal_state: "unknown",
|
|
183
|
-
} as const satisfies Record<string, WorkflowOutcomeKind>;
|
|
184
|
-
|
|
185
|
-
export type OrgStructureOutcomeReason =
|
|
186
|
-
keyof typeof ORG_STRUCTURE_OUTCOME_KIND_OF_REASON;
|
|
187
|
-
|
|
188
|
-
/** The counts a finished org-structure proposal carries. */
|
|
189
|
-
export const OrgStructureOutcomeFactsSchema = z
|
|
190
|
-
.object({
|
|
191
|
-
departmentCount: Count,
|
|
192
|
-
teamCount: Count,
|
|
193
|
-
placedCount: Count,
|
|
194
|
-
reviewItemCount: Count,
|
|
195
|
-
})
|
|
196
|
-
.strict();
|
|
197
|
-
|
|
198
|
-
export type OrgStructureOutcomeFacts = z.infer<
|
|
199
|
-
typeof OrgStructureOutcomeFactsSchema
|
|
200
|
-
>;
|
|
201
|
-
|
|
202
82
|
// ---------------------------------------------------------------------------
|
|
203
83
|
// The union
|
|
204
84
|
// ---------------------------------------------------------------------------
|
|
@@ -207,7 +87,12 @@ function memberSchema<
|
|
|
207
87
|
T extends string,
|
|
208
88
|
R extends Record<string, WorkflowOutcomeKind>,
|
|
209
89
|
F extends z.ZodTypeAny,
|
|
210
|
-
>(
|
|
90
|
+
>(
|
|
91
|
+
workflowType: T,
|
|
92
|
+
kindOfReason: R,
|
|
93
|
+
facts: F,
|
|
94
|
+
affordancesOfReason: Record<keyof R, readonly OfferedAffordance[]>,
|
|
95
|
+
) {
|
|
211
96
|
const reasons = Object.keys(kindOfReason) as [
|
|
212
97
|
keyof R & string,
|
|
213
98
|
...(keyof R & string)[],
|
|
@@ -221,6 +106,10 @@ function memberSchema<
|
|
|
221
106
|
reason: z.enum(reasons),
|
|
222
107
|
facts: facts.nullable(),
|
|
223
108
|
disposition: WorkflowOutcomeDispositionSchema,
|
|
109
|
+
/** The next steps this ending offers, frozen with it (see the table). */
|
|
110
|
+
affordances: z
|
|
111
|
+
.array(OfferedAffordanceSchema)
|
|
112
|
+
.max(MAX_OFFERED_AFFORDANCES),
|
|
224
113
|
})
|
|
225
114
|
.strict()
|
|
226
115
|
.superRefine((outcome, ctx) => {
|
|
@@ -243,6 +132,15 @@ function memberSchema<
|
|
|
243
132
|
message: "only a produced or partial outcome may hand off to review",
|
|
244
133
|
});
|
|
245
134
|
}
|
|
135
|
+
const offered = affordancesOfReason[outcome.reason as keyof R];
|
|
136
|
+
if (!sameAffordances(outcome.affordances, offered)) {
|
|
137
|
+
ctx.addIssue({
|
|
138
|
+
code: z.ZodIssueCode.custom,
|
|
139
|
+
path: ["affordances"],
|
|
140
|
+
message:
|
|
141
|
+
"an outcome offers exactly its reason's affordances, in order",
|
|
142
|
+
});
|
|
143
|
+
}
|
|
246
144
|
});
|
|
247
145
|
}
|
|
248
146
|
|
|
@@ -250,21 +148,25 @@ export const DiscoverWorkflowOutcomeSchema = memberSchema(
|
|
|
250
148
|
"source-sync/discover",
|
|
251
149
|
DISCOVER_OUTCOME_KIND_OF_REASON,
|
|
252
150
|
DiscoverOutcomeFactsSchema,
|
|
151
|
+
DISCOVER_AFFORDANCES_OF_REASON,
|
|
253
152
|
);
|
|
254
153
|
export const SynthesizeWorkflowOutcomeSchema = memberSchema(
|
|
255
154
|
"source-sync/synthesize",
|
|
256
155
|
SYNTHESIZE_OUTCOME_KIND_OF_REASON,
|
|
257
156
|
SynthesizeOutcomeFactsSchema,
|
|
157
|
+
SYNTHESIZE_AFFORDANCES_OF_REASON,
|
|
258
158
|
);
|
|
259
159
|
export const HrisConnectWorkflowOutcomeSchema = memberSchema(
|
|
260
160
|
"org-structure/hris-connect",
|
|
261
161
|
ORG_STRUCTURE_OUTCOME_KIND_OF_REASON,
|
|
262
162
|
OrgStructureOutcomeFactsSchema,
|
|
163
|
+
ORG_STRUCTURE_AFFORDANCES_OF_REASON,
|
|
263
164
|
);
|
|
264
165
|
export const ReanalyzeWorkflowOutcomeSchema = memberSchema(
|
|
265
166
|
"org-structure/reanalyze",
|
|
266
167
|
ORG_STRUCTURE_OUTCOME_KIND_OF_REASON,
|
|
267
168
|
OrgStructureOutcomeFactsSchema,
|
|
169
|
+
ORG_STRUCTURE_AFFORDANCES_OF_REASON,
|
|
268
170
|
);
|
|
269
171
|
|
|
270
172
|
export type DiscoverWorkflowOutcome = z.infer<
|