@exaudeus/workrail 3.17.0 → 3.18.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/dist/application/services/validation-engine.js +7 -11
- package/dist/application/services/workflow-compiler.js +9 -11
- package/dist/manifest.json +27 -27
- package/dist/mcp/handlers/v2-advance-core/assessment-consequences.d.ts +1 -1
- package/dist/mcp/handlers/v2-advance-core/assessment-consequences.js +14 -11
- package/dist/mcp/handlers/v2-advance-core/assessment-validation.d.ts +5 -3
- package/dist/mcp/handlers/v2-advance-core/assessment-validation.js +109 -87
- package/dist/mcp/handlers/v2-advance-core/input-validation.d.ts +0 -4
- package/dist/mcp/handlers/v2-advance-core/input-validation.js +1 -3
- package/dist/mcp/handlers/v2-advance-core/outcome-blocked.js +8 -3
- package/dist/mcp/handlers/v2-advance-core/outcome-success.js +8 -3
- package/dist/mcp/handlers/v2-execution/replay.js +4 -4
- package/dist/mcp/output-schemas.d.ts +12 -12
- package/dist/mcp/output-schemas.js +10 -11
- package/dist/v2/durable-core/domain/prompt-renderer.js +4 -0
- package/package.json +1 -1
- package/spec/authoring-spec.json +3 -3
- package/spec/workflow.schema.json +1 -2
- package/workflows/workflow-for-workflows.json +558 -448
|
@@ -685,24 +685,24 @@ let ValidationEngine = ValidationEngine_1 = class ValidationEngine {
|
|
|
685
685
|
issues.push(`${stepLabel}: assessmentConsequences must not be empty when declared`);
|
|
686
686
|
return;
|
|
687
687
|
}
|
|
688
|
-
if (!step.assessmentRefs || step.assessmentRefs.length
|
|
689
|
-
issues.push(`${stepLabel}: assessmentConsequences require
|
|
690
|
-
suggestions.push(`Add
|
|
688
|
+
if (!step.assessmentRefs || step.assessmentRefs.length === 0) {
|
|
689
|
+
issues.push(`${stepLabel}: assessmentConsequences require at least one assessmentRef on the same step`);
|
|
690
|
+
suggestions.push(`Add at least one assessmentRef to ${stepLabel} before declaring assessmentConsequences`);
|
|
691
691
|
return;
|
|
692
692
|
}
|
|
693
693
|
if (step.assessmentConsequences.length > 1) {
|
|
694
694
|
issues.push(`${stepLabel}: v1 assessment support allows exactly one assessment consequence per step`);
|
|
695
695
|
suggestions.push(`Reduce assessmentConsequences on ${stepLabel} to a single declaration`);
|
|
696
696
|
}
|
|
697
|
-
const
|
|
698
|
-
if (
|
|
697
|
+
const referencedDefinitions = assessments.filter(assessment => step.assessmentRefs.includes(assessment.id));
|
|
698
|
+
if (referencedDefinitions.length === 0)
|
|
699
699
|
return;
|
|
700
700
|
for (const consequence of step.assessmentConsequences) {
|
|
701
701
|
const trigger = consequence.when;
|
|
702
702
|
const effect = consequence.effect;
|
|
703
|
-
const allLevels =
|
|
703
|
+
const allLevels = referencedDefinitions.flatMap(def => def.dimensions.flatMap(d => d.levels));
|
|
704
704
|
if (!allLevels.includes(trigger.anyEqualsLevel)) {
|
|
705
|
-
issues.push(`${stepLabel}: assessment consequence anyEqualsLevel '${trigger.anyEqualsLevel}' is not declared in any dimension of assessment
|
|
705
|
+
issues.push(`${stepLabel}: assessment consequence anyEqualsLevel '${trigger.anyEqualsLevel}' is not declared in any dimension of any referenced assessment`);
|
|
706
706
|
suggestions.push(`Use a level declared in one of the dimensions: ${[...new Set(allLevels)].join(', ')}`);
|
|
707
707
|
}
|
|
708
708
|
if (effect.kind !== 'require_followup') {
|
|
@@ -776,10 +776,6 @@ let ValidationEngine = ValidationEngine_1 = class ValidationEngine {
|
|
|
776
776
|
}
|
|
777
777
|
}
|
|
778
778
|
validateAssessmentRefsForStep(typedStep, `Step '${step.id}'`);
|
|
779
|
-
if (typedStep.assessmentRefs !== undefined && typedStep.assessmentRefs.length > 1) {
|
|
780
|
-
issues.push(`Step '${step.id}': v1 assessment support allows exactly one assessmentRef per step`);
|
|
781
|
-
suggestions.push(`Reduce assessmentRefs on step '${step.id}' to a single assessment id`);
|
|
782
|
-
}
|
|
783
779
|
validateAssessmentConsequencesForStep(typedStep, `Step '${step.id}'`);
|
|
784
780
|
const callValidation = this.validateStepFunctionCalls(step, workflow.definition.functionDefinitions || []);
|
|
785
781
|
if (!callValidation.valid) {
|
|
@@ -140,21 +140,19 @@ let WorkflowCompiler = class WorkflowCompiler {
|
|
|
140
140
|
const assessmentConsequences = typedStep.assessmentConsequences;
|
|
141
141
|
if (!assessmentConsequences)
|
|
142
142
|
continue;
|
|
143
|
-
if (!typedStep.assessmentRefs || typedStep.assessmentRefs.length
|
|
144
|
-
return (0, neverthrow_1.err)(error_1.Err.invalidState(`Step '${step.id}' declares assessmentConsequences but
|
|
145
|
-
}
|
|
146
|
-
const assessment = (workflow.definition.assessments ?? []).find(candidate => candidate.id === typedStep.assessmentRefs?.[0]);
|
|
147
|
-
if (!assessment) {
|
|
148
|
-
return (0, neverthrow_1.err)(error_1.Err.invalidState(`Step '${step.id}' declares assessmentConsequences for unknown assessmentRef '${typedStep.assessmentRefs[0]}'`));
|
|
143
|
+
if (!typedStep.assessmentRefs || typedStep.assessmentRefs.length === 0) {
|
|
144
|
+
return (0, neverthrow_1.err)(error_1.Err.invalidState(`Step '${step.id}' declares assessmentConsequences but declares no assessmentRefs`));
|
|
149
145
|
}
|
|
150
146
|
if (assessmentConsequences.length > 1) {
|
|
151
147
|
return (0, neverthrow_1.err)(error_1.Err.invalidState(`Step '${step.id}' declares ${assessmentConsequences.length} assessment consequences. V1 supports exactly one assessment consequence per step.`));
|
|
152
148
|
}
|
|
149
|
+
const allLevelsAcrossRefs = (workflow.definition.assessments ?? [])
|
|
150
|
+
.filter(candidate => typedStep.assessmentRefs.includes(candidate.id))
|
|
151
|
+
.flatMap(assessment => assessment.dimensions.flatMap(d => d.levels));
|
|
153
152
|
for (const consequence of assessmentConsequences) {
|
|
154
153
|
const trigger = consequence.when;
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
return (0, neverthrow_1.err)(error_1.Err.invalidState(`Step '${step.id}' declares consequence with anyEqualsLevel '${trigger.anyEqualsLevel}' that is not declared in any dimension of assessment '${assessment.id}'`));
|
|
154
|
+
if (!allLevelsAcrossRefs.includes(trigger.anyEqualsLevel)) {
|
|
155
|
+
return (0, neverthrow_1.err)(error_1.Err.invalidState(`Step '${step.id}' declares consequence with anyEqualsLevel '${trigger.anyEqualsLevel}' that is not declared in any dimension of any referenced assessment`));
|
|
158
156
|
}
|
|
159
157
|
if (consequence.effect.kind !== 'require_followup') {
|
|
160
158
|
return (0, neverthrow_1.err)(error_1.Err.invalidState(`Step '${step.id}' declares unsupported assessment consequence effect '${String(consequence.effect.kind)}'`));
|
|
@@ -187,8 +185,8 @@ let WorkflowCompiler = class WorkflowCompiler {
|
|
|
187
185
|
}
|
|
188
186
|
}
|
|
189
187
|
if (bodyStep.assessmentConsequences) {
|
|
190
|
-
if (!bodyStep.assessmentRefs || bodyStep.assessmentRefs.length
|
|
191
|
-
return (0, neverthrow_1.err)(error_1.Err.invalidState(`Loop body step '${bodyStep.id}' in loop '${loop.id}' declares assessmentConsequences but
|
|
188
|
+
if (!bodyStep.assessmentRefs || bodyStep.assessmentRefs.length === 0) {
|
|
189
|
+
return (0, neverthrow_1.err)(error_1.Err.invalidState(`Loop body step '${bodyStep.id}' in loop '${loop.id}' declares assessmentConsequences but declares no assessmentRefs`));
|
|
192
190
|
}
|
|
193
191
|
}
|
|
194
192
|
}
|
package/dist/manifest.json
CHANGED
|
@@ -126,16 +126,16 @@
|
|
|
126
126
|
"bytes": 2122
|
|
127
127
|
},
|
|
128
128
|
"application/services/validation-engine.js": {
|
|
129
|
-
"sha256": "
|
|
130
|
-
"bytes":
|
|
129
|
+
"sha256": "6231bc1fe0a130ca9771f24da7e5b661d7ceba5839e2867aab6a47b4e50e1a99",
|
|
130
|
+
"bytes": 48831
|
|
131
131
|
},
|
|
132
132
|
"application/services/workflow-compiler.d.ts": {
|
|
133
133
|
"sha256": "f51443e1c3e8e079a972dd032e8de3bcde7b82d891e9a3621a6357cc4fc0e30d",
|
|
134
134
|
"bytes": 1718
|
|
135
135
|
},
|
|
136
136
|
"application/services/workflow-compiler.js": {
|
|
137
|
-
"sha256": "
|
|
138
|
-
"bytes":
|
|
137
|
+
"sha256": "61d09a365540d49865f3d9a1b80eb5f21bad1bd4ccfe2950af63302dd4048dcf",
|
|
138
|
+
"bytes": 14175
|
|
139
139
|
},
|
|
140
140
|
"application/services/workflow-interpreter.d.ts": {
|
|
141
141
|
"sha256": "56b5b5ad06d42096deba9f0abe7642c18a355a1e598749aab1730df4e9847674",
|
|
@@ -766,20 +766,20 @@
|
|
|
766
766
|
"bytes": 306
|
|
767
767
|
},
|
|
768
768
|
"mcp/handlers/v2-advance-core/assessment-consequences.d.ts": {
|
|
769
|
-
"sha256": "
|
|
769
|
+
"sha256": "69323678acf77575569b66a0444aa38578f392b5bfd3aa8f013ff6a463967f66",
|
|
770
770
|
"bytes": 836
|
|
771
771
|
},
|
|
772
772
|
"mcp/handlers/v2-advance-core/assessment-consequences.js": {
|
|
773
|
-
"sha256": "
|
|
774
|
-
"bytes":
|
|
773
|
+
"sha256": "b5f920c648fd8ffd4bf37df57f40e15eb85a84c606a050b0336f71ad15e9a039",
|
|
774
|
+
"bytes": 1203
|
|
775
775
|
},
|
|
776
776
|
"mcp/handlers/v2-advance-core/assessment-validation.d.ts": {
|
|
777
|
-
"sha256": "
|
|
778
|
-
"bytes":
|
|
777
|
+
"sha256": "57c4e1cda1f7006d8cbcab19a7c2d0f6418aff128f0237265a200388ee378772",
|
|
778
|
+
"bytes": 1020
|
|
779
779
|
},
|
|
780
780
|
"mcp/handlers/v2-advance-core/assessment-validation.js": {
|
|
781
|
-
"sha256": "
|
|
782
|
-
"bytes":
|
|
781
|
+
"sha256": "9bf6b000610afcfc97b6f769574ed27b734baf1be2e52978534486bb453d23c4",
|
|
782
|
+
"bytes": 10270
|
|
783
783
|
},
|
|
784
784
|
"mcp/handlers/v2-advance-core/event-builders.d.ts": {
|
|
785
785
|
"sha256": "64502bdfc33901fdb9f9d0d676c9762497bc03f17f0f9a68959a460b270b13b2",
|
|
@@ -798,28 +798,28 @@
|
|
|
798
798
|
"bytes": 8087
|
|
799
799
|
},
|
|
800
800
|
"mcp/handlers/v2-advance-core/input-validation.d.ts": {
|
|
801
|
-
"sha256": "
|
|
802
|
-
"bytes":
|
|
801
|
+
"sha256": "4e057b4496c0d0b263a1296f313df6583df3b5fb34855c1e26d38cbdd39536ea",
|
|
802
|
+
"bytes": 2581
|
|
803
803
|
},
|
|
804
804
|
"mcp/handlers/v2-advance-core/input-validation.js": {
|
|
805
|
-
"sha256": "
|
|
806
|
-
"bytes":
|
|
805
|
+
"sha256": "6f690863bc61eec4cd9632b75d2bf6dc6b37fdaca445aded371715f351df673e",
|
|
806
|
+
"bytes": 5275
|
|
807
807
|
},
|
|
808
808
|
"mcp/handlers/v2-advance-core/outcome-blocked.d.ts": {
|
|
809
809
|
"sha256": "837a6515ba8a1b5de8627c44e5f639a4b8e95d99833a784121539beb262cd96d",
|
|
810
810
|
"bytes": 1242
|
|
811
811
|
},
|
|
812
812
|
"mcp/handlers/v2-advance-core/outcome-blocked.js": {
|
|
813
|
-
"sha256": "
|
|
814
|
-
"bytes":
|
|
813
|
+
"sha256": "3f13d7672c182ecaaf7ca44a616b2a358d27f7826a297fea6ea2afdb4d32d2c1",
|
|
814
|
+
"bytes": 6313
|
|
815
815
|
},
|
|
816
816
|
"mcp/handlers/v2-advance-core/outcome-success.d.ts": {
|
|
817
817
|
"sha256": "09ddde83767b1a997cc20933d62bac89a83937be331bf021555d9e661b97cfa6",
|
|
818
818
|
"bytes": 1055
|
|
819
819
|
},
|
|
820
820
|
"mcp/handlers/v2-advance-core/outcome-success.js": {
|
|
821
|
-
"sha256": "
|
|
822
|
-
"bytes":
|
|
821
|
+
"sha256": "ebb8c7e942d915f479e456c01bf42a3f27a2b0502c24e3d924fbbc426d4cc422",
|
|
822
|
+
"bytes": 7752
|
|
823
823
|
},
|
|
824
824
|
"mcp/handlers/v2-advance-events.d.ts": {
|
|
825
825
|
"sha256": "02cdb52a2c16dd619645b5496caf0880e57937bf21ea9efe44e6cd195cd43b94",
|
|
@@ -906,8 +906,8 @@
|
|
|
906
906
|
"bytes": 2808
|
|
907
907
|
},
|
|
908
908
|
"mcp/handlers/v2-execution/replay.js": {
|
|
909
|
-
"sha256": "
|
|
910
|
-
"bytes":
|
|
909
|
+
"sha256": "5c0f7456db8862538103d876f00ff4c06533045c9f0dbe25e5ed4f53baf83e79",
|
|
910
|
+
"bytes": 11397
|
|
911
911
|
},
|
|
912
912
|
"mcp/handlers/v2-execution/start.d.ts": {
|
|
913
913
|
"sha256": "2deb05345e125667576ede3bb20756a1b22ec86f18028d242b5d9b54dd25afaf",
|
|
@@ -998,12 +998,12 @@
|
|
|
998
998
|
"bytes": 7991
|
|
999
999
|
},
|
|
1000
1000
|
"mcp/output-schemas.d.ts": {
|
|
1001
|
-
"sha256": "
|
|
1002
|
-
"bytes":
|
|
1001
|
+
"sha256": "291a605a38ca41a6a6849ae6325b2541694a547d02cc231951fb6438f781b316",
|
|
1002
|
+
"bytes": 93176
|
|
1003
1003
|
},
|
|
1004
1004
|
"mcp/output-schemas.js": {
|
|
1005
|
-
"sha256": "
|
|
1006
|
-
"bytes":
|
|
1005
|
+
"sha256": "b9901935144a7842dd237a869b51fdd72153ce2970225da1e83cc22193bd1293",
|
|
1006
|
+
"bytes": 22211
|
|
1007
1007
|
},
|
|
1008
1008
|
"mcp/render-envelope.d.ts": {
|
|
1009
1009
|
"sha256": "22e83e1aba52968a7136cf289125a217b5f462a5a66a1eebe4669006e3326fdb",
|
|
@@ -1682,8 +1682,8 @@
|
|
|
1682
1682
|
"bytes": 1295
|
|
1683
1683
|
},
|
|
1684
1684
|
"v2/durable-core/domain/prompt-renderer.js": {
|
|
1685
|
-
"sha256": "
|
|
1686
|
-
"bytes":
|
|
1685
|
+
"sha256": "b4e6b9683d05eb63b86b346996ead259157882bcb1e6a70834a919c90c6007f9",
|
|
1686
|
+
"bytes": 18937
|
|
1687
1687
|
},
|
|
1688
1688
|
"v2/durable-core/domain/reason-model.d.ts": {
|
|
1689
1689
|
"sha256": "a944e7e0d9b3c73468488263cb0aa1e446c023f8084fd2af53cbda3f3bfcd37a",
|
|
@@ -9,6 +9,6 @@ export interface TriggeredAssessmentConsequenceV1 {
|
|
|
9
9
|
}
|
|
10
10
|
export declare function evaluateAssessmentConsequences(args: {
|
|
11
11
|
readonly step: WorkflowStepDefinition | undefined;
|
|
12
|
-
readonly
|
|
12
|
+
readonly recordedAssessments: readonly RecordedAssessmentV1[];
|
|
13
13
|
}): TriggeredAssessmentConsequenceV1 | undefined;
|
|
14
14
|
export declare function getDeclaredAssessmentConsequence(step: WorkflowStepDefinition | undefined): AssessmentConsequenceDefinition | undefined;
|
|
@@ -5,21 +5,24 @@ exports.getDeclaredAssessmentConsequence = getDeclaredAssessmentConsequence;
|
|
|
5
5
|
function evaluateAssessmentConsequences(args) {
|
|
6
6
|
if (!args.step?.assessmentConsequences || args.step.assessmentConsequences.length === 0)
|
|
7
7
|
return undefined;
|
|
8
|
-
if (
|
|
8
|
+
if (args.recordedAssessments.length === 0)
|
|
9
9
|
return undefined;
|
|
10
10
|
const consequence = args.step.assessmentConsequences[0];
|
|
11
11
|
if (!consequence)
|
|
12
12
|
return undefined;
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
13
|
+
for (const recorded of args.recordedAssessments) {
|
|
14
|
+
const matched = recorded.dimensions.find(d => d.level === consequence.when.anyEqualsLevel);
|
|
15
|
+
if (matched) {
|
|
16
|
+
return {
|
|
17
|
+
kind: 'require_followup',
|
|
18
|
+
assessmentId: recorded.assessmentId,
|
|
19
|
+
firstMatchedDimensionId: matched.dimensionId,
|
|
20
|
+
triggerLevel: consequence.when.anyEqualsLevel,
|
|
21
|
+
guidance: consequence.effect.guidance,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return undefined;
|
|
23
26
|
}
|
|
24
27
|
function getDeclaredAssessmentConsequence(step) {
|
|
25
28
|
return step?.assessmentConsequences?.[0];
|
|
@@ -5,9 +5,11 @@ import type { RecordedAssessmentV1 } from '../../../v2/durable-core/domain/asses
|
|
|
5
5
|
export interface AssessmentValidationOutcome {
|
|
6
6
|
readonly contractRef: typeof ASSESSMENT_CONTRACT_REF;
|
|
7
7
|
readonly validation: ValidationResult;
|
|
8
|
-
readonly
|
|
9
|
-
readonly
|
|
10
|
-
|
|
8
|
+
readonly recordedAssessments: readonly RecordedAssessmentV1[];
|
|
9
|
+
readonly acceptedArtifacts: ReadonlyArray<{
|
|
10
|
+
readonly artifact: AssessmentArtifactV1;
|
|
11
|
+
readonly artifactIndex: number;
|
|
12
|
+
}>;
|
|
11
13
|
}
|
|
12
14
|
export declare function validateAssessmentForStep(args: {
|
|
13
15
|
readonly step: WorkflowStepDefinition;
|
|
@@ -38,39 +38,6 @@ function extractSubmittedRationale(value) {
|
|
|
38
38
|
const trimmed = value.rationale?.trim();
|
|
39
39
|
return trimmed && trimmed.length > 0 ? trimmed : undefined;
|
|
40
40
|
}
|
|
41
|
-
function buildDefinitionLookup(assessments, step) {
|
|
42
|
-
const refs = step.assessmentRefs ?? [];
|
|
43
|
-
if (refs.length === 0) {
|
|
44
|
-
return {
|
|
45
|
-
definition: undefined,
|
|
46
|
-
issues: [],
|
|
47
|
-
suggestions: [],
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
if (!assessments || assessments.length === 0) {
|
|
51
|
-
return {
|
|
52
|
-
definition: undefined,
|
|
53
|
-
issues: [`Step "${step.id}" expects assessment input, but the workflow declares no assessments.`],
|
|
54
|
-
suggestions: ['Update the workflow definition to declare the assessments referenced by this step.'],
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
if (refs.length > 1) {
|
|
58
|
-
return {
|
|
59
|
-
definition: undefined,
|
|
60
|
-
issues: [`Step "${step.id}" declares multiple assessmentRefs. Assessment boundary validation currently supports exactly one assessment per step.`],
|
|
61
|
-
suggestions: ['Reduce assessmentRefs to a single assessment for this step in v1.'],
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
const definition = assessments.find((assessment) => assessment.id === refs[0]);
|
|
65
|
-
if (!definition) {
|
|
66
|
-
return {
|
|
67
|
-
definition: undefined,
|
|
68
|
-
issues: [`Step "${step.id}" references undeclared assessment "${refs[0]}".`],
|
|
69
|
-
suggestions: [`Declare assessment "${refs[0]}" on the workflow or remove the step reference.`],
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
return { definition, issues: [], suggestions: [] };
|
|
73
|
-
}
|
|
74
41
|
function validateDimension(dimension, artifact, issues, suggestions, warnings, recordedDimensions) {
|
|
75
42
|
const submitted = artifact.dimensions[dimension.id];
|
|
76
43
|
if (submitted === undefined) {
|
|
@@ -111,103 +78,158 @@ function validateDimension(dimension, artifact, issues, suggestions, warnings, r
|
|
|
111
78
|
}
|
|
112
79
|
}
|
|
113
80
|
}
|
|
114
|
-
function
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if (
|
|
81
|
+
function validateSingleAssessment(args) {
|
|
82
|
+
const assessmentArtifacts = args.artifacts
|
|
83
|
+
.map((artifact, index) => ({ artifact, index }))
|
|
84
|
+
.filter(({ artifact }) => typeof artifact === 'object' && artifact !== null && artifact.kind === 'wr.assessment');
|
|
85
|
+
if (assessmentArtifacts.length === 0) {
|
|
119
86
|
return {
|
|
120
|
-
|
|
87
|
+
issues: [`This step requires an assessment submission for "${args.definition.id}".`],
|
|
88
|
+
suggestions: [
|
|
89
|
+
`Provide an artifact with kind "wr.assessment" for assessment "${args.definition.id}".`,
|
|
90
|
+
`Include dimension values for: ${args.definition.dimensions.map((dimension) => `${dimension.id} (${dimension.levels.join(' | ')})`).join(', ')}.`,
|
|
91
|
+
],
|
|
92
|
+
warnings: [],
|
|
121
93
|
acceptedArtifact: undefined,
|
|
122
94
|
acceptedArtifactIndex: undefined,
|
|
123
95
|
recordedAssessment: undefined,
|
|
124
|
-
validation: {
|
|
125
|
-
valid: false,
|
|
126
|
-
issues: [...lookup.issues],
|
|
127
|
-
suggestions: [...lookup.suggestions],
|
|
128
|
-
},
|
|
129
96
|
};
|
|
130
97
|
}
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
.
|
|
134
|
-
|
|
98
|
+
const candidateEntry = args.isSingleRef
|
|
99
|
+
? assessmentArtifacts[0]
|
|
100
|
+
: assessmentArtifacts.find(({ artifact }) => {
|
|
101
|
+
const parsed = (0, index_js_1.parseAssessmentArtifact)(artifact);
|
|
102
|
+
return parsed?.assessmentId === args.definition.id;
|
|
103
|
+
});
|
|
104
|
+
if (!candidateEntry) {
|
|
135
105
|
return {
|
|
136
|
-
|
|
106
|
+
issues: [`Missing assessment artifact for "${args.definition.id}". Provide an artifact with kind "wr.assessment" and assessmentId "${args.definition.id}".`],
|
|
107
|
+
suggestions: [
|
|
108
|
+
`Include dimension values for: ${args.definition.dimensions.map((d) => `${d.id} (${d.levels.join(' | ')})`).join(', ')}.`,
|
|
109
|
+
],
|
|
110
|
+
warnings: [],
|
|
137
111
|
acceptedArtifact: undefined,
|
|
138
112
|
acceptedArtifactIndex: undefined,
|
|
139
113
|
recordedAssessment: undefined,
|
|
140
|
-
validation: {
|
|
141
|
-
valid: false,
|
|
142
|
-
issues: [`This step requires an assessment submission for "${lookup.definition.id}".`],
|
|
143
|
-
suggestions: [
|
|
144
|
-
`Provide an artifact with kind "wr.assessment" for assessment "${lookup.definition.id}".`,
|
|
145
|
-
`Include dimension values for: ${lookup.definition.dimensions.map((dimension) => `${dimension.id} (${dimension.levels.join(' | ')})`).join(', ')}.`,
|
|
146
|
-
],
|
|
147
|
-
},
|
|
148
114
|
};
|
|
149
115
|
}
|
|
150
|
-
const
|
|
151
|
-
const parsed = (0, index_js_1.parseAssessmentArtifact)(acceptedCandidate.artifact);
|
|
116
|
+
const parsed = (0, index_js_1.parseAssessmentArtifact)(candidateEntry.artifact);
|
|
152
117
|
if (!parsed) {
|
|
153
118
|
return {
|
|
154
|
-
|
|
119
|
+
issues: ['Assessment artifact is malformed or does not match the expected shape.'],
|
|
120
|
+
suggestions: [
|
|
121
|
+
`Use an artifact with kind "wr.assessment", a dimensions object, and canonical dimension values for assessment "${args.definition.id}".`,
|
|
122
|
+
],
|
|
123
|
+
warnings: [],
|
|
155
124
|
acceptedArtifact: undefined,
|
|
156
125
|
acceptedArtifactIndex: undefined,
|
|
157
126
|
recordedAssessment: undefined,
|
|
158
|
-
validation: {
|
|
159
|
-
valid: false,
|
|
160
|
-
issues: ['Assessment artifact is malformed or does not match the expected shape.'],
|
|
161
|
-
suggestions: [
|
|
162
|
-
`Use an artifact with kind "wr.assessment", a dimensions object, and canonical dimension values for assessment "${lookup.definition.id}".`,
|
|
163
|
-
],
|
|
164
|
-
},
|
|
165
127
|
};
|
|
166
128
|
}
|
|
167
|
-
if (parsed.assessmentId && parsed.assessmentId !==
|
|
129
|
+
if (parsed.assessmentId && parsed.assessmentId !== args.definition.id) {
|
|
168
130
|
return {
|
|
169
|
-
|
|
131
|
+
issues: [`Assessment artifact targets "${parsed.assessmentId}", but this step expects "${args.definition.id}".`],
|
|
132
|
+
suggestions: [`Set assessmentId to "${args.definition.id}" or omit it and provide the correct dimensions.`],
|
|
133
|
+
warnings: [],
|
|
170
134
|
acceptedArtifact: undefined,
|
|
171
135
|
acceptedArtifactIndex: undefined,
|
|
172
136
|
recordedAssessment: undefined,
|
|
173
|
-
validation: {
|
|
174
|
-
valid: false,
|
|
175
|
-
issues: [`Assessment artifact targets "${parsed.assessmentId}", but this step expects "${lookup.definition.id}".`],
|
|
176
|
-
suggestions: [`Set assessmentId to "${lookup.definition.id}" or omit it and provide the correct dimensions.`],
|
|
177
|
-
},
|
|
178
137
|
};
|
|
179
138
|
}
|
|
180
139
|
const issues = [];
|
|
181
140
|
const suggestions = [];
|
|
182
141
|
const warnings = [];
|
|
183
142
|
const recordedDimensions = [];
|
|
184
|
-
for (const dimension of
|
|
143
|
+
for (const dimension of args.definition.dimensions) {
|
|
185
144
|
validateDimension(dimension, parsed, issues, suggestions, warnings, recordedDimensions);
|
|
186
145
|
}
|
|
187
|
-
const allowedDimensionIds = new Set(
|
|
146
|
+
const allowedDimensionIds = new Set(args.definition.dimensions.map((d) => d.id));
|
|
188
147
|
for (const submittedDimensionId of Object.keys(parsed.dimensions)) {
|
|
189
148
|
if (!allowedDimensionIds.has(submittedDimensionId)) {
|
|
190
|
-
issues.push(`Unknown assessment dimension "${submittedDimensionId}" for assessment "${
|
|
191
|
-
suggestions.push(`Remove "${submittedDimensionId}" and use only: ${
|
|
149
|
+
issues.push(`Unknown assessment dimension "${submittedDimensionId}" for assessment "${args.definition.id}".`);
|
|
150
|
+
suggestions.push(`Remove "${submittedDimensionId}" and use only: ${args.definition.dimensions.map((d) => d.id).join(', ')}.`);
|
|
192
151
|
}
|
|
193
152
|
}
|
|
153
|
+
const valid = issues.length === 0;
|
|
194
154
|
return {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
155
|
+
issues,
|
|
156
|
+
suggestions,
|
|
157
|
+
warnings,
|
|
158
|
+
acceptedArtifact: valid ? parsed : undefined,
|
|
159
|
+
acceptedArtifactIndex: valid ? candidateEntry.index : undefined,
|
|
160
|
+
recordedAssessment: valid
|
|
199
161
|
? {
|
|
200
|
-
assessmentId:
|
|
162
|
+
assessmentId: args.definition.id,
|
|
201
163
|
summary: parsed.summary,
|
|
202
164
|
dimensions: recordedDimensions,
|
|
203
165
|
normalizationNotes: warnings,
|
|
204
166
|
}
|
|
205
167
|
: undefined,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function validateAssessmentForStep(args) {
|
|
171
|
+
if (!args.step.assessmentRefs || args.step.assessmentRefs.length === 0)
|
|
172
|
+
return undefined;
|
|
173
|
+
const refs = args.step.assessmentRefs;
|
|
174
|
+
if (!args.assessments || args.assessments.length === 0) {
|
|
175
|
+
return {
|
|
176
|
+
contractRef: index_js_1.ASSESSMENT_CONTRACT_REF,
|
|
177
|
+
recordedAssessments: [],
|
|
178
|
+
acceptedArtifacts: [],
|
|
179
|
+
validation: {
|
|
180
|
+
valid: false,
|
|
181
|
+
issues: refs.map((ref) => `Step expects assessment input for "${ref}", but the workflow declares no assessments.`),
|
|
182
|
+
suggestions: ['Update the workflow definition to declare the assessments referenced by this step.'],
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
const allIssues = [];
|
|
187
|
+
const allSuggestions = [];
|
|
188
|
+
const definitions = [];
|
|
189
|
+
for (const ref of refs) {
|
|
190
|
+
const definition = args.assessments.find((a) => a.id === ref);
|
|
191
|
+
if (!definition) {
|
|
192
|
+
allIssues.push(`Step references undeclared assessment "${ref}".`);
|
|
193
|
+
allSuggestions.push(`Declare assessment "${ref}" on the workflow or remove the step reference.`);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
definitions.push(definition);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (allIssues.length > 0) {
|
|
200
|
+
return {
|
|
201
|
+
contractRef: index_js_1.ASSESSMENT_CONTRACT_REF,
|
|
202
|
+
recordedAssessments: [],
|
|
203
|
+
acceptedArtifacts: [],
|
|
204
|
+
validation: { valid: false, issues: allIssues, suggestions: allSuggestions },
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
const isSingleRef = refs.length === 1;
|
|
208
|
+
const perRefResults = definitions.map((definition) => validateSingleAssessment({ definition, artifacts: args.artifacts, isSingleRef }));
|
|
209
|
+
const combinedIssues = perRefResults.flatMap((r) => r.issues);
|
|
210
|
+
const combinedSuggestions = perRefResults.flatMap((r) => r.suggestions);
|
|
211
|
+
const combinedWarnings = perRefResults.flatMap((r) => r.warnings);
|
|
212
|
+
const allValid = combinedIssues.length === 0;
|
|
213
|
+
const recordedAssessments = [];
|
|
214
|
+
const acceptedArtifacts = [];
|
|
215
|
+
if (allValid) {
|
|
216
|
+
for (const result of perRefResults) {
|
|
217
|
+
if (result.recordedAssessment)
|
|
218
|
+
recordedAssessments.push(result.recordedAssessment);
|
|
219
|
+
if (result.acceptedArtifact !== undefined && result.acceptedArtifactIndex !== undefined) {
|
|
220
|
+
acceptedArtifacts.push({ artifact: result.acceptedArtifact, artifactIndex: result.acceptedArtifactIndex });
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
contractRef: index_js_1.ASSESSMENT_CONTRACT_REF,
|
|
226
|
+
recordedAssessments,
|
|
227
|
+
acceptedArtifacts,
|
|
206
228
|
validation: {
|
|
207
|
-
valid:
|
|
208
|
-
issues,
|
|
209
|
-
suggestions,
|
|
210
|
-
|
|
229
|
+
valid: allValid,
|
|
230
|
+
issues: combinedIssues,
|
|
231
|
+
suggestions: combinedSuggestions,
|
|
232
|
+
...(combinedWarnings.length > 0 ? { warnings: combinedWarnings } : {}),
|
|
211
233
|
},
|
|
212
234
|
};
|
|
213
235
|
}
|
|
@@ -5,8 +5,6 @@ import type { JsonValue, JsonObject } from '../../../v2/durable-core/canonical/j
|
|
|
5
5
|
import type { V2ContinueWorkflowInput } from '../../v2/tools.js';
|
|
6
6
|
import type { AssessmentDefinition, OutputContract } from '../../../types/workflow-definition.js';
|
|
7
7
|
import type { ValidationCriteria } from '../../../types/validation.js';
|
|
8
|
-
import type { AssessmentArtifactV1 } from '../../../v2/durable-core/schemas/artifacts/index.js';
|
|
9
|
-
import type { RecordedAssessmentV1 } from '../../../v2/durable-core/domain/assessment-record.js';
|
|
10
8
|
import type { TriggeredAssessmentConsequenceV1 } from './assessment-consequences.js';
|
|
11
9
|
import type { InternalError } from '../v2-error-mapping.js';
|
|
12
10
|
import type { SessionIndex } from '../../../v2/durable-core/session-index.js';
|
|
@@ -25,8 +23,6 @@ export interface ValidatedAdvanceInputs {
|
|
|
25
23
|
readonly outputContract: OutputContract | undefined;
|
|
26
24
|
readonly notesMarkdown: string | undefined;
|
|
27
25
|
readonly artifacts: readonly unknown[];
|
|
28
|
-
readonly assessmentArtifact: AssessmentArtifactV1 | undefined;
|
|
29
|
-
readonly recordedAssessment: RecordedAssessmentV1 | undefined;
|
|
30
26
|
readonly triggeredAssessmentConsequence: TriggeredAssessmentConsequenceV1 | undefined;
|
|
31
27
|
readonly stepAssessments: readonly AssessmentDefinition[];
|
|
32
28
|
readonly autonomy: 'guided' | 'full_auto_stop_on_user_deps' | 'full_auto_never_stop';
|
|
@@ -48,7 +48,7 @@ function validateAdvanceInputs(args) {
|
|
|
48
48
|
: undefined;
|
|
49
49
|
const triggeredAssessmentConsequence = (0, assessment_consequences_js_1.evaluateAssessmentConsequences)({
|
|
50
50
|
step: typedStep,
|
|
51
|
-
|
|
51
|
+
recordedAssessments: assessmentValidation?.recordedAssessments ?? [],
|
|
52
52
|
});
|
|
53
53
|
const notesOptional = outputContract !== undefined ||
|
|
54
54
|
(step !== null && step !== undefined && 'notesOptional' in step && step.notesOptional === true);
|
|
@@ -92,8 +92,6 @@ function validateAdvanceInputs(args) {
|
|
|
92
92
|
outputContract,
|
|
93
93
|
notesMarkdown: inputOutput?.notesMarkdown,
|
|
94
94
|
artifacts: inputOutput?.artifacts ?? [],
|
|
95
|
-
assessmentArtifact: assessmentValidation?.acceptedArtifact,
|
|
96
|
-
recordedAssessment: assessmentValidation?.recordedAssessment,
|
|
97
95
|
triggeredAssessmentConsequence,
|
|
98
96
|
stepAssessments,
|
|
99
97
|
autonomy,
|
|
@@ -65,8 +65,13 @@ function buildBlockedOutcome(args) {
|
|
|
65
65
|
? outputAppendResult.value
|
|
66
66
|
: [];
|
|
67
67
|
const validated = args.v;
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
const acceptedArtifacts = validated?.assessmentValidation?.acceptedArtifacts ?? [];
|
|
69
|
+
for (let i = 0; i < acceptedArtifacts.length; i++) {
|
|
70
|
+
const { artifactIndex } = acceptedArtifacts[i];
|
|
71
|
+
const recordedAssessment = validated?.assessmentValidation?.recordedAssessments[i];
|
|
72
|
+
if (!recordedAssessment)
|
|
73
|
+
continue;
|
|
74
|
+
const assessmentOutput = outputsToAppend[artifactIndex];
|
|
70
75
|
if (!assessmentOutput || assessmentOutput.outputChannel !== 'artifact') {
|
|
71
76
|
return errAsync({ kind: 'invariant_violation', message: 'Accepted assessment artifact did not produce a matching artifact output on blocked path.' });
|
|
72
77
|
}
|
|
@@ -75,7 +80,7 @@ function buildBlockedOutcome(args) {
|
|
|
75
80
|
attemptId: String(attemptId),
|
|
76
81
|
artifactOutputId: String(assessmentOutput.outputId),
|
|
77
82
|
scope: { runId: String(runId), nodeId: String(currentNodeId) },
|
|
78
|
-
assessment:
|
|
83
|
+
assessment: recordedAssessment,
|
|
79
84
|
minted: { eventId: idFactory.mintEventId() },
|
|
80
85
|
});
|
|
81
86
|
if (assessmentEventRes.isErr()) {
|
|
@@ -125,8 +125,13 @@ function buildSuccessOutcome(args) {
|
|
|
125
125
|
if (artifactOutputsRes.isErr()) {
|
|
126
126
|
return errAsync(artifactOutputsRes.error);
|
|
127
127
|
}
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
const acceptedArtifacts = v.assessmentValidation?.acceptedArtifacts ?? [];
|
|
129
|
+
for (let i = 0; i < acceptedArtifacts.length; i++) {
|
|
130
|
+
const { artifactIndex } = acceptedArtifacts[i];
|
|
131
|
+
const recordedAssessment = v.assessmentValidation?.recordedAssessments[i];
|
|
132
|
+
if (!recordedAssessment)
|
|
133
|
+
continue;
|
|
134
|
+
const assessmentOutput = artifactOutputsRes.value[artifactIndex];
|
|
130
135
|
if (!assessmentOutput || assessmentOutput.outputChannel !== 'artifact') {
|
|
131
136
|
return errAsync({
|
|
132
137
|
kind: 'invariant_violation',
|
|
@@ -138,7 +143,7 @@ function buildSuccessOutcome(args) {
|
|
|
138
143
|
attemptId: String(attemptId),
|
|
139
144
|
artifactOutputId: String(assessmentOutput.outputId),
|
|
140
145
|
scope: { runId: String(runId), nodeId: String(currentNodeId) },
|
|
141
|
-
assessment:
|
|
146
|
+
assessment: recordedAssessment,
|
|
142
147
|
minted: { eventId: idFactory.mintEventId() },
|
|
143
148
|
});
|
|
144
149
|
if (assessmentEventRes.isErr()) {
|
|
@@ -153,11 +153,11 @@ function buildStepContext(events, completedNodeId) {
|
|
|
153
153
|
console.warn(`[workrail:replay] stepContext projection failed for node '${String(completedNodeId)}' — stepContext will be absent: ${projection.error.message}`);
|
|
154
154
|
return undefined;
|
|
155
155
|
}
|
|
156
|
-
const
|
|
157
|
-
if (!
|
|
156
|
+
const allRecorded = projection.value.byNodeId[String(completedNodeId)];
|
|
157
|
+
if (!allRecorded || allRecorded.length === 0)
|
|
158
158
|
return undefined;
|
|
159
159
|
return {
|
|
160
|
-
assessments: {
|
|
160
|
+
assessments: allRecorded.map((recorded) => ({
|
|
161
161
|
assessmentId: recorded.assessmentId,
|
|
162
162
|
dimensions: recorded.dimensions.map((d) => ({
|
|
163
163
|
dimensionId: d.dimensionId,
|
|
@@ -165,7 +165,7 @@ function buildStepContext(events, completedNodeId) {
|
|
|
165
165
|
...(d.rationale !== undefined ? { rationale: d.rationale } : {}),
|
|
166
166
|
})),
|
|
167
167
|
normalizationNotes: recorded.normalizationNotes,
|
|
168
|
-
},
|
|
168
|
+
})),
|
|
169
169
|
};
|
|
170
170
|
}
|
|
171
171
|
function replayFromRecordedAdvance(args) {
|