@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 CHANGED
@@ -6,6 +6,66 @@ discipline for keeping the two in sync.
6
6
 
7
7
  **Tracks AIgentFlow flow schema: `v2.831.0`** (`SPEC_VERSION` in [`src/spec/aigentflow-spec.json`](./src/spec/aigentflow-spec.json)), which adds the rule `unknown_function_operation` and a clearer `unknown_executor_scheme` message (package 0.23.0, below). Earlier: the rule `flow_data_key_reserved` (package 0.22.0). Earlier: the `here` executor scheme, the `strict_templates` flow key and the rule `template_default_piped` (package 0.21.0). Earlier: the warning `compliance_residency_unenforced` (package 0.20.0). `orchestrator.region` / `orchestrator.enforce_region` (package 0.19.0). Earlier: the AigentChat executor was removed (package 0.18.0). Earlier additions: the `examples:` block (package 0.17.0), `server_owned_query_key` (package 0.15.1) from the AIgentFlow release after v2.790.0, `credential_endpoint_unpaired` (package 0.15.2) from AIgentFlow v2.793.0 and the release after it, and `display_name_too_long` (package 0.15.3) from AIgentFlow v2.802.0.
8
8
 
9
+ > package 0.26.0 — **three new rules, and the atlas rules brought in line with the reference.**
10
+ > `reserved_input_name` (error): an input the flow declares under the top-level `query:` map, or as an
11
+ > `input_schema` field name, that starts with two underscores. That namespace belongs to the platform
12
+ > (the acting person, the credential manifest, the untrusted-input marker), and a value or default
13
+ > written under such a name is never delivered. Every name the platform reserves today starts with
14
+ > `__`; one leading underscore (`_private`) or an inner `__` (`a__b`) is an ordinary name. Fields:
15
+ > `query.<name>` (names sorted) and `input_schema.fields.<name>` (file order), no step id. The schema
16
+ > field is addressed by **name**, not by index like this port's other `input_schema` findings, because
17
+ > the reference reports it that way and a host that merges several verdicts drops a finding only when
18
+ > code and field both match. `atlas_model_not_literal` (error): an `atlas://agent/run` step whose
19
+ > `query.model` holds a string containing `{{` anywhere (provider, model, reasoning_effort, or any
20
+ > nested value). The model choice is fixed in the flow, never computed from input.
21
+ > `atlas_param_refused` (error): **one** finding per atlas step listing, sorted, the `query` keys the
22
+ > platform owns. An agent run refuses `api_key`, `attribution`, `base_url`, `host`, `idempotency_key`,
23
+ > `org_id`, `person`, `untrusted_input`, `untrusted_input_override`, `url`, `user_id`; a capability step
24
+ > refuses only `attribution`, `idempotency_key`, `untrusted_input`, `untrusted_input_override` (its
25
+ > query is the tool's own arguments, so a `url` is legitimate there). The key sets live in the spec
26
+ > block `atlasExecutor.paramRefused`; the reserved-name prefix in the new top-level block
27
+ > `reservedInputNames`.
28
+ >
29
+ > _Alignments (the reference is authoritative; the old behaviour was looser)._ `agent`, `prompt` and
30
+ > `prompt_template` are present only when they are non-empty strings **after trimming whitespace**: an
31
+ > `agent` that is not a string (`42`) is missing, `prompt: " "` is absent, and `prompt: ""` next to a
32
+ > `prompt_template` is **not** `atlas_prompt_both`. The `{{` check on `capabilities` is deep (any
33
+ > string entry or nested string) and applies to every `atlas://` step with a valid operation. The
34
+ > capability reference pattern is now `^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$` (a dot or colon is refused).
35
+ > An `atlas://` URL that the shared executor-URL shape refuses is no longer skipped by the atlas
36
+ > rules: it is split at the first slash after `atlas://` and judged (a reference with a dot is
37
+ > `atlas_capability_ref_invalid`, `atlas://agent/run/extra` is `atlas_operation_unknown`); the shape's own
38
+ > `invalid_executor_url` finding is still reported beside it. The scheme match stays exact. The
39
+ > `atlas_agent_missing` message now ends "missing, empty or not a string". `specVersion` is unchanged
40
+ > (`2.831.0`). Modules: `validators/executors.ts`, `validators/reservedInputs.ts`. Gates: thirteen new
41
+ > shared fixtures (one invalid per code, the valid ones forbid every atlas code, `reserved_input_name`
42
+ > and `unknown_executor_scheme`), byte-identical with the Go port, and
43
+ > `test/v0260-atlas-contract.test.ts`. On the 227 bundled example flows plus the six atlas examples,
44
+ > both ports report zero new findings and agree finding for finding (0 errors, 36 warnings).
45
+
46
+ > package 0.25.0 — **the `atlas://` executor scheme and seven rules**. `atlas` becomes a known
47
+ > scheme (no `unknown_executor_scheme` warning). The URL form is `atlas://<provider>/<resource>`:
48
+ > provider `agent` has the single resource `run`, provider `capability` takes a capability reference
49
+ > as its resource. Seven new **errors**, all with the step as `field` (a loop sub-step reports its
50
+ > sub-step path and the composite `parent.child` step id):
51
+ > `atlas_operation_unknown` (any other provider, or `agent` with a resource other than `run`);
52
+ > `atlas_agent_missing` (an agent run whose `query.agent` is absent, empty or not a string);
53
+ > `atlas_agent_not_literal` (`query.agent` contains `{{`: the agent is always written out, never
54
+ > computed from input); `atlas_capabilities_not_literal` (a string entry of `query.capabilities`
55
+ > contains `{{`); `atlas_prompt_missing` and `atlas_prompt_both` (an agent run takes exactly one of
56
+ > `query.prompt` and `query.prompt_template`; an empty string counts as absent);
57
+ > `atlas_capability_ref_invalid` (the reference fails `^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$`).
58
+ > Templates in `prompt`, in `inputs` values and in a capability's `args` are fine. A templated
59
+ > executor is skipped, an unparsable URL stays `invalid_executor_url`'s, and the scheme match is
60
+ > exact (`ATLAS://` is a known scheme but gets none of these rules). The shape check runs first, so
61
+ > a reference containing a character outside letters, digits, `_`, `-` and `/` (for example a dot
62
+ > or colon) is reported as `invalid_executor_url` and never reaches the reference pattern.
63
+ > `specVersion` is unchanged (`2.831.0`). Module: `validators/executors.ts`; spec block
64
+ > `atlasExecutor`. Gates: thirteen `invalid-atlas-*` / `valid-atlas-*` fixtures (the valid ones
65
+ > forbid every atlas code and `unknown_executor_scheme`), shared byte for byte with the Go port, and
66
+ > `test/v0250-atlas-executor.test.ts`. On the 227 bundled example flows both ports report no new
67
+ > findings.
68
+
9
69
  > package 0.24.0 — **`potential_infinite_loop` fires only on a cycle with no way out**, in step
10
70
  > with the reference. It used to fire on every cycle reachable from the start step, so a deliberate
11
71
  > ask-again loop (a step that routes back until a condition sends it onward) carried a warning that
package/dist/cli.js CHANGED
@@ -463,6 +463,7 @@ var aigentflow_spec_default = {
463
463
  "ai",
464
464
  "aiv",
465
465
  "async",
466
+ "atlas",
466
467
  "browser",
467
468
  "chart",
468
469
  "db",
@@ -1006,6 +1007,87 @@ var aigentflow_spec_default = {
1006
1007
  "utils/parse-date"
1007
1008
  ]
1008
1009
  },
1010
+ atlasExecutor: {
1011
+ $comment: "atlas://<provider>/<resource>: calls into the Atlas platform. Providers are agent (the one resource is run) and capability (the resource is a capability reference). All findings are ERRORS, field = the step (loop sub-steps use the composite step id and the sub-step path). Templated executors, unparsable URLs and other schemes are skipped. A literal agent and literal capabilities keep a step from being steered by data: query.agent and every string anywhere in query.capabilities and query.model may not contain templateActionOpen, while prompt, inputs and capability args may. agent, prompt and prompt_template count as present only when they are non-empty strings after trimming whitespace. A message format takes the quoted step id first. A URL the shared executor-URL shape refuses (a dot or colon in a reference, say) is still judged here, split at the first slash after atlas://.",
1012
+ scheme: "atlas",
1013
+ providerAgent: "agent",
1014
+ providerCapability: "capability",
1015
+ agentResource: "run",
1016
+ capabilityRefPattern: "^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$",
1017
+ operationUnknown: {
1018
+ code: "atlas_operation_unknown",
1019
+ messageFormat: "step %s uses %s, which is not an Atlas operation. The providers are agent (resource run) and capability (resource: a capability reference).",
1020
+ suggestion: "Use atlas://agent/run or atlas://capability/<capability-ref>."
1021
+ },
1022
+ agentMissing: {
1023
+ code: "atlas_agent_missing",
1024
+ messageFormat: "step %s runs an Atlas agent but query.agent is missing, empty or not a string.",
1025
+ suggestion: "Set query.agent to the agent to run, written out as a literal such as @acme/reporter."
1026
+ },
1027
+ agentNotLiteral: {
1028
+ code: "atlas_agent_not_literal",
1029
+ messageFormat: "step %s computes query.agent from a template. The agent must be a fixed literal, never derived from input.",
1030
+ suggestion: "Write the agent out as a literal such as @acme/reporter. Data may go into the prompt or the inputs instead."
1031
+ },
1032
+ capabilitiesNotLiteral: {
1033
+ code: "atlas_capabilities_not_literal",
1034
+ messageFormat: "step %s computes an entry of query.capabilities from a template. Capabilities must be fixed literals, never derived from input.",
1035
+ suggestion: "Write each capability out as a literal. Data may go into the prompt or the inputs instead."
1036
+ },
1037
+ promptMissing: {
1038
+ code: "atlas_prompt_missing",
1039
+ messageFormat: "step %s runs an Atlas agent with neither query.prompt nor query.prompt_template.",
1040
+ suggestion: "Set exactly one of query.prompt or query.prompt_template."
1041
+ },
1042
+ promptBoth: {
1043
+ code: "atlas_prompt_both",
1044
+ messageFormat: "step %s sets both query.prompt and query.prompt_template.",
1045
+ suggestion: "Keep exactly one of query.prompt or query.prompt_template."
1046
+ },
1047
+ capabilityRefInvalid: {
1048
+ code: "atlas_capability_ref_invalid",
1049
+ messageFormat: "step %s uses atlas://capability/%s, which is not a valid capability reference.",
1050
+ suggestion: "A capability reference starts with a letter or digit and continues with letters, digits, _ and - up to 128 characters in all."
1051
+ },
1052
+ modelNotLiteral: {
1053
+ code: "atlas_model_not_literal",
1054
+ 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.",
1055
+ suggestion: "Write the model choice out as literals. Data may go into the prompt or the inputs instead."
1056
+ },
1057
+ paramRefused: {
1058
+ code: "atlas_param_refused",
1059
+ messageFormat: "step %s sets %s under query. Atlas decides these itself, so a step may not set them.",
1060
+ suggestion: "Remove these keys from the query.",
1061
+ agentKeys: [
1062
+ "api_key",
1063
+ "attribution",
1064
+ "base_url",
1065
+ "host",
1066
+ "idempotency_key",
1067
+ "org_id",
1068
+ "person",
1069
+ "untrusted_input",
1070
+ "untrusted_input_override",
1071
+ "url",
1072
+ "user_id"
1073
+ ],
1074
+ capabilityKeys: [
1075
+ "attribution",
1076
+ "idempotency_key",
1077
+ "untrusted_input",
1078
+ "untrusted_input_override"
1079
+ ]
1080
+ }
1081
+ },
1082
+ reservedInputNames: {
1083
+ $comment: "reserved_input_name (ERROR): an input the flow declares under the top-level query: map, or as an input_schema field name, that starts with prefix. The platform keeps that namespace for values it writes itself (the acting person, the credential manifest, the untrusted-input marker); a value or default written under such a name is never delivered. Every name the platform reserves today starts with the prefix. Matching is exact and case-sensitive: one leading underscore is an ordinary name. Findings carry no step id. queryFieldFormat takes the input name; schemaFieldFormat takes the field name as written (a non-string name is skipped). Query names are reported sorted, then schema fields in file order.",
1084
+ prefix: "__",
1085
+ code: "reserved_input_name",
1086
+ 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.",
1087
+ suggestion: 'Rename the input so it does not start with "__".',
1088
+ queryFieldFormat: "query.%s",
1089
+ schemaFieldFormat: "input_schema.fields.%s"
1090
+ },
1009
1091
  flowDataReservedKeys: {
1010
1092
  $comment: "flow_data_key_reserved (ERROR, no loop demotion): a key of the top-level data: map that names engine state. data: is seeded into the mission's .data namespace, where the engine keeps its own bookkeeping, so a flow declaring such a key would forge it. Matching is exact and case-sensitive. A key is reserved when it is one of exact (each with its reason), or starts with one of prefixes (checked in order, first wins; each with its reason). The finding's field is fieldFormat with the key; the message is messageFormat with the key (JSON-quoted, as Go's %q) then the reason; the suggestion is verbatim. Findings are sorted by key. Reference: FlowDataKeyReservation, validateFlowDataKeysAreNotReserved (aigentflow#247 review).",
1011
1093
  code: "flow_data_key_reserved",
@@ -2129,6 +2211,37 @@ var FUNCTION_OPERATIONS = {
2129
2211
  operations: new Set(aigentflow_spec_default.functionOperations.operations),
2130
2212
  sorted: aigentflow_spec_default.functionOperations.operations
2131
2213
  };
2214
+ var atlas = aigentflow_spec_default.atlasExecutor;
2215
+ var ATLAS_EXECUTOR = {
2216
+ scheme: atlas.scheme,
2217
+ providerAgent: atlas.providerAgent,
2218
+ providerCapability: atlas.providerCapability,
2219
+ agentResource: atlas.agentResource,
2220
+ capabilityRefPattern: new RegExp(atlas.capabilityRefPattern),
2221
+ operationUnknown: atlas.operationUnknown,
2222
+ agentMissing: atlas.agentMissing,
2223
+ agentNotLiteral: atlas.agentNotLiteral,
2224
+ capabilitiesNotLiteral: atlas.capabilitiesNotLiteral,
2225
+ promptMissing: atlas.promptMissing,
2226
+ promptBoth: atlas.promptBoth,
2227
+ capabilityRefInvalid: atlas.capabilityRefInvalid,
2228
+ modelNotLiteral: atlas.modelNotLiteral,
2229
+ paramRefused: {
2230
+ code: atlas.paramRefused.code,
2231
+ messageFormat: atlas.paramRefused.messageFormat,
2232
+ suggestion: atlas.paramRefused.suggestion,
2233
+ agentKeys: atlas.paramRefused.agentKeys,
2234
+ capabilityKeys: atlas.paramRefused.capabilityKeys
2235
+ }
2236
+ };
2237
+ var RESERVED_INPUT_NAMES = {
2238
+ prefix: aigentflow_spec_default.reservedInputNames.prefix,
2239
+ code: aigentflow_spec_default.reservedInputNames.code,
2240
+ messageFormat: aigentflow_spec_default.reservedInputNames.messageFormat,
2241
+ suggestion: aigentflow_spec_default.reservedInputNames.suggestion,
2242
+ queryFieldFormat: aigentflow_spec_default.reservedInputNames.queryFieldFormat,
2243
+ schemaFieldFormat: aigentflow_spec_default.reservedInputNames.schemaFieldFormat
2244
+ };
2132
2245
 
2133
2246
  // src/validators/executors.ts
2134
2247
  var SCHEME_SEPARATOR = "://";
@@ -2192,6 +2305,63 @@ function checkExecutor(executor, field, stepID, issues) {
2192
2305
  }
2193
2306
  checkFunctionOperation(executor, field, stepID, templated, issues);
2194
2307
  }
2308
+ function checkAtlasStep(executor, query, stepField, stepID, issues) {
2309
+ if (executor.includes(TEMPLATE_ACTION_OPEN)) return;
2310
+ const prefix = `${ATLAS_EXECUTOR.scheme}://`;
2311
+ if (!executor.startsWith(prefix)) return;
2312
+ const rest = executor.slice(prefix.length);
2313
+ const slash = rest.indexOf("/");
2314
+ const provider = slash < 0 ? rest : rest.slice(0, slash);
2315
+ const resource = slash < 0 ? "" : rest.slice(slash + 1);
2316
+ const quoted = JSON.stringify(stepID);
2317
+ const report = (rule, ...args) => {
2318
+ let message = rule.messageFormat.replace("%s", () => quoted);
2319
+ for (const a of args) message = message.replace("%s", () => a);
2320
+ issues.error({
2321
+ field: stepField,
2322
+ message,
2323
+ code: rule.code,
2324
+ stepId: stepID,
2325
+ suggestion: rule.suggestion
2326
+ });
2327
+ };
2328
+ const q2 = isRecord(query) ? query : {};
2329
+ let refusedKeys = ATLAS_EXECUTOR.paramRefused.capabilityKeys;
2330
+ if (provider === ATLAS_EXECUTOR.providerCapability) {
2331
+ if (!ATLAS_EXECUTOR.capabilityRefPattern.test(resource)) {
2332
+ report(ATLAS_EXECUTOR.capabilityRefInvalid, resource);
2333
+ }
2334
+ } else if (provider === ATLAS_EXECUTOR.providerAgent && resource === ATLAS_EXECUTOR.agentResource) {
2335
+ refusedKeys = ATLAS_EXECUTOR.paramRefused.agentKeys;
2336
+ const agent = q2.agent;
2337
+ if (typeof agent !== "string" || agent.trim() === "") {
2338
+ report(ATLAS_EXECUTOR.agentMissing);
2339
+ } else if (agent.includes(TEMPLATE_ACTION_OPEN)) {
2340
+ report(ATLAS_EXECUTOR.agentNotLiteral);
2341
+ }
2342
+ const hasPrompt = atlasTextPresent(q2.prompt);
2343
+ const hasTemplate = atlasTextPresent(q2.prompt_template);
2344
+ if (!hasPrompt && !hasTemplate) report(ATLAS_EXECUTOR.promptMissing);
2345
+ else if (hasPrompt && hasTemplate) report(ATLAS_EXECUTOR.promptBoth);
2346
+ if (anyTemplate(q2.model)) report(ATLAS_EXECUTOR.modelNotLiteral);
2347
+ } else {
2348
+ report(ATLAS_EXECUTOR.operationUnknown, executor);
2349
+ return;
2350
+ }
2351
+ if (anyTemplate(q2.capabilities)) report(ATLAS_EXECUTOR.capabilitiesNotLiteral);
2352
+ const refused = refusedKeys.filter((key) => Object.prototype.hasOwnProperty.call(q2, key)).sort();
2353
+ if (refused.length > 0) report(ATLAS_EXECUTOR.paramRefused, refused.join(", "));
2354
+ }
2355
+ function anyTemplate(v) {
2356
+ if (typeof v === "string") return v.includes(TEMPLATE_ACTION_OPEN);
2357
+ if (Array.isArray(v)) return v.some(anyTemplate);
2358
+ if (isRecord(v)) return Object.values(v).some(anyTemplate);
2359
+ return false;
2360
+ }
2361
+ function atlasTextPresent(v) {
2362
+ if (v === void 0 || v === null) return false;
2363
+ return typeof v !== "string" || v.trim() !== "";
2364
+ }
2195
2365
  function checkFunctionOperation(executor, field, stepID, templated, issues) {
2196
2366
  if (templated) return;
2197
2367
  const m = EXECUTOR_URL_PATTERN.exec(executor);
@@ -2216,6 +2386,7 @@ function validateExecutors(flow, issues) {
2216
2386
  const executor = issues.stringOf(step, "executor", `steps.${stepID}`);
2217
2387
  if (executor !== null && executor !== "") {
2218
2388
  checkExecutor(executor, `steps.${stepID}.executor`, stepID, issues);
2389
+ checkAtlasStep(executor, step.query, `steps.${stepID}`, stepID, issues);
2219
2390
  }
2220
2391
  const loop = step.loop;
2221
2392
  if (isRecord(loop) && Array.isArray(loop.steps)) {
@@ -2232,6 +2403,7 @@ function validateExecutors(flow, issues) {
2232
2403
  `${stepID}.${subID}`,
2233
2404
  issues
2234
2405
  );
2406
+ checkAtlasStep(subExecutor, subStep.query, subPath, `${stepID}.${subID}`, issues);
2235
2407
  }
2236
2408
  });
2237
2409
  }
