@dailephd/my-dev-kit-lab 0.4.2 → 0.4.4
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/README.md +28 -113
- package/benchmarks/contracts/todo-behavior.md +1 -1
- package/benchmarks/projects/task-analytics-large-mixed/README.md +2 -0
- package/benchmarks/projects/task-workflow-medium-ts/README.md +3 -1
- package/dist/src/evaluation/stageContextDeterminism/calculateStageContextDeterminism.js +52 -0
- package/dist/src/evaluation/stageContextDeterminism/canonicalizeStageContextRun.js +53 -0
- package/dist/src/evaluation/stageContextDeterminism/index.js +2 -0
- package/dist/src/evaluation/stageContextDeterminism/types.js +1 -0
- package/dist/src/evaluation/stageContextExpectations/index.js +2 -0
- package/dist/src/evaluation/stageContextExpectations/producerReadinessExpectationTypes.js +8 -0
- package/dist/src/evaluation/stageContextExpectations/readStageContextExpectationFixtureV1.js +50 -0
- package/dist/src/evaluation/stageContextExpectations/readTypes.js +1 -0
- package/dist/src/evaluation/stageContextExpectations/types.js +1 -0
- package/dist/src/evaluation/stageContextExpectations/validation.js +768 -0
- package/dist/src/evaluation/stageContextMetrics/calculateAllocationMetrics.js +96 -0
- package/dist/src/evaluation/stageContextMetrics/calculateArtifactStateMetrics.js +130 -0
- package/dist/src/evaluation/stageContextMetrics/calculateContextSizeMetrics.js +85 -0
- package/dist/src/evaluation/stageContextMetrics/calculateCriticalityMetrics.js +112 -0
- package/dist/src/evaluation/stageContextMetrics/calculateExpectationMetrics.js +103 -0
- package/dist/src/evaluation/stageContextMetrics/calculateOwnerMetrics.js +84 -0
- package/dist/src/evaluation/stageContextMetrics/calculateReadinessAgreement.js +152 -0
- package/dist/src/evaluation/stageContextMetrics/calculateResponsibilityMappingMetrics.js +36 -0
- package/dist/src/evaluation/stageContextMetrics/calculateSupplementalRawAgreement.js +50 -0
- package/dist/src/evaluation/stageContextMetrics/calculateTruncationClassification.js +44 -0
- package/dist/src/evaluation/stageContextMetrics/collectContextCapsuleEvidence.js +312 -0
- package/dist/src/evaluation/stageContextMetrics/collectRetrievalAuditEvidence.js +35 -0
- package/dist/src/evaluation/stageContextMetrics/collectWorkflowInstructionEvidence.js +137 -0
- package/dist/src/evaluation/stageContextMetrics/evaluateProducerReadinessBridge.js +127 -0
- package/dist/src/evaluation/stageContextMetrics/evaluateV043StageContextExecution.js +247 -0
- package/dist/src/evaluation/stageContextMetrics/index.js +17 -0
- package/dist/src/evaluation/stageContextMetrics/matchStageContextExpectations.js +38 -0
- package/dist/src/evaluation/stageContextMetrics/producerReadinessMetricTypes.js +1 -0
- package/dist/src/evaluation/stageContextMetrics/targetKeys.js +35 -0
- package/dist/src/evaluation/stageContextMetrics/types.js +1 -0
- package/dist/src/evaluation/stageContextSelectors/contextArtifactConsistency.js +89 -0
- package/dist/src/evaluation/stageContextSelectors/contextCapsuleSelectors.js +126 -0
- package/dist/src/evaluation/stageContextSelectors/index.js +4 -0
- package/dist/src/evaluation/stageContextSelectors/retrievalAuditRecordSelectors.js +54 -0
- package/dist/src/evaluation/stageContextSelectors/workflowInstructionPacketSelectors.js +51 -0
- package/dist/src/evaluation/targetImmutability/captureTargetSnapshot.js +208 -0
- package/dist/src/evaluation/targetImmutability/compareTargetSnapshots.js +56 -0
- package/dist/src/evaluation/targetImmutability/index.js +3 -0
- package/dist/src/evaluation/targetImmutability/types.js +1 -0
- package/dist/src/evaluation/targetImmutability/validateTargetImmutabilityConfig.js +130 -0
- package/dist/src/evaluation/upstreamArtifacts/artifactReadTypes.js +1 -0
- package/dist/src/evaluation/upstreamArtifacts/index.js +9 -0
- package/dist/src/evaluation/upstreamArtifacts/jsonTypes.js +1 -0
- package/dist/src/evaluation/upstreamArtifacts/myDevKitClassificationTypesV1.js +1 -0
- package/dist/src/evaluation/upstreamArtifacts/myDevKitContextArtifactsV1.js +1 -0
- package/dist/src/evaluation/upstreamArtifacts/myDevKitSemanticTypesV1.js +1 -0
- package/dist/src/evaluation/upstreamArtifacts/orchestratorContextReadinessResultV1.js +247 -0
- package/dist/src/evaluation/upstreamArtifacts/orchestratorWorkflowInstructionPacketV1.js +1 -0
- package/dist/src/evaluation/upstreamArtifacts/readImplementationContextPacketV1.js +9 -0
- package/dist/src/evaluation/upstreamArtifacts/readImplementationContextRetrievalReportV1.js +9 -0
- package/dist/src/evaluation/upstreamArtifacts/readJsonArtifact.js +53 -0
- package/dist/src/evaluation/upstreamArtifacts/readMyDevKitContextCapsuleV1.js +9 -0
- package/dist/src/evaluation/upstreamArtifacts/readMyDevKitRetrievalAuditRecordV1.js +9 -0
- package/dist/src/evaluation/upstreamArtifacts/readOrchestratorWorkflowInstructionPacketV1.js +9 -0
- package/dist/src/evaluation/upstreamArtifacts/readSupplementalContextTextFile.js +29 -0
- package/dist/src/evaluation/upstreamArtifacts/readTestContextPacketV1.js +9 -0
- package/dist/src/evaluation/upstreamArtifacts/readTestContextRetrievalReportV1.js +9 -0
- package/dist/src/evaluation/upstreamArtifacts/runtimeValidation.js +131 -0
- package/dist/src/evaluation/upstreamArtifacts/schemaVersion.js +32 -0
- package/dist/src/evaluation/upstreamArtifacts/supplementalContextTextParser.js +75 -0
- package/dist/src/evaluation/upstreamArtifacts/supplementalContextTypes.js +152 -0
- package/dist/src/evaluation/upstreamArtifacts/validateMyDevKitContextCapsuleV1.js +1208 -0
- package/dist/src/evaluation/upstreamArtifacts/validateMyDevKitRetrievalAuditRecordV1.js +112 -0
- package/dist/src/evaluation/upstreamArtifacts/validateOrchestratorWorkflowInstructionPacketV1.js +235 -0
- package/dist/src/evaluation/upstreamArtifacts/validateSupplementalContextDocumentV1.js +148 -0
- package/dist/src/experiments/plugins/contextStrategyComparison/executeV043StageContextStrategy.js +46 -0
- package/dist/src/experiments/plugins/contextStrategyComparison/index.js +9 -0
- package/dist/src/experiments/plugins/contextStrategyComparison/loadV043StrategyArtifacts.js +397 -0
- package/dist/src/experiments/plugins/contextStrategyComparison/plugin.js +39 -1
- package/dist/src/experiments/plugins/contextStrategyComparison/readV043FullWorkflowLibraryFixture.js +162 -0
- package/dist/src/experiments/plugins/contextStrategyComparison/resolveV043StrategyInputs.js +43 -0
- package/dist/src/experiments/plugins/contextStrategyComparison/resultMapping.js +3 -0
- package/dist/src/experiments/plugins/contextStrategyComparison/runV043StageContextStrategyWithAssurance.js +205 -0
- package/dist/src/experiments/plugins/contextStrategyComparison/v043FullWorkflowLibraryFixture.js +1 -0
- package/dist/src/experiments/plugins/contextStrategyComparison/v043RunAssuranceTypes.js +1 -0
- package/dist/src/experiments/plugins/contextStrategyComparison/v043StrategyExecutionTypes.js +1 -0
- package/dist/src/experiments/plugins/contextStrategyComparison/v043StrategyIds.js +13 -0
- package/dist/src/experiments/plugins/contextStrategyComparison/v043StrategyInputContracts.js +1 -0
- package/dist/src/experiments/plugins/contextStrategyComparison/validateV043RunAssuranceConfig.js +59 -0
- package/dist/src/experiments/plugins/contextStrategyComparison/validateV043StrategyInput.js +266 -0
- package/dist/src/report/experiments/buildContextStrategyComparisonV043Report.js +520 -0
- package/dist/src/report/experiments/buildPluginExperimentReport.js +21 -6
- package/dist/src/report/experiments/contextStrategyComparisonV043ReportModel.js +1 -0
- package/dist/src/report/experiments/index.js +4 -0
- package/dist/src/report/experiments/renderContextStrategyComparisonV043Html.js +296 -0
- package/dist/src/report/experiments/renderPluginExperimentReportHtml.js +3 -0
- package/dist/src/report/experiments/renderPluginExperimentReportText.js +292 -0
- package/dist/src/report/experiments/writePluginExperimentReports.js +3 -0
- package/dist/src/securityValidation/attackScenarios/scenarios/secretLeakageScenario.js +215 -9
- package/docs/METRICS.md +84 -10
- package/package.json +2 -2
- package/tests/fixtures/full-workflow-library/complete-v1.0.0.json +24 -0
- package/tests/fixtures/full-workflow-library/future-minor-v1.1.0-additive.json +25 -0
- package/tests/fixtures/stage-context-expectations/complete-v1.0.0.json +230 -0
- package/tests/fixtures/stage-context-expectations/future-minor-v1.1.0-additive.json +232 -0
- package/tests/fixtures/stage-context-expectations/invalid/malformed-json.txt +1 -0
- package/tests/fixtures/stage-context-expectations/invalid/non-object-root.json +1 -0
- package/tests/fixtures/stage-context-expectations/minimal-v1.0.0.json +18 -0
- package/tests/fixtures/upstream-artifacts/invalid/malformed-json.txt +1 -0
- package/tests/fixtures/upstream-artifacts/invalid/non-object-root.json +1 -0
- package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.2/context-capsule/complete-v1.0.0.json +504 -0
- package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.2/context-capsule/future-minor-v1.1.0-additive.json +955 -0
- package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.2/retrieval-audit-record/complete-v1.0.0.json +190 -0
- package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.2/retrieval-audit-record/future-minor-v1.1.0-additive.json +327 -0
- package/tests/fixtures/upstream-artifacts/my-dev-kit-1.10.2-identity/PROVENANCE.txt +13 -0
- package/tests/fixtures/upstream-artifacts/my-dev-kit-1.10.2-identity/context-capsule.json +7874 -0
- package/tests/fixtures/upstream-artifacts/my-dev-kit-1.10.2-identity/retrieval-audit-record.json +1076 -0
- package/tests/fixtures/upstream-artifacts/my-dev-kit-orchestrator/1.2.1/workflow-instruction-packet/complete-v1.0.0.json +160 -0
- package/tests/fixtures/upstream-artifacts/my-dev-kit-orchestrator/1.2.1/workflow-instruction-packet/future-minor-v1.1.0-additive.json +186 -0
|
@@ -0,0 +1,768 @@
|
|
|
1
|
+
const SCHEMA_VERSION_PATTERN = /^[0-9]+\.[0-9]+\.[0-9]+$/;
|
|
2
|
+
const CASE_ID_PATTERN = /^CASE-[A-Z0-9]+(?:-[A-Z0-9]+)*-[0-9]{3}$/;
|
|
3
|
+
const EXPECTATION_ID_PATTERN = /^(REQ|ALLOW|FORBID)-[A-Z0-9]+(?:-[A-Z0-9]+)*-[0-9]{3}$/;
|
|
4
|
+
const INCLUSION_VALUES = ["required", "allowed", "forbidden"];
|
|
5
|
+
const SOURCE_ARTIFACT_VALUES = [
|
|
6
|
+
"context-capsule",
|
|
7
|
+
"retrieval-audit-record",
|
|
8
|
+
"workflow-instruction-packet",
|
|
9
|
+
"full-workflow-library"
|
|
10
|
+
];
|
|
11
|
+
const CATEGORY_VALUES = [
|
|
12
|
+
"file",
|
|
13
|
+
"symbol",
|
|
14
|
+
"source-range",
|
|
15
|
+
"contract",
|
|
16
|
+
"validator",
|
|
17
|
+
"constant",
|
|
18
|
+
"error",
|
|
19
|
+
"schema-or-serializer",
|
|
20
|
+
"production-responsibility",
|
|
21
|
+
"test-file",
|
|
22
|
+
"fixture",
|
|
23
|
+
"factory",
|
|
24
|
+
"mock",
|
|
25
|
+
"setup-file",
|
|
26
|
+
"test-configuration",
|
|
27
|
+
"package-script",
|
|
28
|
+
"test-command",
|
|
29
|
+
"workflow",
|
|
30
|
+
"stage",
|
|
31
|
+
"command",
|
|
32
|
+
"rule",
|
|
33
|
+
"report-contract",
|
|
34
|
+
"provenance"
|
|
35
|
+
];
|
|
36
|
+
const PATH_CATEGORIES = [
|
|
37
|
+
"file",
|
|
38
|
+
"test-file",
|
|
39
|
+
"fixture",
|
|
40
|
+
"factory",
|
|
41
|
+
"mock",
|
|
42
|
+
"setup-file",
|
|
43
|
+
"test-configuration"
|
|
44
|
+
];
|
|
45
|
+
const SYMBOL_CATEGORIES = [
|
|
46
|
+
"symbol",
|
|
47
|
+
"contract",
|
|
48
|
+
"validator",
|
|
49
|
+
"constant",
|
|
50
|
+
"error",
|
|
51
|
+
"schema-or-serializer"
|
|
52
|
+
];
|
|
53
|
+
const WORKFLOW_STABLE_ID_CATEGORIES = [
|
|
54
|
+
"workflow",
|
|
55
|
+
"stage",
|
|
56
|
+
"command",
|
|
57
|
+
"rule",
|
|
58
|
+
"report-contract"
|
|
59
|
+
];
|
|
60
|
+
const INCLUSION_PREFIX = {
|
|
61
|
+
required: "REQ-",
|
|
62
|
+
allowed: "ALLOW-",
|
|
63
|
+
forbidden: "FORBID-"
|
|
64
|
+
};
|
|
65
|
+
const CONTEXT_ADEQUACY_STATUS_VALUES = [
|
|
66
|
+
"context sufficient for implementation",
|
|
67
|
+
"context sufficient with listed assumptions",
|
|
68
|
+
"context insufficient and more retrieval required",
|
|
69
|
+
"context conflict found and user or upstream stage decision required"
|
|
70
|
+
];
|
|
71
|
+
const FRESHNESS_STATE_VALUES = ["fresh", "stale", "unknown"];
|
|
72
|
+
const PACKET_ADEQUACY_STATUS_VALUES = ["adequate", "inadequate"];
|
|
73
|
+
function failure(sourcePath, code, message, extra) {
|
|
74
|
+
return { ok: false, sourcePath, code, message, ...extra };
|
|
75
|
+
}
|
|
76
|
+
function isPlainObject(value) {
|
|
77
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
78
|
+
}
|
|
79
|
+
function isStringArray(value) {
|
|
80
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
81
|
+
}
|
|
82
|
+
function isNonNegativeInteger(value) {
|
|
83
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 0;
|
|
84
|
+
}
|
|
85
|
+
function isPositiveInteger(value) {
|
|
86
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0;
|
|
87
|
+
}
|
|
88
|
+
function hasDuplicates(values) {
|
|
89
|
+
return new Set(values).size !== values.length;
|
|
90
|
+
}
|
|
91
|
+
function requireNonEmptyString(root, key, fieldPath, sourcePath) {
|
|
92
|
+
const value = root[key];
|
|
93
|
+
if (value === undefined) {
|
|
94
|
+
return failure(sourcePath, "MISSING_REQUIRED_FIELD", `${fieldPath} is required.`, { fieldPath });
|
|
95
|
+
}
|
|
96
|
+
if (typeof value !== "string") {
|
|
97
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${fieldPath} must be a string.`, { fieldPath });
|
|
98
|
+
}
|
|
99
|
+
if (value.trim().length === 0) {
|
|
100
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${fieldPath} must be a nonempty string.`, { fieldPath });
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
export function validateStageContextExpectationFixtureV1(value, sourcePath) {
|
|
105
|
+
const root = value;
|
|
106
|
+
if (root.schemaVersion === undefined) {
|
|
107
|
+
return failure(sourcePath, "MISSING_REQUIRED_FIELD", "schemaVersion is required.", { fieldPath: "schemaVersion" });
|
|
108
|
+
}
|
|
109
|
+
if (typeof root.schemaVersion !== "string") {
|
|
110
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", "schemaVersion must be a string.", { fieldPath: "schemaVersion" });
|
|
111
|
+
}
|
|
112
|
+
if (!SCHEMA_VERSION_PATTERN.test(root.schemaVersion)) {
|
|
113
|
+
return failure(sourcePath, "INVALID_SCHEMA_VERSION", `schemaVersion "${root.schemaVersion}" does not match x.y.z.`, {
|
|
114
|
+
fieldPath: "schemaVersion",
|
|
115
|
+
actual: root.schemaVersion
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
const schemaVersionValue = root.schemaVersion;
|
|
119
|
+
const schemaMajor = Number(schemaVersionValue.split(".")[0]);
|
|
120
|
+
if (schemaMajor !== 1) {
|
|
121
|
+
return failure(sourcePath, "UNSUPPORTED_SCHEMA_MAJOR", `schemaVersion major "${schemaMajor}" is not supported.`, {
|
|
122
|
+
fieldPath: "schemaVersion",
|
|
123
|
+
actual: schemaVersionValue
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
if (root.caseId === undefined) {
|
|
127
|
+
return failure(sourcePath, "MISSING_REQUIRED_FIELD", "caseId is required.", { fieldPath: "caseId" });
|
|
128
|
+
}
|
|
129
|
+
if (typeof root.caseId !== "string") {
|
|
130
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", "caseId must be a string.", { fieldPath: "caseId" });
|
|
131
|
+
}
|
|
132
|
+
if (!CASE_ID_PATTERN.test(root.caseId)) {
|
|
133
|
+
return failure(sourcePath, "INVALID_CASE_ID", `caseId "${root.caseId}" does not match the required pattern.`, {
|
|
134
|
+
fieldPath: "caseId",
|
|
135
|
+
actual: root.caseId
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
const titleFailure = requireNonEmptyString(root, "title", "title", sourcePath);
|
|
139
|
+
if (titleFailure)
|
|
140
|
+
return titleFailure;
|
|
141
|
+
const descriptionFailure = requireNonEmptyString(root, "description", "description", sourcePath);
|
|
142
|
+
if (descriptionFailure)
|
|
143
|
+
return descriptionFailure;
|
|
144
|
+
if (root.expectedEvidence === undefined) {
|
|
145
|
+
return failure(sourcePath, "MISSING_REQUIRED_FIELD", "expectedEvidence is required.", { fieldPath: "expectedEvidence" });
|
|
146
|
+
}
|
|
147
|
+
if (!Array.isArray(root.expectedEvidence)) {
|
|
148
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", "expectedEvidence must be an array.", { fieldPath: "expectedEvidence" });
|
|
149
|
+
}
|
|
150
|
+
if (root.expectedEvidence.length === 0) {
|
|
151
|
+
return failure(sourcePath, "EMPTY_EXPECTATION_SET", "expectedEvidence must contain at least one item.", {
|
|
152
|
+
fieldPath: "expectedEvidence"
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
if (root.expectedStates === undefined) {
|
|
156
|
+
return failure(sourcePath, "MISSING_REQUIRED_FIELD", "expectedStates is required.", { fieldPath: "expectedStates" });
|
|
157
|
+
}
|
|
158
|
+
if (!isPlainObject(root.expectedStates)) {
|
|
159
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", "expectedStates must be an object.", { fieldPath: "expectedStates" });
|
|
160
|
+
}
|
|
161
|
+
if (root.warnings === undefined) {
|
|
162
|
+
return failure(sourcePath, "MISSING_REQUIRED_FIELD", "warnings is required.", { fieldPath: "warnings" });
|
|
163
|
+
}
|
|
164
|
+
if (!isStringArray(root.warnings)) {
|
|
165
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", "warnings must be an array of strings.", { fieldPath: "warnings" });
|
|
166
|
+
}
|
|
167
|
+
const items = root.expectedEvidence;
|
|
168
|
+
for (let index = 0; index < items.length; index += 1) {
|
|
169
|
+
const itemFailure = validateExpectationItem(items[index], `expectedEvidence[${index}]`, sourcePath);
|
|
170
|
+
if (itemFailure)
|
|
171
|
+
return itemFailure;
|
|
172
|
+
}
|
|
173
|
+
const typedItems = items;
|
|
174
|
+
const seenIds = new Set();
|
|
175
|
+
for (let index = 0; index < typedItems.length; index += 1) {
|
|
176
|
+
const id = typedItems[index].expectationId;
|
|
177
|
+
if (seenIds.has(id)) {
|
|
178
|
+
return failure(sourcePath, "DUPLICATE_EXPECTATION_ID", `expectationId "${id}" is duplicated.`, {
|
|
179
|
+
fieldPath: `expectedEvidence[${index}].expectationId`,
|
|
180
|
+
actual: id
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
seenIds.add(id);
|
|
184
|
+
}
|
|
185
|
+
const seenTargets = new Map();
|
|
186
|
+
for (let index = 0; index < typedItems.length; index += 1) {
|
|
187
|
+
const item = typedItems[index];
|
|
188
|
+
const targetKey = buildTargetKey(item);
|
|
189
|
+
const inclusion = item.inclusion;
|
|
190
|
+
const existingInclusion = seenTargets.get(targetKey);
|
|
191
|
+
if (existingInclusion !== undefined) {
|
|
192
|
+
if (existingInclusion === inclusion) {
|
|
193
|
+
return failure(sourcePath, "DUPLICATE_EXPECTATION_TARGET", `Target "${targetKey}" is duplicated with the same inclusion.`, { fieldPath: `expectedEvidence[${index}]`, actual: targetKey });
|
|
194
|
+
}
|
|
195
|
+
return failure(sourcePath, "CONFLICTING_EXPECTATION_INCLUSION", `Target "${targetKey}" has conflicting inclusion values.`, { fieldPath: `expectedEvidence[${index}]`, actual: targetKey });
|
|
196
|
+
}
|
|
197
|
+
seenTargets.set(targetKey, inclusion);
|
|
198
|
+
}
|
|
199
|
+
const statesFailure = validateExpectedStates(root.expectedStates, sourcePath);
|
|
200
|
+
if (statesFailure)
|
|
201
|
+
return statesFailure;
|
|
202
|
+
if (root.producerReadinessExpectations !== undefined) {
|
|
203
|
+
const producerReadinessFailure = validateProducerReadinessExpectations(root.producerReadinessExpectations, sourcePath);
|
|
204
|
+
if (producerReadinessFailure)
|
|
205
|
+
return producerReadinessFailure;
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
ok: true,
|
|
209
|
+
sourcePath,
|
|
210
|
+
schemaVersion: schemaVersionValue,
|
|
211
|
+
schemaMajor: 1,
|
|
212
|
+
fixture: value,
|
|
213
|
+
rawFixture: value
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
function validateExpectationItem(itemValue, itemPath, sourcePath) {
|
|
217
|
+
if (!isPlainObject(itemValue)) {
|
|
218
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath} must be an object.`, { fieldPath: itemPath });
|
|
219
|
+
}
|
|
220
|
+
const item = itemValue;
|
|
221
|
+
if (item.expectationId === undefined) {
|
|
222
|
+
return failure(sourcePath, "MISSING_REQUIRED_FIELD", `${itemPath}.expectationId is required.`, {
|
|
223
|
+
fieldPath: `${itemPath}.expectationId`
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
if (typeof item.expectationId !== "string") {
|
|
227
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath}.expectationId must be a string.`, {
|
|
228
|
+
fieldPath: `${itemPath}.expectationId`
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
if (item.inclusion === undefined) {
|
|
232
|
+
return failure(sourcePath, "MISSING_REQUIRED_FIELD", `${itemPath}.inclusion is required.`, {
|
|
233
|
+
fieldPath: `${itemPath}.inclusion`
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
if (typeof item.inclusion !== "string") {
|
|
237
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath}.inclusion must be a string.`, {
|
|
238
|
+
fieldPath: `${itemPath}.inclusion`
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
if (!INCLUSION_VALUES.includes(item.inclusion)) {
|
|
242
|
+
return failure(sourcePath, "INVALID_LITERAL_VALUE", `${itemPath}.inclusion "${item.inclusion}" is not valid.`, {
|
|
243
|
+
fieldPath: `${itemPath}.inclusion`,
|
|
244
|
+
actual: item.inclusion
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
if (item.sourceArtifact === undefined) {
|
|
248
|
+
return failure(sourcePath, "MISSING_REQUIRED_FIELD", `${itemPath}.sourceArtifact is required.`, {
|
|
249
|
+
fieldPath: `${itemPath}.sourceArtifact`
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
if (typeof item.sourceArtifact !== "string") {
|
|
253
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath}.sourceArtifact must be a string.`, {
|
|
254
|
+
fieldPath: `${itemPath}.sourceArtifact`
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
if (!SOURCE_ARTIFACT_VALUES.includes(item.sourceArtifact)) {
|
|
258
|
+
return failure(sourcePath, "INVALID_LITERAL_VALUE", `${itemPath}.sourceArtifact "${item.sourceArtifact}" is not valid.`, {
|
|
259
|
+
fieldPath: `${itemPath}.sourceArtifact`,
|
|
260
|
+
actual: item.sourceArtifact
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
if (item.category === undefined) {
|
|
264
|
+
return failure(sourcePath, "MISSING_REQUIRED_FIELD", `${itemPath}.category is required.`, {
|
|
265
|
+
fieldPath: `${itemPath}.category`
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
if (typeof item.category !== "string") {
|
|
269
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath}.category must be a string.`, {
|
|
270
|
+
fieldPath: `${itemPath}.category`
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
if (!CATEGORY_VALUES.includes(item.category)) {
|
|
274
|
+
return failure(sourcePath, "INVALID_LITERAL_VALUE", `${itemPath}.category "${item.category}" is not valid.`, {
|
|
275
|
+
fieldPath: `${itemPath}.category`,
|
|
276
|
+
actual: item.category
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
if (item.match === undefined) {
|
|
280
|
+
return failure(sourcePath, "MISSING_REQUIRED_FIELD", `${itemPath}.match is required.`, {
|
|
281
|
+
fieldPath: `${itemPath}.match`
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
if (!isPlainObject(item.match)) {
|
|
285
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath}.match must be an object.`, {
|
|
286
|
+
fieldPath: `${itemPath}.match`
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
if (item.notes === undefined) {
|
|
290
|
+
return failure(sourcePath, "MISSING_REQUIRED_FIELD", `${itemPath}.notes is required.`, {
|
|
291
|
+
fieldPath: `${itemPath}.notes`
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
if (!isStringArray(item.notes)) {
|
|
295
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath}.notes must be an array of strings.`, {
|
|
296
|
+
fieldPath: `${itemPath}.notes`
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
const expectationId = item.expectationId;
|
|
300
|
+
if (!EXPECTATION_ID_PATTERN.test(expectationId)) {
|
|
301
|
+
return failure(sourcePath, "INVALID_EXPECTATION_ID", `${itemPath}.expectationId "${expectationId}" does not match the required pattern.`, { fieldPath: `${itemPath}.expectationId`, actual: expectationId });
|
|
302
|
+
}
|
|
303
|
+
const inclusion = item.inclusion;
|
|
304
|
+
const requiredPrefix = INCLUSION_PREFIX[inclusion];
|
|
305
|
+
if (!expectationId.startsWith(requiredPrefix)) {
|
|
306
|
+
return failure(sourcePath, "EXPECTATION_ID_PREFIX_MISMATCH", `${itemPath}.expectationId "${expectationId}" does not have the "${requiredPrefix}" prefix required by inclusion "${inclusion}".`, { fieldPath: `${itemPath}.expectationId`, actual: expectationId });
|
|
307
|
+
}
|
|
308
|
+
const category = item.category;
|
|
309
|
+
const sourceArtifact = item.sourceArtifact;
|
|
310
|
+
const pairFailure = validateCategorySourcePair(category, sourceArtifact, itemPath, sourcePath);
|
|
311
|
+
if (pairFailure)
|
|
312
|
+
return pairFailure;
|
|
313
|
+
const matchFailure = validateMatchFields(category, item.match, itemPath, sourcePath);
|
|
314
|
+
if (matchFailure)
|
|
315
|
+
return matchFailure;
|
|
316
|
+
return null;
|
|
317
|
+
}
|
|
318
|
+
function allowedSourceArtifactsForCategory(category) {
|
|
319
|
+
if (PATH_CATEGORIES.includes(category))
|
|
320
|
+
return ["context-capsule"];
|
|
321
|
+
if (SYMBOL_CATEGORIES.includes(category))
|
|
322
|
+
return ["context-capsule"];
|
|
323
|
+
if (category === "source-range")
|
|
324
|
+
return ["context-capsule"];
|
|
325
|
+
if (category === "production-responsibility")
|
|
326
|
+
return ["context-capsule", "retrieval-audit-record"];
|
|
327
|
+
if (category === "package-script")
|
|
328
|
+
return ["context-capsule"];
|
|
329
|
+
if (category === "test-command")
|
|
330
|
+
return ["context-capsule"];
|
|
331
|
+
if (WORKFLOW_STABLE_ID_CATEGORIES.includes(category)) {
|
|
332
|
+
return ["workflow-instruction-packet", "full-workflow-library"];
|
|
333
|
+
}
|
|
334
|
+
return SOURCE_ARTIFACT_VALUES;
|
|
335
|
+
}
|
|
336
|
+
function validateCategorySourcePair(category, sourceArtifact, itemPath, sourcePath) {
|
|
337
|
+
const allowed = allowedSourceArtifactsForCategory(category);
|
|
338
|
+
if (!allowed.includes(sourceArtifact)) {
|
|
339
|
+
return failure(sourcePath, "INVALID_CATEGORY_SOURCE_PAIR", `${itemPath} category "${category}" is not valid for sourceArtifact "${sourceArtifact}".`, { fieldPath: `${itemPath}.sourceArtifact`, actual: sourceArtifact });
|
|
340
|
+
}
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
function requireNonEmptyMatchString(match, key, itemPath, sourcePath) {
|
|
344
|
+
const value = match[key];
|
|
345
|
+
if (value === undefined) {
|
|
346
|
+
return failure(sourcePath, "MISSING_REQUIRED_FIELD", `${itemPath}.match.${key} is required.`, {
|
|
347
|
+
fieldPath: `${itemPath}.match.${key}`
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
if (typeof value !== "string") {
|
|
351
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath}.match.${key} must be a string.`, {
|
|
352
|
+
fieldPath: `${itemPath}.match.${key}`
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
if (value.trim().length === 0) {
|
|
356
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath}.match.${key} must be a nonempty string.`, {
|
|
357
|
+
fieldPath: `${itemPath}.match.${key}`
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
function validateMatchFields(category, match, itemPath, sourcePath) {
|
|
363
|
+
if (PATH_CATEGORIES.includes(category)) {
|
|
364
|
+
return requireNonEmptyMatchString(match, "path", itemPath, sourcePath);
|
|
365
|
+
}
|
|
366
|
+
if (SYMBOL_CATEGORIES.includes(category)) {
|
|
367
|
+
return requireNonEmptyMatchString(match, "symbolId", itemPath, sourcePath);
|
|
368
|
+
}
|
|
369
|
+
if (category === "source-range") {
|
|
370
|
+
const filePathFailure = requireNonEmptyMatchString(match, "filePath", itemPath, sourcePath);
|
|
371
|
+
if (filePathFailure)
|
|
372
|
+
return filePathFailure;
|
|
373
|
+
if (match.startLine === undefined) {
|
|
374
|
+
return failure(sourcePath, "MISSING_REQUIRED_FIELD", `${itemPath}.match.startLine is required.`, {
|
|
375
|
+
fieldPath: `${itemPath}.match.startLine`
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
if (!isPositiveInteger(match.startLine)) {
|
|
379
|
+
return failure(sourcePath, "INVALID_SOURCE_RANGE", `${itemPath}.match.startLine must be a positive integer.`, {
|
|
380
|
+
fieldPath: `${itemPath}.match.startLine`,
|
|
381
|
+
actual: match.startLine
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
if (match.endLine === undefined) {
|
|
385
|
+
return failure(sourcePath, "MISSING_REQUIRED_FIELD", `${itemPath}.match.endLine is required.`, {
|
|
386
|
+
fieldPath: `${itemPath}.match.endLine`
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
if (!isPositiveInteger(match.endLine)) {
|
|
390
|
+
return failure(sourcePath, "INVALID_SOURCE_RANGE", `${itemPath}.match.endLine must be a positive integer.`, {
|
|
391
|
+
fieldPath: `${itemPath}.match.endLine`,
|
|
392
|
+
actual: match.endLine
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
if (match.endLine < match.startLine) {
|
|
396
|
+
return failure(sourcePath, "INVALID_SOURCE_RANGE", `${itemPath}.match.endLine must be >= startLine.`, {
|
|
397
|
+
fieldPath: `${itemPath}.match.endLine`,
|
|
398
|
+
actual: match.endLine
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
return null;
|
|
402
|
+
}
|
|
403
|
+
if (category === "production-responsibility") {
|
|
404
|
+
return requireNonEmptyMatchString(match, "responsibilityId", itemPath, sourcePath);
|
|
405
|
+
}
|
|
406
|
+
if (category === "package-script") {
|
|
407
|
+
return requireNonEmptyMatchString(match, "name", itemPath, sourcePath);
|
|
408
|
+
}
|
|
409
|
+
if (category === "test-command") {
|
|
410
|
+
return requireNonEmptyMatchString(match, "commandText", itemPath, sourcePath);
|
|
411
|
+
}
|
|
412
|
+
if (WORKFLOW_STABLE_ID_CATEGORIES.includes(category)) {
|
|
413
|
+
return requireNonEmptyMatchString(match, "id", itemPath, sourcePath);
|
|
414
|
+
}
|
|
415
|
+
return requireNonEmptyMatchString(match, "evidenceId", itemPath, sourcePath);
|
|
416
|
+
}
|
|
417
|
+
function buildTargetKey(item) {
|
|
418
|
+
const category = item.category;
|
|
419
|
+
const sourceArtifact = item.sourceArtifact;
|
|
420
|
+
const match = item.match;
|
|
421
|
+
if (PATH_CATEGORIES.includes(category)) {
|
|
422
|
+
return `${sourceArtifact}|${category}|path:${match.path}`;
|
|
423
|
+
}
|
|
424
|
+
if (SYMBOL_CATEGORIES.includes(category)) {
|
|
425
|
+
return `${sourceArtifact}|${category}|symbolId:${match.symbolId}`;
|
|
426
|
+
}
|
|
427
|
+
if (category === "source-range") {
|
|
428
|
+
return `context-capsule|source-range|filePath:${match.filePath}|startLine:${match.startLine}|endLine:${match.endLine}`;
|
|
429
|
+
}
|
|
430
|
+
if (category === "production-responsibility") {
|
|
431
|
+
return `${sourceArtifact}|production-responsibility|responsibilityId:${match.responsibilityId}`;
|
|
432
|
+
}
|
|
433
|
+
if (category === "package-script") {
|
|
434
|
+
return `context-capsule|package-script|name:${match.name}`;
|
|
435
|
+
}
|
|
436
|
+
if (category === "test-command") {
|
|
437
|
+
return `context-capsule|test-command|commandText:${match.commandText}`;
|
|
438
|
+
}
|
|
439
|
+
if (WORKFLOW_STABLE_ID_CATEGORIES.includes(category)) {
|
|
440
|
+
return `${sourceArtifact}|${category}|id:${match.id}`;
|
|
441
|
+
}
|
|
442
|
+
return `${sourceArtifact}|provenance|evidenceId:${match.evidenceId}`;
|
|
443
|
+
}
|
|
444
|
+
function validateMyDevKitContextArtifactState(value, fieldPath, sourcePath) {
|
|
445
|
+
if (value === undefined)
|
|
446
|
+
return null;
|
|
447
|
+
if (!isPlainObject(value)) {
|
|
448
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${fieldPath} must be an object.`, { fieldPath });
|
|
449
|
+
}
|
|
450
|
+
if (value.contextAdequacyStatus !== undefined &&
|
|
451
|
+
!CONTEXT_ADEQUACY_STATUS_VALUES.includes(value.contextAdequacyStatus)) {
|
|
452
|
+
return failure(sourcePath, "INVALID_LITERAL_VALUE", `${fieldPath}.contextAdequacyStatus is not valid.`, {
|
|
453
|
+
fieldPath: `${fieldPath}.contextAdequacyStatus`,
|
|
454
|
+
actual: value.contextAdequacyStatus
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
if (value.roleAdequacyStatus !== undefined &&
|
|
458
|
+
!CONTEXT_ADEQUACY_STATUS_VALUES.includes(value.roleAdequacyStatus)) {
|
|
459
|
+
return failure(sourcePath, "INVALID_LITERAL_VALUE", `${fieldPath}.roleAdequacyStatus is not valid.`, {
|
|
460
|
+
fieldPath: `${fieldPath}.roleAdequacyStatus`,
|
|
461
|
+
actual: value.roleAdequacyStatus
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
if (value.freshnessState !== undefined && !FRESHNESS_STATE_VALUES.includes(value.freshnessState)) {
|
|
465
|
+
return failure(sourcePath, "INVALID_LITERAL_VALUE", `${fieldPath}.freshnessState is not valid.`, {
|
|
466
|
+
fieldPath: `${fieldPath}.freshnessState`,
|
|
467
|
+
actual: value.freshnessState
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
if (value.truncated !== undefined && typeof value.truncated !== "boolean") {
|
|
471
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${fieldPath}.truncated must be a boolean.`, {
|
|
472
|
+
fieldPath: `${fieldPath}.truncated`
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
if (value.fullFileFallbackUsed !== undefined && !isNonNegativeInteger(value.fullFileFallbackUsed)) {
|
|
476
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${fieldPath}.fullFileFallbackUsed must be a nonnegative integer.`, {
|
|
477
|
+
fieldPath: `${fieldPath}.fullFileFallbackUsed`,
|
|
478
|
+
actual: value.fullFileFallbackUsed
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
if (value.unresolvedItemIds !== undefined) {
|
|
482
|
+
if (!isStringArray(value.unresolvedItemIds) || value.unresolvedItemIds.some((entry) => entry.length === 0)) {
|
|
483
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${fieldPath}.unresolvedItemIds must be an array of nonempty strings.`, {
|
|
484
|
+
fieldPath: `${fieldPath}.unresolvedItemIds`
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
if (hasDuplicates(value.unresolvedItemIds)) {
|
|
488
|
+
return failure(sourcePath, "DUPLICATE_EXPECTED_VALUE", `${fieldPath}.unresolvedItemIds contains duplicates.`, {
|
|
489
|
+
fieldPath: `${fieldPath}.unresolvedItemIds`
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
if (value.warningCount !== undefined && !isNonNegativeInteger(value.warningCount)) {
|
|
494
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${fieldPath}.warningCount must be a nonnegative integer.`, {
|
|
495
|
+
fieldPath: `${fieldPath}.warningCount`,
|
|
496
|
+
actual: value.warningCount
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
return null;
|
|
500
|
+
}
|
|
501
|
+
function validateWorkflowPacketState(value, sourcePath) {
|
|
502
|
+
const fieldPath = "expectedStates.workflowInstructionPacket";
|
|
503
|
+
if (value === undefined)
|
|
504
|
+
return null;
|
|
505
|
+
if (!isPlainObject(value)) {
|
|
506
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${fieldPath} must be an object.`, { fieldPath });
|
|
507
|
+
}
|
|
508
|
+
if (value.adequacyStatus !== undefined && !PACKET_ADEQUACY_STATUS_VALUES.includes(value.adequacyStatus)) {
|
|
509
|
+
return failure(sourcePath, "INVALID_LITERAL_VALUE", `${fieldPath}.adequacyStatus is not valid.`, {
|
|
510
|
+
fieldPath: `${fieldPath}.adequacyStatus`,
|
|
511
|
+
actual: value.adequacyStatus
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
if (value.truncated !== undefined && typeof value.truncated !== "boolean") {
|
|
515
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${fieldPath}.truncated must be a boolean.`, {
|
|
516
|
+
fieldPath: `${fieldPath}.truncated`
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
if (value.unresolvedReferences !== undefined) {
|
|
520
|
+
if (!isStringArray(value.unresolvedReferences)) {
|
|
521
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${fieldPath}.unresolvedReferences must be an array of strings.`, {
|
|
522
|
+
fieldPath: `${fieldPath}.unresolvedReferences`
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
if (hasDuplicates(value.unresolvedReferences)) {
|
|
526
|
+
return failure(sourcePath, "DUPLICATE_EXPECTED_VALUE", `${fieldPath}.unresolvedReferences contains duplicates.`, {
|
|
527
|
+
fieldPath: `${fieldPath}.unresolvedReferences`
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
if (value.warningCount !== undefined && !isNonNegativeInteger(value.warningCount)) {
|
|
532
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${fieldPath}.warningCount must be a nonnegative integer.`, {
|
|
533
|
+
fieldPath: `${fieldPath}.warningCount`,
|
|
534
|
+
actual: value.warningCount
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
return null;
|
|
538
|
+
}
|
|
539
|
+
function validateTargetImmutabilityState(value, sourcePath) {
|
|
540
|
+
const fieldPath = "expectedStates.targetImmutability";
|
|
541
|
+
if (value === undefined)
|
|
542
|
+
return null;
|
|
543
|
+
if (!isPlainObject(value)) {
|
|
544
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${fieldPath} must be an object.`, { fieldPath });
|
|
545
|
+
}
|
|
546
|
+
if (value.newMutationCount === undefined) {
|
|
547
|
+
return failure(sourcePath, "MISSING_REQUIRED_FIELD", `${fieldPath}.newMutationCount is required.`, {
|
|
548
|
+
fieldPath: `${fieldPath}.newMutationCount`
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
if (!isNonNegativeInteger(value.newMutationCount)) {
|
|
552
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${fieldPath}.newMutationCount must be a nonnegative integer.`, {
|
|
553
|
+
fieldPath: `${fieldPath}.newMutationCount`,
|
|
554
|
+
actual: value.newMutationCount
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
return null;
|
|
558
|
+
}
|
|
559
|
+
function validateExpectedStates(statesValue, sourcePath) {
|
|
560
|
+
const contextCapsuleFailure = validateMyDevKitContextArtifactState(statesValue.contextCapsule, "expectedStates.contextCapsule", sourcePath);
|
|
561
|
+
if (contextCapsuleFailure)
|
|
562
|
+
return contextCapsuleFailure;
|
|
563
|
+
const auditFailure = validateMyDevKitContextArtifactState(statesValue.retrievalAuditRecord, "expectedStates.retrievalAuditRecord", sourcePath);
|
|
564
|
+
if (auditFailure)
|
|
565
|
+
return auditFailure;
|
|
566
|
+
const packetFailure = validateWorkflowPacketState(statesValue.workflowInstructionPacket, sourcePath);
|
|
567
|
+
if (packetFailure)
|
|
568
|
+
return packetFailure;
|
|
569
|
+
const immutabilityFailure = validateTargetImmutabilityState(statesValue.targetImmutability, sourcePath);
|
|
570
|
+
if (immutabilityFailure)
|
|
571
|
+
return immutabilityFailure;
|
|
572
|
+
return null;
|
|
573
|
+
}
|
|
574
|
+
// v0.4.4 Batch 2: additive, optional producer/readiness expectation validation. Structural
|
|
575
|
+
// classification only, mirroring the existing expectation-item validation conventions.
|
|
576
|
+
const OWNER_INCLUSION_VALUES = ["required", "allowed", "forbidden"];
|
|
577
|
+
const READINESS_KIND_VALUES = ["implementation", "test"];
|
|
578
|
+
const READINESS_DECISION_VALUES = ["not-required", "ready", "refresh-required"];
|
|
579
|
+
const CRITICALITY_VALUES = ["critical", "noncritical"];
|
|
580
|
+
const PRODUCER_READINESS_SOURCE_ARTIFACT_VALUES = ["context-capsule", "retrieval-audit-record"];
|
|
581
|
+
function requireNonEmptyExpectationId(item, itemPath, sourcePath) {
|
|
582
|
+
return requireNonEmptyString(item, "expectationId", `${itemPath}.expectationId`, sourcePath);
|
|
583
|
+
}
|
|
584
|
+
function validateOwnerExpectation(itemValue, itemPath, sourcePath) {
|
|
585
|
+
if (!isPlainObject(itemValue)) {
|
|
586
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath} must be an object.`, { fieldPath: itemPath });
|
|
587
|
+
}
|
|
588
|
+
const idFailure = requireNonEmptyExpectationId(itemValue, itemPath, sourcePath);
|
|
589
|
+
if (idFailure)
|
|
590
|
+
return idFailure;
|
|
591
|
+
if (!OWNER_INCLUSION_VALUES.includes(itemValue.inclusion)) {
|
|
592
|
+
return failure(sourcePath, "INVALID_LITERAL_VALUE", `${itemPath}.inclusion is not valid.`, {
|
|
593
|
+
fieldPath: `${itemPath}.inclusion`,
|
|
594
|
+
actual: itemValue.inclusion
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
if (!PRODUCER_READINESS_SOURCE_ARTIFACT_VALUES.includes(itemValue.sourceArtifact)) {
|
|
598
|
+
return failure(sourcePath, "INVALID_LITERAL_VALUE", `${itemPath}.sourceArtifact is not valid.`, {
|
|
599
|
+
fieldPath: `${itemPath}.sourceArtifact`,
|
|
600
|
+
actual: itemValue.sourceArtifact
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
const ownerIdFailure = requireNonEmptyString(itemValue, "ownerId", `${itemPath}.ownerId`, sourcePath);
|
|
604
|
+
if (ownerIdFailure)
|
|
605
|
+
return ownerIdFailure;
|
|
606
|
+
if (itemValue.notes === undefined || !isStringArray(itemValue.notes)) {
|
|
607
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath}.notes must be an array of strings.`, {
|
|
608
|
+
fieldPath: `${itemPath}.notes`
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
return null;
|
|
612
|
+
}
|
|
613
|
+
function validateAllocationExpectation(itemValue, itemPath, sourcePath) {
|
|
614
|
+
if (!isPlainObject(itemValue)) {
|
|
615
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath} must be an object.`, { fieldPath: itemPath });
|
|
616
|
+
}
|
|
617
|
+
const idFailure = requireNonEmptyExpectationId(itemValue, itemPath, sourcePath);
|
|
618
|
+
if (idFailure)
|
|
619
|
+
return idFailure;
|
|
620
|
+
const groupIdFailure = requireNonEmptyString(itemValue, "groupId", `${itemPath}.groupId`, sourcePath);
|
|
621
|
+
if (groupIdFailure)
|
|
622
|
+
return groupIdFailure;
|
|
623
|
+
if (itemValue.expectedCapacity !== undefined && itemValue.expectedCapacity !== null && !isNonNegativeInteger(itemValue.expectedCapacity)) {
|
|
624
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath}.expectedCapacity must be a nonnegative integer or null.`, {
|
|
625
|
+
fieldPath: `${itemPath}.expectedCapacity`
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
if (itemValue.expectedUsedReservation !== undefined &&
|
|
629
|
+
itemValue.expectedUsedReservation !== null &&
|
|
630
|
+
!isNonNegativeInteger(itemValue.expectedUsedReservation)) {
|
|
631
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath}.expectedUsedReservation must be a nonnegative integer or null.`, {
|
|
632
|
+
fieldPath: `${itemPath}.expectedUsedReservation`
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
if (itemValue.expectedRequiredEvidenceIds !== undefined && !isStringArray(itemValue.expectedRequiredEvidenceIds)) {
|
|
636
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath}.expectedRequiredEvidenceIds must be an array of strings.`, {
|
|
637
|
+
fieldPath: `${itemPath}.expectedRequiredEvidenceIds`
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
if (itemValue.expectedOmitted !== undefined && typeof itemValue.expectedOmitted !== "boolean") {
|
|
641
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath}.expectedOmitted must be a boolean.`, {
|
|
642
|
+
fieldPath: `${itemPath}.expectedOmitted`
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
if (itemValue.notes === undefined || !isStringArray(itemValue.notes)) {
|
|
646
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath}.notes must be an array of strings.`, {
|
|
647
|
+
fieldPath: `${itemPath}.notes`
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
return null;
|
|
651
|
+
}
|
|
652
|
+
function validateReadinessExpectation(itemValue, itemPath, sourcePath) {
|
|
653
|
+
if (!isPlainObject(itemValue)) {
|
|
654
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath} must be an object.`, { fieldPath: itemPath });
|
|
655
|
+
}
|
|
656
|
+
const idFailure = requireNonEmptyExpectationId(itemValue, itemPath, sourcePath);
|
|
657
|
+
if (idFailure)
|
|
658
|
+
return idFailure;
|
|
659
|
+
if (!READINESS_KIND_VALUES.includes(itemValue.kind)) {
|
|
660
|
+
return failure(sourcePath, "INVALID_LITERAL_VALUE", `${itemPath}.kind is not valid.`, {
|
|
661
|
+
fieldPath: `${itemPath}.kind`,
|
|
662
|
+
actual: itemValue.kind
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
if (itemValue.allowedDecisions !== undefined) {
|
|
666
|
+
if (!isStringArray(itemValue.allowedDecisions) || itemValue.allowedDecisions.some((d) => !READINESS_DECISION_VALUES.includes(d))) {
|
|
667
|
+
return failure(sourcePath, "INVALID_LITERAL_VALUE", `${itemPath}.allowedDecisions contains an invalid decision value.`, {
|
|
668
|
+
fieldPath: `${itemPath}.allowedDecisions`
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
if (itemValue.expectedClassification !== undefined && typeof itemValue.expectedClassification !== "string") {
|
|
673
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath}.expectedClassification must be a string.`, {
|
|
674
|
+
fieldPath: `${itemPath}.expectedClassification`
|
|
675
|
+
});
|
|
676
|
+
}
|
|
677
|
+
if (itemValue.expectedIssueCodes !== undefined && !isStringArray(itemValue.expectedIssueCodes)) {
|
|
678
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath}.expectedIssueCodes must be an array of strings.`, {
|
|
679
|
+
fieldPath: `${itemPath}.expectedIssueCodes`
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
if (itemValue.expectedPrimaryIssueCode !== undefined && typeof itemValue.expectedPrimaryIssueCode !== "string") {
|
|
683
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath}.expectedPrimaryIssueCode must be a string.`, {
|
|
684
|
+
fieldPath: `${itemPath}.expectedPrimaryIssueCode`
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
if (itemValue.notApplicable !== undefined && typeof itemValue.notApplicable !== "boolean") {
|
|
688
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath}.notApplicable must be a boolean.`, {
|
|
689
|
+
fieldPath: `${itemPath}.notApplicable`
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
if (itemValue.notes === undefined || !isStringArray(itemValue.notes)) {
|
|
693
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath}.notes must be an array of strings.`, {
|
|
694
|
+
fieldPath: `${itemPath}.notes`
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
return null;
|
|
698
|
+
}
|
|
699
|
+
function validateCriticalityExpectation(itemValue, itemPath, sourcePath) {
|
|
700
|
+
if (!isPlainObject(itemValue)) {
|
|
701
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath} must be an object.`, { fieldPath: itemPath });
|
|
702
|
+
}
|
|
703
|
+
const idFailure = requireNonEmptyExpectationId(itemValue, itemPath, sourcePath);
|
|
704
|
+
if (idFailure)
|
|
705
|
+
return idFailure;
|
|
706
|
+
const responsibilityIdFailure = requireNonEmptyString(itemValue, "responsibilityId", `${itemPath}.responsibilityId`, sourcePath);
|
|
707
|
+
if (responsibilityIdFailure)
|
|
708
|
+
return responsibilityIdFailure;
|
|
709
|
+
if (!CRITICALITY_VALUES.includes(itemValue.expectedCriticality)) {
|
|
710
|
+
return failure(sourcePath, "INVALID_LITERAL_VALUE", `${itemPath}.expectedCriticality is not valid.`, {
|
|
711
|
+
fieldPath: `${itemPath}.expectedCriticality`,
|
|
712
|
+
actual: itemValue.expectedCriticality
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
if (typeof itemValue.applicable !== "boolean") {
|
|
716
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath}.applicable must be a boolean.`, {
|
|
717
|
+
fieldPath: `${itemPath}.applicable`
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
if (typeof itemValue.requiresFullMapping !== "boolean") {
|
|
721
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath}.requiresFullMapping must be a boolean.`, {
|
|
722
|
+
fieldPath: `${itemPath}.requiresFullMapping`
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
if (itemValue.notes === undefined || !isStringArray(itemValue.notes)) {
|
|
726
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${itemPath}.notes must be an array of strings.`, {
|
|
727
|
+
fieldPath: `${itemPath}.notes`
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
return null;
|
|
731
|
+
}
|
|
732
|
+
function validateProducerReadinessExpectations(value, sourcePath) {
|
|
733
|
+
const fieldPath = "producerReadinessExpectations";
|
|
734
|
+
if (!isPlainObject(value)) {
|
|
735
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${fieldPath} must be an object.`, { fieldPath });
|
|
736
|
+
}
|
|
737
|
+
const lists = [
|
|
738
|
+
["ownerExpectations", value.ownerExpectations, validateOwnerExpectation],
|
|
739
|
+
["allocationExpectations", value.allocationExpectations, validateAllocationExpectation],
|
|
740
|
+
["readinessExpectations", value.readinessExpectations, validateReadinessExpectation],
|
|
741
|
+
["criticalityExpectations", value.criticalityExpectations, validateCriticalityExpectation]
|
|
742
|
+
];
|
|
743
|
+
const seenIds = new Set();
|
|
744
|
+
for (const [key, listValue, validateItem] of lists) {
|
|
745
|
+
if (listValue === undefined)
|
|
746
|
+
continue;
|
|
747
|
+
if (!Array.isArray(listValue)) {
|
|
748
|
+
return failure(sourcePath, "INVALID_FIELD_TYPE", `${fieldPath}.${key} must be an array.`, {
|
|
749
|
+
fieldPath: `${fieldPath}.${key}`
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
for (let index = 0; index < listValue.length; index += 1) {
|
|
753
|
+
const itemPath = `${fieldPath}.${key}[${index}]`;
|
|
754
|
+
const itemFailure = validateItem(listValue[index], itemPath, sourcePath);
|
|
755
|
+
if (itemFailure)
|
|
756
|
+
return itemFailure;
|
|
757
|
+
const id = listValue[index].expectationId;
|
|
758
|
+
if (seenIds.has(id)) {
|
|
759
|
+
return failure(sourcePath, "DUPLICATE_PRODUCER_READINESS_EXPECTATION_ID", `${itemPath}.expectationId "${id}" is duplicated.`, {
|
|
760
|
+
fieldPath: `${itemPath}.expectationId`,
|
|
761
|
+
actual: id
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
seenIds.add(id);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
return null;
|
|
768
|
+
}
|