@company-semantics/contracts 89.0.0 → 89.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 +1 -1
- package/src/api/generated-spec-hash.ts +2 -2
- package/src/api/generated.ts +956 -1
- package/src/generated/openapi-routes.ts +15 -0
- package/src/message-parts/README.md +3 -0
- package/src/message-parts/__tests__/workflow-outcome.test.ts +41 -0
- package/src/message-parts/index.ts +7 -0
- package/src/message-parts/types.ts +7 -1
- package/src/message-parts/wire.ts +26 -0
- package/src/message-parts/workflow-outcome.ts +54 -0
- package/src/root-exports/agent-runtime.ts +4 -0
- package/src/root-exports/delivery.ts +36 -0
- package/src/workflows/README.md +17 -1
- package/src/workflows/__tests__/README.md +6 -0
- package/src/workflows/__tests__/outcome.test.ts +130 -0
- package/src/workflows/index.ts +33 -0
- package/src/workflows/outcome.ts +299 -0
|
@@ -94,6 +94,7 @@ export const openApiRoutes = {
|
|
|
94
94
|
'/api/factory/floor': ['GET'],
|
|
95
95
|
'/api/factory/kpis': ['GET'],
|
|
96
96
|
'/api/factory/quality/changes': ['POST'],
|
|
97
|
+
'/api/factory/quality/corpus': ['GET'],
|
|
97
98
|
'/api/factory/quality/deployments': ['POST'],
|
|
98
99
|
'/api/factory/quality/plans/{planId}': ['GET'],
|
|
99
100
|
'/api/factory/quality/plans/{planId}/decision': ['GET'],
|
|
@@ -102,6 +103,19 @@ export const openApiRoutes = {
|
|
|
102
103
|
'/api/internal-admin/impersonate/end': ['POST'],
|
|
103
104
|
'/api/internal-admin/impersonate/session': ['GET'],
|
|
104
105
|
'/api/internal-admin/impersonate/start': ['POST'],
|
|
106
|
+
'/api/internal-admin/quality/blocked': ['GET'],
|
|
107
|
+
'/api/internal-admin/quality/candidates': ['GET'],
|
|
108
|
+
'/api/internal-admin/quality/candidates/{id}': ['GET'],
|
|
109
|
+
'/api/internal-admin/quality/candidates/{id}/accept': ['POST'],
|
|
110
|
+
'/api/internal-admin/quality/candidates/{id}/reject': ['POST'],
|
|
111
|
+
'/api/internal-admin/quality/changes/manual': ['POST'],
|
|
112
|
+
'/api/internal-admin/quality/escalations': ['GET'],
|
|
113
|
+
'/api/internal-admin/quality/escalations/{id}/resolve': ['POST'],
|
|
114
|
+
'/api/internal-admin/quality/plans/{planId}/status': ['GET'],
|
|
115
|
+
'/api/internal-admin/quality/references/floor': ['PUT'],
|
|
116
|
+
'/api/internal-admin/quality/spend': ['GET'],
|
|
117
|
+
'/api/internal-admin/quality/subjects': ['GET'],
|
|
118
|
+
'/api/internal-admin/quality/subjects/{subjectKind}/{subjectKey}/timeline': ['GET'],
|
|
105
119
|
'/api/me': ['GET'],
|
|
106
120
|
'/api/me/access-list': ['GET'],
|
|
107
121
|
'/api/me/action-items': ['GET'],
|
|
@@ -156,6 +170,7 @@ export const openApiRoutes = {
|
|
|
156
170
|
'/api/org/cancel-deletion': ['POST'],
|
|
157
171
|
'/api/org/delete': ['POST'],
|
|
158
172
|
'/api/org/deletion-eligibility': ['GET'],
|
|
173
|
+
'/api/org/improve-with-usage': ['GET', 'PUT'],
|
|
159
174
|
'/api/org/reconciliation': ['GET'],
|
|
160
175
|
'/api/org/reconciliation/divergences/{divergenceId}/resolution': ['POST'],
|
|
161
176
|
'/api/org/structure-findings': ['GET'],
|
|
@@ -91,6 +91,9 @@ Canonical vocabulary for structured assistant message output. Defines the type s
|
|
|
91
91
|
- `UndoResultData` _(type)_ — Undo result data payload.
|
|
92
92
|
- `UndoResultDataPart` _(type)_ — Undo result data part (wire format).
|
|
93
93
|
- `WireSurfaceBuilder` — Factory for creating wire-format surface parts.
|
|
94
|
+
- `WorkflowOutcomeData` _(type)_ — Workflow outcome data payload: which workflow, and how its epoch ended.
|
|
95
|
+
- `WorkflowOutcomeDataPart` _(type)_ — Workflow outcome data part (wire format, as persisted in `chat_messages.parts`).
|
|
96
|
+
- `WorkflowOutcomePart` _(type)_ — Workflow outcome message part (semantic type, as rendered).
|
|
94
97
|
- `WorkflowProgressData` _(type)_ — Workflow progress surface data payload — the anchor's handle and its discriminator.
|
|
95
98
|
- `WorkflowProgressDataPart` _(type)_ — Workflow progress data part (wire format, as persisted in `chat_messages.parts`).
|
|
96
99
|
- `WorkflowProgressPart` _(type)_ — Workflow progress message part (semantic type, as rendered).
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { WireSurfaceBuilder } from "../wire";
|
|
4
|
+
import type { WorkflowOutcomeData } from "../workflow-outcome";
|
|
5
|
+
|
|
6
|
+
describe("WireSurfaceBuilder.workflowOutcome", () => {
|
|
7
|
+
const data: WorkflowOutcomeData = {
|
|
8
|
+
workflowId: "3f1c2d4e-0000-0000-0000-000000000000",
|
|
9
|
+
outcome: {
|
|
10
|
+
workflowType: "source-sync/discover",
|
|
11
|
+
executionEpoch: 0,
|
|
12
|
+
kind: "empty",
|
|
13
|
+
reason: "nothing_found",
|
|
14
|
+
facts: {
|
|
15
|
+
probesTotal: 12,
|
|
16
|
+
probesDone: 12,
|
|
17
|
+
filesSeen: 0,
|
|
18
|
+
filesShown: 0,
|
|
19
|
+
filesHidden: 0,
|
|
20
|
+
filesDropped: 0,
|
|
21
|
+
coveragePercent: 100,
|
|
22
|
+
},
|
|
23
|
+
disposition: { kind: "narrate" },
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
it("returns a data-workflow-outcome part carrying the data verbatim", () => {
|
|
28
|
+
const part = WireSurfaceBuilder.workflowOutcome(data);
|
|
29
|
+
expect(part.type).toBe("data-workflow-outcome");
|
|
30
|
+
expect(part.data).toEqual(data);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Non-governed: nothing on the payload makes it count against the
|
|
34
|
+
// at-most-one-governed-surface-per-turn budget.
|
|
35
|
+
it("carries no governed-surface fields", () => {
|
|
36
|
+
const part = WireSurfaceBuilder.workflowOutcome(data);
|
|
37
|
+
expect(Object.keys(part.data).sort()).toEqual(["outcome", "workflowId"]);
|
|
38
|
+
expect(part.data).not.toHaveProperty("executionId");
|
|
39
|
+
expect(part.data).not.toHaveProperty("submitEndpoint");
|
|
40
|
+
});
|
|
41
|
+
});
|
|
@@ -90,6 +90,13 @@ export type {
|
|
|
90
90
|
WorkflowProgressDataPart,
|
|
91
91
|
} from "./workflow-progress";
|
|
92
92
|
|
|
93
|
+
// Workflow outcome types (non-governed, the frozen outcome on a settlement message)
|
|
94
|
+
export type {
|
|
95
|
+
WorkflowOutcomeData,
|
|
96
|
+
WorkflowOutcomePart,
|
|
97
|
+
WorkflowOutcomeDataPart,
|
|
98
|
+
} from "./workflow-outcome";
|
|
99
|
+
|
|
93
100
|
// Execution result types
|
|
94
101
|
export type {
|
|
95
102
|
ExecutionArtifactStatus,
|
|
@@ -21,6 +21,7 @@ import type { StructureReviewPart } from "./structure-review";
|
|
|
21
21
|
import type { InputRequestPart } from "./input-request";
|
|
22
22
|
import type { SuggestedRepliesPart } from "./suggested-replies";
|
|
23
23
|
import type { WorkflowProgressPart } from "./workflow-progress";
|
|
24
|
+
import type { WorkflowOutcomePart } from "./workflow-outcome";
|
|
24
25
|
|
|
25
26
|
// =============================================================================
|
|
26
27
|
// Narrative Parts (Streamable)
|
|
@@ -125,6 +126,10 @@ export interface TablePart {
|
|
|
125
126
|
* background workflow to the occurrence and presents no decision, so it must
|
|
126
127
|
* not consume the governed-surface budget either.
|
|
127
128
|
*
|
|
129
|
+
* WorkflowOutcomePart is the third non-governed member: the frozen outcome of a
|
|
130
|
+
* workflow's execution epoch, carried on its settlement message. It presents no
|
|
131
|
+
* decision; a review disposition is delivered as its own InputRequestPart.
|
|
132
|
+
*
|
|
128
133
|
* InputRequestPart is GOVERNED, like StructureReviewPart: it anchors a reviewed
|
|
129
134
|
* request that asks the person to decide, so it counts against the
|
|
130
135
|
* at-most-one-governed-surface-per-turn budget. It is the generic anchor;
|
|
@@ -142,7 +147,8 @@ export type SurfacePart =
|
|
|
142
147
|
| StructureReviewPart
|
|
143
148
|
| InputRequestPart
|
|
144
149
|
| SuggestedRepliesPart
|
|
145
|
-
| WorkflowProgressPart
|
|
150
|
+
| WorkflowProgressPart
|
|
151
|
+
| WorkflowOutcomePart;
|
|
146
152
|
|
|
147
153
|
/**
|
|
148
154
|
* All assistant message part types.
|
|
@@ -35,6 +35,10 @@ import type {
|
|
|
35
35
|
WorkflowProgressData,
|
|
36
36
|
WorkflowProgressDataPart,
|
|
37
37
|
} from "./workflow-progress";
|
|
38
|
+
import type {
|
|
39
|
+
WorkflowOutcomeData,
|
|
40
|
+
WorkflowOutcomeDataPart,
|
|
41
|
+
} from "./workflow-outcome";
|
|
38
42
|
import type {
|
|
39
43
|
ExecutionResultData,
|
|
40
44
|
ExecutionResultDataPart,
|
|
@@ -246,6 +250,28 @@ export const WireSurfaceBuilder = {
|
|
|
246
250
|
};
|
|
247
251
|
},
|
|
248
252
|
|
|
253
|
+
/**
|
|
254
|
+
* Build a workflow-outcome data part for a settlement message.
|
|
255
|
+
* The frozen outcome of one execution epoch, written once at settlement
|
|
256
|
+
* (control ADR-CTRL-540).
|
|
257
|
+
*
|
|
258
|
+
* INVARIANTS:
|
|
259
|
+
* - Not a governed surface: presents no decision
|
|
260
|
+
* - The outcome is the classified, immutable value; nothing re-derives it
|
|
261
|
+
* - Counts and closed codes only, so it is safe on share-visible parts
|
|
262
|
+
* - Emission is orchestration-driven (settlement delivery), never a model
|
|
263
|
+
* choice
|
|
264
|
+
*
|
|
265
|
+
* @param data - Workflow outcome data (workflowId + frozen outcome)
|
|
266
|
+
* @returns Wire-format workflow outcome part
|
|
267
|
+
*/
|
|
268
|
+
workflowOutcome(data: WorkflowOutcomeData): WorkflowOutcomeDataPart {
|
|
269
|
+
return {
|
|
270
|
+
type: "data-workflow-outcome",
|
|
271
|
+
data,
|
|
272
|
+
};
|
|
273
|
+
},
|
|
274
|
+
|
|
249
275
|
/**
|
|
250
276
|
* Build an execution result data part for streaming.
|
|
251
277
|
* Reports the outcome of an executed action.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow Outcome Part Types
|
|
3
|
+
*
|
|
4
|
+
* The settled outcome of one execution epoch of a durable background workflow,
|
|
5
|
+
* carried on the settlement message the server writes into the conversation
|
|
6
|
+
* that launched the workflow (control ADR-CTRL-540). It is the durable,
|
|
7
|
+
* conversation-level EVIDENCE of how the run ended: the deterministic narration
|
|
8
|
+
* beside it is built from exactly this value, and a later turn ("what
|
|
9
|
+
* happened?") is grounded in it.
|
|
10
|
+
*
|
|
11
|
+
* WORKFLOW OUTCOME INVARIANTS:
|
|
12
|
+
* - WRITTEN ONCE, AT SETTLEMENT. Unlike `data-workflow-progress`, which is
|
|
13
|
+
* minted at t=0 and so must carry no result, this part is minted only after
|
|
14
|
+
* the outcome is frozen, on a message of its own. It can never be stale.
|
|
15
|
+
* - THE FROZEN OUTCOME, VERBATIM. `outcome` is the value the backend classified
|
|
16
|
+
* atomically with the terminal transition. Nothing re-derives it.
|
|
17
|
+
* - SHARE-SAFE. Chat parts reach token-only share readers verbatim, so the
|
|
18
|
+
* outcome holds counts and closed codes only (see `../workflows/outcome.ts`).
|
|
19
|
+
* - NON-GOVERNED. It presents no decision: no `executionId`, no
|
|
20
|
+
* `submitEndpoint`. A `review` disposition is delivered as its own input
|
|
21
|
+
* request anchor, not through this part.
|
|
22
|
+
* - Emission is orchestration-driven (settlement delivery), never a model
|
|
23
|
+
* choice.
|
|
24
|
+
*
|
|
25
|
+
* Purely additive: an app that predates this part normalizes unknown part types
|
|
26
|
+
* to null, drops it, and still renders the narration text.
|
|
27
|
+
*
|
|
28
|
+
* @see ../workflows/outcome.ts for the outcome vocabulary
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import type { WorkflowOutcome } from "../workflows/outcome";
|
|
32
|
+
|
|
33
|
+
/** Workflow outcome data payload: which workflow, and how its epoch ended. */
|
|
34
|
+
export interface WorkflowOutcomeData {
|
|
35
|
+
/** The durable workflow the outcome settles. */
|
|
36
|
+
workflowId: string;
|
|
37
|
+
/** The frozen, typed outcome (carries its workflow type and epoch). */
|
|
38
|
+
outcome: WorkflowOutcome;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Workflow outcome message part (semantic type, as rendered). */
|
|
42
|
+
export interface WorkflowOutcomePart {
|
|
43
|
+
type: "workflow-outcome";
|
|
44
|
+
data: WorkflowOutcomeData;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Workflow outcome data part (wire format, as persisted in
|
|
49
|
+
* `chat_messages.parts`). Uses AI SDK's data-{name} convention.
|
|
50
|
+
*/
|
|
51
|
+
export interface WorkflowOutcomeDataPart {
|
|
52
|
+
type: "data-workflow-outcome";
|
|
53
|
+
data: WorkflowOutcomeData;
|
|
54
|
+
}
|
|
@@ -93,6 +93,10 @@ export type {
|
|
|
93
93
|
WorkflowProgressData,
|
|
94
94
|
WorkflowProgressPart,
|
|
95
95
|
WorkflowProgressDataPart,
|
|
96
|
+
// Workflow outcome types (non-governed, frozen outcome on a settlement message, ADR-CTRL-540)
|
|
97
|
+
WorkflowOutcomeData,
|
|
98
|
+
WorkflowOutcomePart,
|
|
99
|
+
WorkflowOutcomeDataPart,
|
|
96
100
|
// Execution result types (Phase 5)
|
|
97
101
|
ExecutionArtifactStatus,
|
|
98
102
|
ExecutionResultSummary,
|
|
@@ -216,3 +216,39 @@ export type {
|
|
|
216
216
|
export { ANALYSIS_WORKFLOW_TYPES, isWorkflowType } from "../workflows/index";
|
|
217
217
|
|
|
218
218
|
export type { WorkflowType } from "../workflows/index";
|
|
219
|
+
|
|
220
|
+
// The typed outcome of a workflow's terminal transition (control ADR-CTRL-540):
|
|
221
|
+
// per-type closed reasons, typed facts and an explicit disposition, classified
|
|
222
|
+
// once by the backend and frozen. See src/workflows/outcome.ts.
|
|
223
|
+
export {
|
|
224
|
+
DISCOVER_OUTCOME_KIND_OF_REASON,
|
|
225
|
+
DiscoverOutcomeFactsSchema,
|
|
226
|
+
DiscoverWorkflowOutcomeSchema,
|
|
227
|
+
HrisConnectWorkflowOutcomeSchema,
|
|
228
|
+
ORG_STRUCTURE_OUTCOME_KIND_OF_REASON,
|
|
229
|
+
OrgStructureOutcomeFactsSchema,
|
|
230
|
+
ReanalyzeWorkflowOutcomeSchema,
|
|
231
|
+
SYNTHESIZE_OUTCOME_KIND_OF_REASON,
|
|
232
|
+
SynthesizeOutcomeFactsSchema,
|
|
233
|
+
SynthesizeWorkflowOutcomeSchema,
|
|
234
|
+
WORKFLOW_OUTCOME_KINDS,
|
|
235
|
+
WorkflowOutcomeDispositionSchema,
|
|
236
|
+
WorkflowOutcomeSchema,
|
|
237
|
+
} from "../workflows/index";
|
|
238
|
+
|
|
239
|
+
export type {
|
|
240
|
+
DiscoverOutcomeFacts,
|
|
241
|
+
DiscoverOutcomeReason,
|
|
242
|
+
DiscoverWorkflowOutcome,
|
|
243
|
+
HrisConnectWorkflowOutcome,
|
|
244
|
+
OrgStructureOutcomeFacts,
|
|
245
|
+
OrgStructureOutcomeReason,
|
|
246
|
+
ReanalyzeWorkflowOutcome,
|
|
247
|
+
SynthesizeOutcomeFacts,
|
|
248
|
+
SynthesizeOutcomeReason,
|
|
249
|
+
SynthesizeWorkflowOutcome,
|
|
250
|
+
WorkflowOutcome,
|
|
251
|
+
WorkflowOutcomeDisposition,
|
|
252
|
+
WorkflowOutcomeKind,
|
|
253
|
+
WorkflowOutcomeOf,
|
|
254
|
+
} from "../workflows/index";
|
package/src/workflows/README.md
CHANGED
|
@@ -32,7 +32,23 @@ so every producer, validator and renderer agrees on it.
|
|
|
32
32
|
- **Source Sync registers two flows.** `source-sync/discover` (Stage 1)
|
|
33
33
|
retains nothing; `source-sync/synthesize` (Stage 4) runs only after a person
|
|
34
34
|
approved the exact set it reads.
|
|
35
|
+
- **Every type has a typed outcome** (`outcome.ts`, control ADR-CTRL-540). A
|
|
36
|
+
terminal transition is classified once, by the backend, into a per-type
|
|
37
|
+
member of `WorkflowOutcome`: a closed `reason`, typed count-only `facts`, a
|
|
38
|
+
`kind` that is a function of the reason (`*_OUTCOME_KIND_OF_REASON`), and an
|
|
39
|
+
explicit `disposition` (`review` or `narrate`). Adding a workflow type means
|
|
40
|
+
adding its outcome member; the union must cover every registered type.
|
|
41
|
+
- **`unknown` is a safety valve, not a status.** It names an unrecognized
|
|
42
|
+
terminal transition, never a workflow whose state could not be read.
|
|
43
|
+
|
|
44
|
+
## Public API
|
|
45
|
+
|
|
46
|
+
- `ANALYSIS_WORKFLOW_TYPES`, `WorkflowType`, `isWorkflowType` (`types.ts`).
|
|
47
|
+
- `WorkflowOutcomeSchema` / `WorkflowOutcome` and the per-type member schemas,
|
|
48
|
+
reason tables, fact schemas and `WorkflowOutcomeDispositionSchema`
|
|
49
|
+
(`outcome.ts`).
|
|
35
50
|
|
|
36
51
|
## Dependencies
|
|
37
52
|
|
|
38
|
-
|
|
53
|
+
`zod` (outcome schemas) and `../input-requests/types` (the review
|
|
54
|
+
disposition's request type). Otherwise pure vocabulary data and one guard.
|
|
@@ -13,6 +13,12 @@ wire value against it.
|
|
|
13
13
|
rejections: a bare `hris-connect` without its namespace, the namespace on
|
|
14
14
|
its own, a trailing separator, an unknown flow, and non-string inputs.
|
|
15
15
|
|
|
16
|
+
- `outcome.test.ts` — the outcome union covers every registered workflow type
|
|
17
|
+
(compile-time), each reason table's kinds are valid, the schema accepts a
|
|
18
|
+
well-formed member and refuses a kind that does not match its reason, a
|
|
19
|
+
review disposition on a non-produced outcome, a reason from another type,
|
|
20
|
+
and extra keys (the facts stay closed).
|
|
21
|
+
|
|
16
22
|
## Invariants
|
|
17
23
|
|
|
18
24
|
- These assert VOCABULARY and SHAPE, never behavior. What a workflow of a
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import type { WorkflowType } from "../types";
|
|
4
|
+
import {
|
|
5
|
+
DISCOVER_OUTCOME_KIND_OF_REASON,
|
|
6
|
+
ORG_STRUCTURE_OUTCOME_KIND_OF_REASON,
|
|
7
|
+
SYNTHESIZE_OUTCOME_KIND_OF_REASON,
|
|
8
|
+
WORKFLOW_OUTCOME_KINDS,
|
|
9
|
+
WorkflowOutcomeSchema,
|
|
10
|
+
type WorkflowOutcome,
|
|
11
|
+
} from "../outcome";
|
|
12
|
+
|
|
13
|
+
// Compile-time: every registered workflow type has an outcome member, and the
|
|
14
|
+
// union names no type that is not registered.
|
|
15
|
+
type MissingOutcome = Exclude<WorkflowType, WorkflowOutcome["workflowType"]>;
|
|
16
|
+
type UnregisteredOutcome = Exclude<
|
|
17
|
+
WorkflowOutcome["workflowType"],
|
|
18
|
+
WorkflowType
|
|
19
|
+
>;
|
|
20
|
+
const coversEveryType: [MissingOutcome, UnregisteredOutcome] extends [
|
|
21
|
+
never,
|
|
22
|
+
never,
|
|
23
|
+
]
|
|
24
|
+
? true
|
|
25
|
+
: false = true;
|
|
26
|
+
|
|
27
|
+
const discoverFacts = {
|
|
28
|
+
probesTotal: 12,
|
|
29
|
+
probesDone: 12,
|
|
30
|
+
filesSeen: 0,
|
|
31
|
+
filesShown: 0,
|
|
32
|
+
filesHidden: 0,
|
|
33
|
+
filesDropped: 0,
|
|
34
|
+
coveragePercent: 100,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const empty = {
|
|
38
|
+
workflowType: "source-sync/discover",
|
|
39
|
+
executionEpoch: 0,
|
|
40
|
+
kind: "empty",
|
|
41
|
+
reason: "nothing_found",
|
|
42
|
+
facts: discoverFacts,
|
|
43
|
+
disposition: { kind: "narrate" },
|
|
44
|
+
} as const;
|
|
45
|
+
|
|
46
|
+
describe("WorkflowOutcome", () => {
|
|
47
|
+
it("covers every registered workflow type", () => {
|
|
48
|
+
expect(coversEveryType).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("maps every reason to a known kind", () => {
|
|
52
|
+
for (const table of [
|
|
53
|
+
DISCOVER_OUTCOME_KIND_OF_REASON,
|
|
54
|
+
SYNTHESIZE_OUTCOME_KIND_OF_REASON,
|
|
55
|
+
ORG_STRUCTURE_OUTCOME_KIND_OF_REASON,
|
|
56
|
+
]) {
|
|
57
|
+
for (const kind of Object.values(table)) {
|
|
58
|
+
expect(WORKFLOW_OUTCOME_KINDS).toContain(kind);
|
|
59
|
+
}
|
|
60
|
+
// Every table keeps the two safety endings.
|
|
61
|
+
expect(table).toHaveProperty("abandoned", "abandoned");
|
|
62
|
+
expect(table).toHaveProperty("unrecognized_terminal_state", "unknown");
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("accepts a well-formed member", () => {
|
|
67
|
+
expect(WorkflowOutcomeSchema.safeParse(empty).success).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("accepts null facts (the execution reported none)", () => {
|
|
71
|
+
const abandoned = {
|
|
72
|
+
...empty,
|
|
73
|
+
kind: "abandoned",
|
|
74
|
+
reason: "abandoned",
|
|
75
|
+
facts: null,
|
|
76
|
+
};
|
|
77
|
+
expect(WorkflowOutcomeSchema.safeParse(abandoned).success).toBe(true);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("refuses a kind that does not match its reason", () => {
|
|
81
|
+
expect(
|
|
82
|
+
WorkflowOutcomeSchema.safeParse({ ...empty, kind: "produced" }).success,
|
|
83
|
+
).toBe(false);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("refuses a review disposition on an outcome that produced nothing", () => {
|
|
87
|
+
const reviewEmpty = {
|
|
88
|
+
...empty,
|
|
89
|
+
disposition: {
|
|
90
|
+
kind: "review",
|
|
91
|
+
requestType: "source-sync/candidates",
|
|
92
|
+
requestId: "set-1",
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
expect(WorkflowOutcomeSchema.safeParse(reviewEmpty).success).toBe(false);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("accepts a review disposition on a produced outcome", () => {
|
|
99
|
+
const produced = {
|
|
100
|
+
...empty,
|
|
101
|
+
kind: "produced",
|
|
102
|
+
reason: "candidates_found",
|
|
103
|
+
disposition: {
|
|
104
|
+
kind: "review",
|
|
105
|
+
requestType: "source-sync/candidates",
|
|
106
|
+
requestId: "set-1",
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
expect(WorkflowOutcomeSchema.safeParse(produced).success).toBe(true);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("refuses a reason that belongs to another workflow type", () => {
|
|
113
|
+
expect(
|
|
114
|
+
WorkflowOutcomeSchema.safeParse({
|
|
115
|
+
...empty,
|
|
116
|
+
kind: "produced",
|
|
117
|
+
reason: "proposal_ready",
|
|
118
|
+
}).success,
|
|
119
|
+
).toBe(false);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("keeps facts closed: an extra key is refused", () => {
|
|
123
|
+
expect(
|
|
124
|
+
WorkflowOutcomeSchema.safeParse({
|
|
125
|
+
...empty,
|
|
126
|
+
facts: { ...discoverFacts, fileNames: 3 },
|
|
127
|
+
}).success,
|
|
128
|
+
).toBe(false);
|
|
129
|
+
});
|
|
130
|
+
});
|
package/src/workflows/index.ts
CHANGED
|
@@ -10,3 +10,36 @@
|
|
|
10
10
|
export type { WorkflowType } from "./types";
|
|
11
11
|
|
|
12
12
|
export { ANALYSIS_WORKFLOW_TYPES, isWorkflowType } from "./types";
|
|
13
|
+
|
|
14
|
+
export type {
|
|
15
|
+
DiscoverOutcomeFacts,
|
|
16
|
+
DiscoverOutcomeReason,
|
|
17
|
+
DiscoverWorkflowOutcome,
|
|
18
|
+
HrisConnectWorkflowOutcome,
|
|
19
|
+
OrgStructureOutcomeFacts,
|
|
20
|
+
OrgStructureOutcomeReason,
|
|
21
|
+
ReanalyzeWorkflowOutcome,
|
|
22
|
+
SynthesizeOutcomeFacts,
|
|
23
|
+
SynthesizeOutcomeReason,
|
|
24
|
+
SynthesizeWorkflowOutcome,
|
|
25
|
+
WorkflowOutcome,
|
|
26
|
+
WorkflowOutcomeDisposition,
|
|
27
|
+
WorkflowOutcomeKind,
|
|
28
|
+
WorkflowOutcomeOf,
|
|
29
|
+
} from "./outcome";
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
DISCOVER_OUTCOME_KIND_OF_REASON,
|
|
33
|
+
DiscoverOutcomeFactsSchema,
|
|
34
|
+
DiscoverWorkflowOutcomeSchema,
|
|
35
|
+
HrisConnectWorkflowOutcomeSchema,
|
|
36
|
+
ORG_STRUCTURE_OUTCOME_KIND_OF_REASON,
|
|
37
|
+
OrgStructureOutcomeFactsSchema,
|
|
38
|
+
ReanalyzeWorkflowOutcomeSchema,
|
|
39
|
+
SYNTHESIZE_OUTCOME_KIND_OF_REASON,
|
|
40
|
+
SynthesizeOutcomeFactsSchema,
|
|
41
|
+
SynthesizeWorkflowOutcomeSchema,
|
|
42
|
+
WORKFLOW_OUTCOME_KINDS,
|
|
43
|
+
WorkflowOutcomeDispositionSchema,
|
|
44
|
+
WorkflowOutcomeSchema,
|
|
45
|
+
} from "./outcome";
|