@@ -3874,6 +4046,37 @@ function validateInputSchema(flow, issues) {
3874
4046
  validateSchemaDefinition(flow.input_schema, "input_schema", issues);
3875
4047
  }
3876
4048
 
4049
+ // src/validators/reservedInputs.ts
4050
+ function formatField(format, name) {
4051
+ return format.replace("%s", () => name);
4052
+ }
4053
+ function validateReservedInputNames(flow, issues) {
4054
+ const rule = RESERVED_INPUT_NAMES;
4055
+ const report = (name, fieldFormat) => {
4056
+ issues.error({
4057
+ field: formatField(fieldFormat, name),
4058
+ message: rule.messageFormat.replace("%s", () => JSON.stringify(name)),
4059
+ code: rule.code,
4060
+ suggestion: rule.suggestion
4061
+ });
4062
+ };
4063
+ const query = flow.query;
4064
+ if (isRecord(query)) {
4065
+ for (const name of Object.keys(query).sort()) {
4066
+ if (name.startsWith(rule.prefix)) report(name, rule.queryFieldFormat);
4067
+ }
4068
+ }
4069
+ const schema = flow.input_schema;
4070
+ const fields = isRecord(schema) ? schema.fields : void 0;
4071
+ if (!Array.isArray(fields)) return;
4072
+ for (const f of fields) {
4073
+ if (!isRecord(f)) continue;
4074
+ if (typeof f.name === "string" && f.name.startsWith(rule.prefix)) {
4075
+ report(f.name, rule.schemaFieldFormat);
4076
+ }
4077
+ }
4078
+ }
4079
+
3877
4080
  // src/validators/outputSchema.ts
