@vaudience/aigentflow-flow-validator 0.24.0 → 0.26.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/PARITY.md +60 -0
- package/dist/cli.js +215 -11
- package/dist/index.cjs +213 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +213 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -457,6 +457,7 @@ var aigentflow_spec_default = {
|
|
|
457
457
|
"ai",
|
|
458
458
|
"aiv",
|
|
459
459
|
"async",
|
|
460
|
+
"atlas",
|
|
460
461
|
"browser",
|
|
461
462
|
"chart",
|
|
462
463
|
"db",
|
|
@@ -986,6 +987,85 @@ var aigentflow_spec_default = {
|
|
|
986
987
|
"utils/parse-date"
|
|
987
988
|
]
|
|
988
989
|
},
|
|
990
|
+
atlasExecutor: {
|
|
991
|
+
scheme: "atlas",
|
|
992
|
+
providerAgent: "agent",
|
|
993
|
+
providerCapability: "capability",
|
|
994
|
+
agentResource: "run",
|
|
995
|
+
capabilityRefPattern: "^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$",
|
|
996
|
+
operationUnknown: {
|
|
997
|
+
code: "atlas_operation_unknown",
|
|
998
|
+
messageFormat: "step %s uses %s, which is not an Atlas operation. The providers are agent (resource run) and capability (resource: a capability reference).",
|
|
999
|
+
suggestion: "Use atlas://agent/run or atlas://capability/<capability-ref>."
|
|
1000
|
+
},
|
|
1001
|
+
agentMissing: {
|
|
1002
|
+
code: "atlas_agent_missing",
|
|
1003
|
+
messageFormat: "step %s runs an Atlas agent but query.agent is missing, empty or not a string.",
|
|
1004
|
+
suggestion: "Set query.agent to the agent to run, written out as a literal such as @acme/reporter."
|
|
1005
|
+
},
|
|
1006
|
+
agentNotLiteral: {
|
|
1007
|
+
code: "atlas_agent_not_literal",
|
|
1008
|
+
messageFormat: "step %s computes query.agent from a template. The agent must be a fixed literal, never derived from input.",
|
|
1009
|
+
suggestion: "Write the agent out as a literal such as @acme/reporter. Data may go into the prompt or the inputs instead."
|
|
1010
|
+
},
|
|
1011
|
+
capabilitiesNotLiteral: {
|
|
1012
|
+
code: "atlas_capabilities_not_literal",
|
|
1013
|
+
messageFormat: "step %s computes an entry of query.capabilities from a template. Capabilities must be fixed literals, never derived from input.",
|
|
1014
|
+
suggestion: "Write each capability out as a literal. Data may go into the prompt or the inputs instead."
|
|
1015
|
+
},
|
|
1016
|
+
promptMissing: {
|
|
1017
|
+
code: "atlas_prompt_missing",
|
|
1018
|
+
messageFormat: "step %s runs an Atlas agent with neither query.prompt nor query.prompt_template.",
|
|
1019
|
+
suggestion: "Set exactly one of query.prompt or query.prompt_template."
|
|
1020
|
+
},
|
|
1021
|
+
promptBoth: {
|
|
1022
|
+
code: "atlas_prompt_both",
|
|
1023
|
+
messageFormat: "step %s sets both query.prompt and query.prompt_template.",
|
|
1024
|
+
suggestion: "Keep exactly one of query.prompt or query.prompt_template."
|
|
1025
|
+
},
|
|
1026
|
+
capabilityRefInvalid: {
|
|
1027
|
+
code: "atlas_capability_ref_invalid",
|
|
1028
|
+
messageFormat: "step %s uses atlas://capability/%s, which is not a valid capability reference.",
|
|
1029
|
+
suggestion: "A capability reference starts with a letter or digit and continues with letters, digits, _ and - up to 128 characters in all."
|
|
1030
|
+
},
|
|
1031
|
+
modelNotLiteral: {
|
|
1032
|
+
code: "atlas_model_not_literal",
|
|
1033
|
+
messageFormat: "step %s computes a value of query.model from a template. The provider, model and reasoning_effort must be fixed literals, never derived from input.",
|
|
1034
|
+
suggestion: "Write the model choice out as literals. Data may go into the prompt or the inputs instead."
|
|
1035
|
+
},
|
|
1036
|
+
paramRefused: {
|
|
1037
|
+
code: "atlas_param_refused",
|
|
1038
|
+
messageFormat: "step %s sets %s under query. Atlas decides these itself, so a step may not set them.",
|
|
1039
|
+
suggestion: "Remove these keys from the query.",
|
|
1040
|
+
agentKeys: [
|
|
1041
|
+
"api_key",
|
|
1042
|
+
"attribution",
|
|
1043
|
+
"base_url",
|
|
1044
|
+
"host",
|
|
1045
|
+
"idempotency_key",
|
|
1046
|
+
"org_id",
|
|
1047
|
+
"person",
|
|
1048
|
+
"untrusted_input",
|
|
1049
|
+
"untrusted_input_override",
|
|
1050
|
+
"url",
|
|
1051
|
+
"user_id"
|
|
1052
|
+
],
|
|
1053
|
+
capabilityKeys: [
|
|
1054
|
+
"attribution",
|
|
1055
|
+
"idempotency_key",
|
|
1056
|
+
"untrusted_input",
|
|
1057
|
+
"untrusted_input_override"
|
|
1058
|
+
]
|
|
1059
|
+
}
|
|
1060
|
+
},
|
|
1061
|
+
reservedInputNames: {
|
|
1062
|
+
prefix: "__",
|
|
1063
|
+
code: "reserved_input_name",
|
|
1064
|
+
messageFormat: "the input %s starts with two underscores. That namespace belongs to the platform (the acting person, the credential manifest, the untrusted-input marker): a flow cannot declare an input there, and a value or default written under such a name is never delivered.",
|
|
1065
|
+
suggestion: 'Rename the input so it does not start with "__".',
|
|
1066
|
+
queryFieldFormat: "query.%s",
|
|
1067
|
+
schemaFieldFormat: "input_schema.fields.%s"
|
|
1068
|
+
},
|
|
989
1069
|
flowDataReservedKeys: {
|
|
990
1070
|
code: "flow_data_key_reserved",
|
|
991
1071
|
fieldFormat: "data.%s",
|
|
@@ -2028,6 +2108,37 @@ var FUNCTION_OPERATIONS = {
|
|
|
2028
2108
|
operations: new Set(aigentflow_spec_default.functionOperations.operations),
|
|
2029
2109
|
sorted: aigentflow_spec_default.functionOperations.operations
|
|
2030
2110
|
};
|
|
2111
|
+
var atlas = aigentflow_spec_default.atlasExecutor;
|
|
2112
|
+
var ATLAS_EXECUTOR = {
|
|
2113
|
+
scheme: atlas.scheme,
|
|
2114
|
+
providerAgent: atlas.providerAgent,
|
|
2115
|
+
providerCapability: atlas.providerCapability,
|
|
2116
|
+
agentResource: atlas.agentResource,
|
|
2117
|
+
capabilityRefPattern: new RegExp(atlas.capabilityRefPattern),
|
|
2118
|
+
operationUnknown: atlas.operationUnknown,
|
|
2119
|
+
agentMissing: atlas.agentMissing,
|
|
2120
|
+
agentNotLiteral: atlas.agentNotLiteral,
|
|
2121
|
+
capabilitiesNotLiteral: atlas.capabilitiesNotLiteral,
|
|
2122
|
+
promptMissing: atlas.promptMissing,
|
|
2123
|
+
promptBoth: atlas.promptBoth,
|
|
2124
|
+
capabilityRefInvalid: atlas.capabilityRefInvalid,
|
|
2125
|
+
modelNotLiteral: atlas.modelNotLiteral,
|
|
2126
|
+
paramRefused: {
|
|
2127
|
+
code: atlas.paramRefused.code,
|
|
2128
|
+
messageFormat: atlas.paramRefused.messageFormat,
|
|
2129
|
+
suggestion: atlas.paramRefused.suggestion,
|
|
2130
|
+
agentKeys: atlas.paramRefused.agentKeys,
|
|
2131
|
+
capabilityKeys: atlas.paramRefused.capabilityKeys
|
|
2132
|
+
}
|
|
2133
|
+
};
|
|
2134
|
+
var RESERVED_INPUT_NAMES = {
|
|
2135
|
+
prefix: aigentflow_spec_default.reservedInputNames.prefix,
|
|
2136
|
+
code: aigentflow_spec_default.reservedInputNames.code,
|
|
2137
|
+
messageFormat: aigentflow_spec_default.reservedInputNames.messageFormat,
|
|
2138
|
+
suggestion: aigentflow_spec_default.reservedInputNames.suggestion,
|
|
2139
|
+
queryFieldFormat: aigentflow_spec_default.reservedInputNames.queryFieldFormat,
|
|
2140
|
+
schemaFieldFormat: aigentflow_spec_default.reservedInputNames.schemaFieldFormat
|
|
2141
|
+
};
|
|
2031
2142
|
|
|
2032
2143
|
// src/validators/executors.ts
|
|
2033
2144
|
var SCHEME_SEPARATOR = "://";
|
|
@@ -2091,6 +2202,63 @@ function checkExecutor(executor, field, stepID, issues) {
|
|
|
2091
2202
|
}
|
|
2092
2203
|
checkFunctionOperation(executor, field, stepID, templated, issues);
|
|
2093
2204
|
}
|
|
2205
|
+
function checkAtlasStep(executor, query, stepField, stepID, issues) {
|
|
2206
|
+
if (executor.includes(TEMPLATE_ACTION_OPEN)) return;
|
|
2207
|
+
const prefix = `${ATLAS_EXECUTOR.scheme}://`;
|
|
2208
|
+
if (!executor.startsWith(prefix)) return;
|
|
2209
|
+
const rest = executor.slice(prefix.length);
|
|
2210
|
+
const slash = rest.indexOf("/");
|
|
2211
|
+
const provider = slash < 0 ? rest : rest.slice(0, slash);
|
|
2212
|
+
const resource = slash < 0 ? "" : rest.slice(slash + 1);
|
|
2213
|
+
const quoted = JSON.stringify(stepID);
|
|
2214
|
+
const report = (rule, ...args) => {
|
|
2215
|
+
let message = rule.messageFormat.replace("%s", () => quoted);
|
|
2216
|
+
for (const a of args) message = message.replace("%s", () => a);
|
|
2217
|
+
issues.error({
|
|
2218
|
+
field: stepField,
|
|
2219
|
+
message,
|
|
2220
|
+
code: rule.code,
|
|
2221
|
+
stepId: stepID,
|
|
2222
|
+
suggestion: rule.suggestion
|
|
2223
|
+
});
|
|
2224
|
+
};
|
|
2225
|
+
const q2 = isRecord(query) ? query : {};
|
|
2226
|
+
let refusedKeys = ATLAS_EXECUTOR.paramRefused.capabilityKeys;
|
|
2227
|
+
if (provider === ATLAS_EXECUTOR.providerCapability) {
|
|
2228
|
+
if (!ATLAS_EXECUTOR.capabilityRefPattern.test(resource)) {
|
|
2229
|
+
report(ATLAS_EXECUTOR.capabilityRefInvalid, resource);
|
|
2230
|
+
}
|
|
2231
|
+
} else if (provider === ATLAS_EXECUTOR.providerAgent && resource === ATLAS_EXECUTOR.agentResource) {
|
|
2232
|
+
refusedKeys = ATLAS_EXECUTOR.paramRefused.agentKeys;
|
|
2233
|
+
const agent = q2.agent;
|
|
2234
|
+
if (typeof agent !== "string" || agent.trim() === "") {
|
|
2235
|
+
report(ATLAS_EXECUTOR.agentMissing);
|
|
2236
|
+
} else if (agent.includes(TEMPLATE_ACTION_OPEN)) {
|
|
2237
|
+
report(ATLAS_EXECUTOR.agentNotLiteral);
|
|
2238
|
+
}
|
|
2239
|
+
const hasPrompt = atlasTextPresent(q2.prompt);
|
|
2240
|
+
const hasTemplate = atlasTextPresent(q2.prompt_template);
|
|
2241
|
+
if (!hasPrompt && !hasTemplate) report(ATLAS_EXECUTOR.promptMissing);
|
|
2242
|
+
else if (hasPrompt && hasTemplate) report(ATLAS_EXECUTOR.promptBoth);
|
|
2243
|
+
if (anyTemplate(q2.model)) report(ATLAS_EXECUTOR.modelNotLiteral);
|
|
2244
|
+
} else {
|
|
2245
|
+
report(ATLAS_EXECUTOR.operationUnknown, executor);
|
|
2246
|
+
return;
|
|
2247
|
+
}
|
|
2248
|
+
if (anyTemplate(q2.capabilities)) report(ATLAS_EXECUTOR.capabilitiesNotLiteral);
|
|
2249
|
+
const refused = refusedKeys.filter((key) => Object.prototype.hasOwnProperty.call(q2, key)).sort();
|
|
2250
|
+
if (refused.length > 0) report(ATLAS_EXECUTOR.paramRefused, refused.join(", "));
|
|
2251
|
+
}
|
|
2252
|
+
function anyTemplate(v) {
|
|
2253
|
+
if (typeof v === "string") return v.includes(TEMPLATE_ACTION_OPEN);
|
|
2254
|
+
if (Array.isArray(v)) return v.some(anyTemplate);
|
|
2255
|
+
if (isRecord(v)) return Object.values(v).some(anyTemplate);
|
|
2256
|
+
return false;
|
|
2257
|
+
}
|
|
2258
|
+
function atlasTextPresent(v) {
|
|
2259
|
+
if (v === void 0 || v === null) return false;
|
|
2260
|
+
return typeof v !== "string" || v.trim() !== "";
|
|
2261
|
+
}
|
|
2094
2262
|
function checkFunctionOperation(executor, field, stepID, templated, issues) {
|
|
2095
2263
|
if (templated) return;
|
|
2096
2264
|
const m = EXECUTOR_URL_PATTERN.exec(executor);
|
|
@@ -2115,6 +2283,7 @@ function validateExecutors(flow, issues) {
|
|
|
2115
2283
|
const executor = issues.stringOf(step, "executor", `steps.${stepID}`);
|
|
2116
2284
|
if (executor !== null && executor !== "") {
|
|
2117
2285
|
checkExecutor(executor, `steps.${stepID}.executor`, stepID, issues);
|
|
2286
|
+
checkAtlasStep(executor, step.query, `steps.${stepID}`, stepID, issues);
|
|
2118
2287
|
}
|
|
2119
2288
|
const loop = step.loop;
|
|
2120
2289
|
if (isRecord(loop) && Array.isArray(loop.steps)) {
|
|
@@ -2131,6 +2300,7 @@ function validateExecutors(flow, issues) {
|
|
|
2131
2300
|
`${stepID}.${subID}`,
|
|
2132
2301
|
issues
|
|
2133
2302
|
);
|
|
2303
|
+
checkAtlasStep(subExecutor, subStep.query, subPath, `${stepID}.${subID}`, issues);
|
|
2134
2304
|
}
|
|
2135
2305
|
});
|
|
2136
2306
|
}
|
|
@@ -3773,6 +3943,37 @@ function validateInputSchema(flow, issues) {
|
|
|
3773
3943
|
validateSchemaDefinition(flow.input_schema, "input_schema", issues);
|
|
3774
3944
|
}
|
|
3775
3945
|
|
|
3946
|
+
// src/validators/reservedInputs.ts
|
|
3947
|
+
function formatField(format, name) {
|
|
3948
|
+
return format.replace("%s", () => name);
|
|
3949
|
+
}
|
|
3950
|
+
function validateReservedInputNames(flow, issues) {
|
|
3951
|
+
const rule = RESERVED_INPUT_NAMES;
|
|
3952
|
+
const report = (name, fieldFormat) => {
|
|
3953
|
+
issues.error({
|
|
3954
|
+
field: formatField(fieldFormat, name),
|
|
3955
|
+
message: rule.messageFormat.replace("%s", () => JSON.stringify(name)),
|
|
3956
|
+
code: rule.code,
|
|
3957
|
+
suggestion: rule.suggestion
|
|
3958
|
+
});
|
|
3959
|
+
};
|
|
3960
|
+
const query = flow.query;
|
|
3961
|
+
if (isRecord(query)) {
|
|
3962
|
+
for (const name of Object.keys(query).sort()) {
|
|
3963
|
+
if (name.startsWith(rule.prefix)) report(name, rule.queryFieldFormat);
|
|
3964
|
+
}
|
|
3965
|
+
}
|
|
3966
|
+
const schema = flow.input_schema;
|
|
3967
|
+
const fields = isRecord(schema) ? schema.fields : void 0;
|
|
3968
|
+
if (!Array.isArray(fields)) return;
|
|
3969
|
+
for (const f of fields) {
|
|
3970
|
+
if (!isRecord(f)) continue;
|
|
3971
|
+
if (typeof f.name === "string" && f.name.startsWith(rule.prefix)) {
|
|
3972
|
+
report(f.name, rule.schemaFieldFormat);
|
|
3973
|
+
}
|
|
3974
|
+
}
|
|
3975
|
+
}
|
|
3976
|
+
|
|
3776
3977
|
// src/validators/outputSchema.ts
|
|
3777
3978
|
function validateOutputSchemas(flow, issues) {
|
|
3778
3979
|
const steps = flow.steps;
|
|
@@ -4887,7 +5088,7 @@ var CODE2 = "server_owned_query_key";
|
|
|
4887
5088
|
var KEY_QUERY = "query";
|
|
4888
5089
|
var KEY_ID = "id";
|
|
4889
5090
|
var SERVER_OWNED = new Set(SERVER_OWNED_QUERY_KEYS.keys);
|
|
4890
|
-
function
|
|
5091
|
+
function formatField2(format, ...args) {
|
|
4891
5092
|
let i = 0;
|
|
4892
5093
|
return format.replace(/%s/g, () => args[i++] ?? "");
|
|
4893
5094
|
}
|
|
@@ -4905,7 +5106,7 @@ function validateServerOwnedQueryKeys(flow, issues) {
|
|
|
4905
5106
|
issues,
|
|
4906
5107
|
stepID,
|
|
4907
5108
|
key,
|
|
4908
|
-
|
|
5109
|
+
formatField2(SERVER_OWNED_QUERY_KEYS.stepFieldFormat, stepID, key)
|
|
4909
5110
|
);
|
|
4910
5111
|
}
|
|
4911
5112
|
}
|
|
@@ -4919,7 +5120,7 @@ function validateServerOwnedQueryKeys(flow, issues) {
|
|
|
4919
5120
|
issues,
|
|
4920
5121
|
stepID,
|
|
4921
5122
|
key,
|
|
4922
|
-
|
|
5123
|
+
formatField2(SERVER_OWNED_QUERY_KEYS.loopStepFieldFormat, stepID, subID, key)
|
|
4923
5124
|
);
|
|
4924
5125
|
}
|
|
4925
5126
|
}
|
|
@@ -5186,7 +5387,7 @@ function own(m, key) {
|
|
|
5186
5387
|
if (!isRecord(m) || !Object.prototype.hasOwnProperty.call(m, key)) return void 0;
|
|
5187
5388
|
return m[key];
|
|
5188
5389
|
}
|
|
5189
|
-
function
|
|
5390
|
+
function formatField3(format, ...args) {
|
|
5190
5391
|
let i = 0;
|
|
5191
5392
|
return format.replace(/%s/g, () => args[i++] ?? "");
|
|
5192
5393
|
}
|
|
@@ -5208,14 +5409,14 @@ function credentialEndpointSteps(flow, issues) {
|
|
|
5208
5409
|
out.push({
|
|
5209
5410
|
executor: issues.stringOf(step, KEY_EXECUTOR, `steps.${stepId}`) ?? "",
|
|
5210
5411
|
query: own(step, KEY_QUERY2),
|
|
5211
|
-
field: (key) =>
|
|
5412
|
+
field: (key) => formatField3(CREDENTIAL_ENDPOINT_PAIRING.stepFieldFormat, stepId, key)
|
|
5212
5413
|
});
|
|
5213
5414
|
for (const sub of loopSubStepsOfStep(stepId, step)) {
|
|
5214
5415
|
const subId = issues.stringOf(sub.raw, KEY_ID2, sub.basePath) ?? "";
|
|
5215
5416
|
out.push({
|
|
5216
5417
|
executor: issues.stringOf(sub.raw, KEY_EXECUTOR, sub.basePath) ?? "",
|
|
5217
5418
|
query: own(sub.raw, KEY_QUERY2),
|
|
5218
|
-
field: (key) =>
|
|
5419
|
+
field: (key) => formatField3(CREDENTIAL_ENDPOINT_PAIRING.loopStepFieldFormat, stepId, subId, key)
|
|
5219
5420
|
});
|
|
5220
5421
|
}
|
|
5221
5422
|
}
|
|
@@ -5279,7 +5480,7 @@ function validateAI(flow, steps, issues) {
|
|
|
5279
5480
|
if ((stepsUsing.get(provider) ?? 0) > 0 && (stepsWithoutOwnKey.get(provider) ?? 0) === 0) {
|
|
5280
5481
|
continue;
|
|
5281
5482
|
}
|
|
5282
|
-
warnStoredShape(issues,
|
|
5483
|
+
warnStoredShape(issues, formatField3(CREDENTIAL_ENDPOINT_PAIRING.executorConfigBaseUrlFieldFormat, provider), provider);
|
|
5283
5484
|
}
|
|
5284
5485
|
}
|
|
5285
5486
|
function warnStoredShape(issues, field, provider) {
|
|
@@ -5326,7 +5527,7 @@ function familySecret(flow, family, step, issues) {
|
|
|
5326
5527
|
if (apiKey !== "" && listHas(family.secretParams, family.configApiKeyParam)) {
|
|
5327
5528
|
return {
|
|
5328
5529
|
envName: serverEnvRef(family, apiKey),
|
|
5329
|
-
field:
|
|
5530
|
+
field: formatField3(
|
|
5330
5531
|
CREDENTIAL_ENDPOINT_PAIRING.executorConfigKeyFieldFormat,
|
|
5331
5532
|
configKey,
|
|
5332
5533
|
CREDENTIAL_ENDPOINT_PAIRING.executorConfigApiKeyField
|
|
@@ -5339,7 +5540,7 @@ function familySecret(flow, family, step, issues) {
|
|
|
5339
5540
|
if (v !== null) {
|
|
5340
5541
|
return {
|
|
5341
5542
|
envName: serverEnvRef(family, v),
|
|
5342
|
-
field:
|
|
5543
|
+
field: formatField3(CREDENTIAL_ENDPOINT_PAIRING.executorConfigExtraFieldFormat, configKey, key)
|
|
5343
5544
|
};
|
|
5344
5545
|
}
|
|
5345
5546
|
}
|
|
@@ -5365,13 +5566,13 @@ function familyAuthorEndpoint(flow, family, step, issues) {
|
|
|
5365
5566
|
if (inst === null) continue;
|
|
5366
5567
|
const baseUrl = configStringField(inst, configKey, CREDENTIAL_ENDPOINT_PAIRING.executorConfigBaseUrlField, issues);
|
|
5367
5568
|
if (baseUrl !== "" && listHas(family.endpointParams, family.configBaseUrlParam)) {
|
|
5368
|
-
return decide(baseUrl,
|
|
5569
|
+
return decide(baseUrl, formatField3(CREDENTIAL_ENDPOINT_PAIRING.executorConfigBaseUrlFieldFormat, configKey));
|
|
5369
5570
|
}
|
|
5370
5571
|
const extra = own(inst, EXECUTOR_CONFIG_ENV_SCOPES.extraKey);
|
|
5371
5572
|
for (const key of family.endpointParams) {
|
|
5372
5573
|
const v = nonEmptyEndpoint(extra, key);
|
|
5373
5574
|
if (v !== null)
|
|
5374
|
-
return decide(v,
|
|
5575
|
+
return decide(v, formatField3(CREDENTIAL_ENDPOINT_PAIRING.executorConfigExtraFieldFormat, configKey, key));
|
|
5375
5576
|
}
|
|
5376
5577
|
}
|
|
5377
5578
|
return null;
|
|
@@ -7082,6 +7283,7 @@ function validateParsed(flow, opts, sources) {
|
|
|
7082
7283
|
validateOrchestratorCampaign(f, issues, opts);
|
|
7083
7284
|
validateCredentialBindings(f, issues);
|
|
7084
7285
|
validateInputSchema(f, issues);
|
|
7286
|
+
validateReservedInputNames(f, issues);
|
|
7085
7287
|
validateOutputSchemas(f, issues);
|
|
7086
7288
|
validateQualityGates(f, issues);
|
|
7087
7289
|
validateProcessingOperations(f, issues);
|