3878
4081
  function validateOutputSchemas(flow, issues) {
3879
4082
  const steps = flow.steps;
@@ -4988,7 +5191,7 @@ var CODE2 = "server_owned_query_key";
4988
5191
  var KEY_QUERY = "query";
4989
5192
  var KEY_ID = "id";
4990
5193
  var SERVER_OWNED = new Set(SERVER_OWNED_QUERY_KEYS.keys);
4991
- function formatField(format, ...args) {
5194
+ function formatField2(format, ...args) {
4992
5195
  let i = 0;
4993
5196
  return format.replace(/%s/g, () => args[i++] ?? "");
4994
5197
  }
@@ -5006,7 +5209,7 @@ function validateServerOwnedQueryKeys(flow, issues) {
5006
5209
  issues,
5007
5210
  stepID,
5008
5211
  key,
5009
- formatField(SERVER_OWNED_QUERY_KEYS.stepFieldFormat, stepID, key)
5212
+ formatField2(SERVER_OWNED_QUERY_KEYS.stepFieldFormat, stepID, key)
5010
5213
  );
5011
5214
  }
5012
5215
  }
@@ -5020,7 +5223,7 @@ function validateServerOwnedQueryKeys(flow, issues) {
5020
5223
  issues,
5021
5224
  stepID,
5022
5225
  key,
5023
- formatField(SERVER_OWNED_QUERY_KEYS.loopStepFieldFormat, stepID, subID, key)
5226
+ formatField2(SERVER_OWNED_QUERY_KEYS.loopStepFieldFormat, stepID, subID, key)
5024
5227
  );
5025
5228
  }
5026
5229
  }
@@ -5289,7 +5492,7 @@ function own(m, key) {
5289
5492
  if (!isRecord(m) || !Object.prototype.hasOwnProperty.call(m, key)) return void 0;
5290
5493
  return m[key];
5291
5494
  }
5292
- function formatField2(format, ...args) {
5495
+ function formatField3(format, ...args) {
5293
5496
  let i = 0;
5294
5497
  return format.replace(/%s/g, () => args[i++] ?? "");
5295
5498
  }
@@ -5311,14 +5514,14 @@ function credentialEndpointSteps(flow, issues) {
5311
5514
  out.push({
5312
5515
  executor: issues.stringOf(step, KEY_EXECUTOR, `steps.${stepId}`) ?? "",
5313
5516
  query: own(step, KEY_QUERY2),
5314
- field: (key) => formatField2(CREDENTIAL_ENDPOINT_PAIRING.stepFieldFormat, stepId, key)
5517
+ field: (key) => formatField3(CREDENTIAL_ENDPOINT_PAIRING.stepFieldFormat, stepId, key)
5315
5518
  });
5316
5519
  for (const sub of loopSubStepsOfStep(stepId, step)) {
5317
5520
  const subId = issues.stringOf(sub.raw, KEY_ID2, sub.basePath) ?? "";
5318
5521
  out.push({
5319
5522
  executor: issues.stringOf(sub.raw, KEY_EXECUTOR, sub.basePath) ?? "",
5320
5523
  query: own(sub.raw, KEY_QUERY2),
5321
- field: (key) => formatField2(CREDENTIAL_ENDPOINT_PAIRING.loopStepFieldFormat, stepId, subId, key)
5524
+ field: (key) => formatField3(CREDENTIAL_ENDPOINT_PAIRING.loopStepFieldFormat, stepId, subId, key)
5322
5525
  });
5323
5526
  }
5324
5527
  }
@@ -5382,7 +5585,7 @@ function validateAI(flow, steps, issues) {
5382
5585
  if ((stepsUsing.get(provider) ?? 0) > 0 && (stepsWithoutOwnKey.get(provider) ?? 0) === 0) {
5383
5586
  continue;
5384
5587
  }
5385
- warnStoredShape(issues, formatField2(CREDENTIAL_ENDPOINT_PAIRING.executorConfigBaseUrlFieldFormat, provider), provider);
5588
+ warnStoredShape(issues, formatField3(CREDENTIAL_ENDPOINT_PAIRING.executorConfigBaseUrlFieldFormat, provider), provider);
5386
5589
  }
5387
5590
  }
5388
5591
  function warnStoredShape(issues, field, provider) {
@@ -5429,7 +5632,7 @@ function familySecret(flow, family, step, issues) {
5429
5632
  if (apiKey !== "" && listHas(family.secretParams, family.configApiKeyParam)) {
5430
5633
  return {
5431
5634
  envName: serverEnvRef(family, apiKey),
5432
- field: formatField2(
5635
+ field: formatField3(
5433
5636
  CREDENTIAL_ENDPOINT_PAIRING.executorConfigKeyFieldFormat,
5434
5637
  configKey,
5435
5638
  CREDENTIAL_ENDPOINT_PAIRING.executorConfigApiKeyField
@@ -5442,7 +5645,7 @@ function familySecret(flow, family, step, issues) {
5442
5645
  if (v !== null) {
5443
5646
  return {
5444
5647
  envName: serverEnvRef(family, v),
5445
- field: formatField2(CREDENTIAL_ENDPOINT_PAIRING.executorConfigExtraFieldFormat, configKey, key)
5648
+ field: formatField3(CREDENTIAL_ENDPOINT_PAIRING.executorConfigExtraFieldFormat, configKey, key)
5446
5649
  };
5447
5650
  }
5448
5651
  }
@@ -5468,13 +5671,13 @@ function familyAuthorEndpoint(flow, family, step, issues) {
5468
5671
  if (inst === null) continue;
5469
5672
  const baseUrl = configStringField(inst, configKey, CREDENTIAL_ENDPOINT_PAIRING.executorConfigBaseUrlField, issues);
5470
5673
  if (baseUrl !== "" && listHas(family.endpointParams, family.configBaseUrlParam)) {
5471
- return decide(baseUrl, formatField2(CREDENTIAL_ENDPOINT_PAIRING.executorConfigBaseUrlFieldFormat, configKey));
5674
+ return decide(baseUrl, formatField3(CREDENTIAL_ENDPOINT_PAIRING.executorConfigBaseUrlFieldFormat, configKey));
5472
5675
  }
5473
5676
  const extra = own(inst, EXECUTOR_CONFIG_ENV_SCOPES.extraKey);
5474
5677
  for (const key of family.endpointParams) {
5475
5678
  const v = nonEmptyEndpoint(extra, key);
5476
5679
  if (v !== null)
5477
- return decide(v, formatField2(CREDENTIAL_ENDPOINT_PAIRING.executorConfigExtraFieldFormat, configKey, key));
5680
+ return decide(v, formatField3(CREDENTIAL_ENDPOINT_PAIRING.executorConfigExtraFieldFormat, configKey, key));
5478
5681
  }
5479
5682
  }
5480
5683
  return null;
@@ -7185,6 +7388,7 @@ function validateParsed(flow, opts, sources) {
7185
7388
  validateOrchestratorCampaign(f, issues, opts);
7186
7389
  validateCredentialBindings(f, issues);
7187
7390
  validateInputSchema(f, issues);
7391
+ validateReservedInputNames(f, issues);
7188
7392
  validateOutputSchemas(f, issues);
7189
7393
  validateQualityGates(f, issues);
7190
7394
  validateProcessingOperations(f, issues);