@vaudience/aigentflow-flow-validator 0.19.0 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -302,6 +302,17 @@ function isValidGoDuration(input) {
302
302
  var RESERVED_STEP_ID_CHAR = ".";
303
303
  var RESERVED_STEP_ID_ORCHESTRATOR = "orchestrator";
304
304
  var DISPLAY_NAME_MAX_LEN = 80;
305
+ var YAML11_BOOL_WORDS = new Set(
306
+ ["y", "yes", "on", "n", "no", "off"].flatMap((w) => [
307
+ w,
308
+ w.toUpperCase(),
309
+ w[0].toUpperCase() + w.slice(1)
310
+ ])
311
+ );
312
+ function isBoolLike(v) {
313
+ if (v === null || typeof v === "boolean") return true;
314
+ return typeof v === "string" && YAML11_BOOL_WORDS.has(v);
315
+ }
305
316
  function validateBasicStructure(flow, issues) {
306
317
  if (!issues.nonEmptyStringOf(flow, "aigentflow_version", "")) {
307
318
  issues.error({
@@ -331,6 +342,14 @@ function validateBasicStructure(flow, issues) {
331
342
  });
332
343
  }
333
344
  }
345
+ if (flow.strict_templates !== void 0 && !isBoolLike(flow.strict_templates)) {
346
+ issues.error({
347
+ field: "strict_templates",
348
+ message: "strict_templates must be a boolean (true or false)",
349
+ code: "invalid_type",
350
+ suggestion: "Write 'strict_templates: true' or remove the key"
351
+ });
352
+ }
334
353
  const start = issues.stringOf(flow, "start", "");
335
354
  if (start === null || start === "") {
336
355
  issues.error({
@@ -430,7 +449,7 @@ function validateBasicStructure(flow, issues) {
430
449
 
431
450
  // src/spec/aigentflow-spec.json
432
451
  var aigentflow_spec_default = {
433
- specVersion: "2.820.0",
452
+ specVersion: "2.827.0",
434
453
  inputSchemaVersion: 1,
435
454
  executorSchemes: [
436
455
  "a2a",
@@ -454,6 +473,7 @@ var aigentflow_spec_default = {
454
473
  "geocoding",
455
474
  "geovisualize",
456
475
  "getmd",
476
+ "here",
457
477
  "homeassistant",
458
478
  "hosting",
459
479
  "http",
@@ -1255,6 +1275,39 @@ var aigentflow_spec_default = {
1255
1275
  }
1256
1276
  }
1257
1277
  },
1278
+ templateDefaultPiped: {
1279
+ code: "template_default_piped",
1280
+ messageFormat: "`default` takes the value FIRST, and a pipe passes the piped value LAST: `%s` is `default <fallback> <value>`, so the fallback is always the result",
1281
+ suggestion: 'write the value first and the fallback second, as a call: `{{ default .x "fallback" }}`'
1282
+ },
1283
+ complianceResidency: {
1284
+ code: "compliance_residency_unenforced",
1285
+ euResidencyCodes: ["EU", "DE", "FR", "IE", "NL", "IT", "ES"],
1286
+ regionLaneProviders: [
1287
+ "bedrock",
1288
+ "google",
1289
+ "azure",
1290
+ "openai",
1291
+ "assemblyai",
1292
+ "speechmatics",
1293
+ "deepgram",
1294
+ "mistral"
1295
+ ],
1296
+ aiProtocol: "ai",
1297
+ protocolSeparator: "://",
1298
+ regionParam: "region",
1299
+ enforceRegionParam: "enforce_region",
1300
+ baseUrlParamSuffix: "_base_url",
1301
+ enforceRegionTrueStrings: ["true", "1", "yes"],
1302
+ stepFieldFormat: "steps.%s.executor",
1303
+ loopStepFieldFormat: "steps.%s.loop.steps.%s.executor",
1304
+ orchestratorField: "orchestrator.exons",
1305
+ siteStepFormat: "step %q",
1306
+ siteLoopStepFormat: "loop sub-step %q of step %q",
1307
+ siteOrchestrator: "the orchestrator",
1308
+ messageFormat: "%s calls provider %q, whose default endpoint commits to no jurisdiction, but sets neither region nor enforce_region, so nothing pins it to the declared residency %v. compliance.residency is a catalogue eligibility check, not endpoint evidence",
1309
+ suggestion: "Add `region: eu` and `enforce_region: true` to the call (an orchestrator: the same two keys on the orchestrator block). Prove it afterwards: the step record's diagnostics.region is stamped from the host actually dialled."
1310
+ },
1258
1311
  examples: {
1259
1312
  limits: {
1260
1313
  maxPerFlow: 50,
@@ -1525,6 +1578,7 @@ var aigentflow_spec_default = {
1525
1578
  rate_limit: "FlowRateLimitConfig",
1526
1579
  start: "scalar",
1527
1580
  steps: "map<StepDefinition>",
1581
+ strict_templates: "scalar",
1528
1582
  tags: "list<scalar>",
1529
1583
  template: "FlowTemplateMetadata",
1530
1584
  tool_discovery: "scalar",
@@ -1850,6 +1904,25 @@ var CREDENTIAL_ENDPOINT_PAIRING = {
1850
1904
  familyKeySeparator: aigentflow_spec_default.credentialEndpointPairing.familyKeySeparator,
1851
1905
  families: aigentflow_spec_default.credentialEndpointPairing.families
1852
1906
  };
1907
+ var COMPLIANCE_RESIDENCY = {
1908
+ code: aigentflow_spec_default.complianceResidency.code,
1909
+ euResidencyCodes: aigentflow_spec_default.complianceResidency.euResidencyCodes,
1910
+ regionLaneProviders: aigentflow_spec_default.complianceResidency.regionLaneProviders,
1911
+ aiProtocol: aigentflow_spec_default.complianceResidency.aiProtocol,
1912
+ protocolSeparator: aigentflow_spec_default.complianceResidency.protocolSeparator,
1913
+ regionParam: aigentflow_spec_default.complianceResidency.regionParam,
1914
+ enforceRegionParam: aigentflow_spec_default.complianceResidency.enforceRegionParam,
1915
+ baseUrlParamSuffix: aigentflow_spec_default.complianceResidency.baseUrlParamSuffix,
1916
+ enforceRegionTrueStrings: aigentflow_spec_default.complianceResidency.enforceRegionTrueStrings,
1917
+ stepFieldFormat: aigentflow_spec_default.complianceResidency.stepFieldFormat,
1918
+ loopStepFieldFormat: aigentflow_spec_default.complianceResidency.loopStepFieldFormat,
1919
+ orchestratorField: aigentflow_spec_default.complianceResidency.orchestratorField,
1920
+ siteStepFormat: aigentflow_spec_default.complianceResidency.siteStepFormat,
1921
+ siteLoopStepFormat: aigentflow_spec_default.complianceResidency.siteLoopStepFormat,
1922
+ siteOrchestrator: aigentflow_spec_default.complianceResidency.siteOrchestrator,
1923
+ messageFormat: aigentflow_spec_default.complianceResidency.messageFormat,
1924
+ suggestion: aigentflow_spec_default.complianceResidency.suggestion
1925
+ };
1853
1926
  var EXAMPLES = {
1854
1927
  limits: aigentflow_spec_default.examples.limits,
1855
1928
  idPattern: new RegExp(aigentflow_spec_default.examples.idPattern),
@@ -1867,6 +1940,11 @@ var EXAMPLES = {
1867
1940
  name: p.name,
1868
1941
  re: new RegExp(p.expr, p.flags)
1869
1942
  }))};
1943
+ var TEMPLATE_DEFAULT_PIPED = {
1944
+ code: aigentflow_spec_default.templateDefaultPiped.code,
1945
+ messageFormat: aigentflow_spec_default.templateDefaultPiped.messageFormat,
1946
+ suggestion: aigentflow_spec_default.templateDefaultPiped.suggestion
1947
+ };
1870
1948
 
1871
1949
  // src/validators/executors.ts
1872
1950
  var SCHEME_SEPARATOR = "://";
@@ -3830,6 +3908,117 @@ function splitPipeline(body) {
3830
3908
  return stages;
3831
3909
  }
3832
3910
 
3911
+ // src/template/gotmpl-default.ts
3912
+ var FUNCTION_NAME = "default";
3913
+ var PIPE = "|";
3914
+ var OPEN_PAREN = "(";
3915
+ var CLOSE_PAREN = ")";
3916
+ var MAX_NESTING_DEPTH = 100;
3917
+ var PIPELINE_KEYWORDS = /^(?:else\s+if|else\s+with|if|range|with|template|block)(?![\w$.])/;
3918
+ var NO_PIPELINE = /^(?:define|else|end|break|continue)(?![\w$.])/;
3919
+ var DECLARATION = /^\$\w*(?:\s*,\s*\$\w*)*\s*:?=/;
3920
+ function pipedDefaultPipelines(src) {
3921
+ const { actions, fatal } = lexActions(src);
3922
+ if (fatal) return [];
3923
+ const found = /* @__PURE__ */ new Set();
3924
+ try {
3925
+ for (const action of actions) {
3926
+ if (action.isComment || action.body === "") continue;
3927
+ scanAction(action.body, found);
3928
+ }
3929
+ } catch (err) {
3930
+ if (!(err instanceof RangeError)) throw err;
3931
+ return [];
3932
+ }
3933
+ return [...found].sort();
3934
+ }
3935
+ function scanAction(body, found) {
3936
+ let rest = body;
3937
+ const kw = PIPELINE_KEYWORDS.exec(rest);
3938
+ if (!kw && NO_PIPELINE.test(rest)) return;
3939
+ if (kw) {
3940
+ rest = rest.slice(kw[0].length).trimStart();
3941
+ const keyword = kw[0].replace(/\s+/g, " ");
3942
+ if (keyword === "template" || keyword === "block") {
3943
+ const q2 = rest[0];
3944
+ if (q2 === '"' || q2 === "`") {
3945
+ const end = scanString(rest, 0, q2);
3946
+ if (end === -1) return;
3947
+ rest = rest.slice(end + 1).trimStart();
3948
+ }
3949
+ }
3950
+ }
3951
+ if (rest === "") return;
3952
+ parsePipeline(rest, 0, false, found, 0);
3953
+ }
3954
+ function parsePipeline(src, start, nested, found, depth) {
3955
+ if (depth > MAX_NESTING_DEPTH) return { text: src.slice(start), end: src.length };
3956
+ let i = start;
3957
+ const n = src.length;
3958
+ let decl = "";
3959
+ const decMatch = DECLARATION.exec(src.slice(i));
3960
+ if (decMatch) {
3961
+ decl = decMatch[0].replace(/\s+/g, " ") + " ";
3962
+ i += decMatch[0].length;
3963
+ }
3964
+ const commands = [];
3965
+ let current = [];
3966
+ let firstWords = [];
3967
+ let pipedDefault = false;
3968
+ const pushCommand = () => {
3969
+ if (current.length > 0) {
3970
+ commands.push(current);
3971
+ firstWords.push(current[0]);
3972
+ }
3973
+ current = [];
3974
+ };
3975
+ while (i < n) {
3976
+ const c = src[i];
3977
+ if (c === " " || c === " " || c === "\n" || c === "\r") {
3978
+ i += 1;
3979
+ continue;
3980
+ }
3981
+ if (c === '"' || c === "`" || c === "'") {
3982
+ const end = scanString(src, i, c);
3983
+ const stop = end === -1 ? n - 1 : end;
3984
+ current.push(src.slice(i, stop + 1));
3985
+ i = stop + 1;
3986
+ continue;
3987
+ }
3988
+ if (c === OPEN_PAREN) {
3989
+ const inner = parsePipeline(src, i + 1, true, found, depth + 1);
3990
+ current.push(`(${inner.text})`);
3991
+ i = inner.end;
3992
+ continue;
3993
+ }
3994
+ if (c === CLOSE_PAREN) {
3995
+ if (nested) {
3996
+ i += 1;
3997
+ break;
3998
+ }
3999
+ i += 1;
4000
+ continue;
4001
+ }
4002
+ if (c === PIPE) {
4003
+ pushCommand();
4004
+ i += 1;
4005
+ continue;
4006
+ }
4007
+ let j = i;
4008
+ while (j < n && !/[\s|()"`']/.test(src[j])) j += 1;
4009
+ if (j === i) j = i + 1;
4010
+ current.push(src.slice(i, j));
4011
+ i = j;
4012
+ }
4013
+ pushCommand();
4014
+ firstWords.forEach((word, idx) => {
4015
+ if (idx > 0 && word === FUNCTION_NAME) pipedDefault = true;
4016
+ });
4017
+ const text = decl + commands.map((cmd) => cmd.join(" ")).join(` ${PIPE} `);
4018
+ if (pipedDefault) found.add(text);
4019
+ return { text, end: i };
4020
+ }
4021
+
3833
4022
  // src/validators/processingOperations.ts
3834
4023
  var PROCESSING_OP_GUARD_KEY = PROCESSING_OPERATIONS.guardKey;
3835
4024
  var PROCESSING_PHASES = ["pre_processing", "post_processing"];
@@ -3976,6 +4165,17 @@ function checkTemplateString(value, field, stepID, issues, stats, opts, demote =
3976
4165
  });
3977
4166
  }
3978
4167
  }
4168
+ if (errors.length > 0) return;
4169
+ for (const pipe of pipedDefaultPipelines(value)) {
4170
+ report({
4171
+ field,
4172
+ message: TEMPLATE_DEFAULT_PIPED.messageFormat.replace("%s", () => pipe),
4173
+ code: TEMPLATE_DEFAULT_PIPED.code,
4174
+ stepId: stepID,
4175
+ context: `Template: ${value}`,
4176
+ suggestion: TEMPLATE_DEFAULT_PIPED.suggestion
4177
+ });
4178
+ }
3979
4179
  }
3980
4180
  function walkStrings2(basePath, value, stepID, issues, stats, opts, check, demote = false) {
3981
4181
  if (isString(value)) {
@@ -5202,6 +5402,141 @@ function warnOrchestratorToolWithheld(flow, orch, report, issues) {
5202
5402
  }
5203
5403
  }
5204
5404
 
5405
+ // src/validators/complianceResidency.ts
5406
+ function own2(m, key) {
5407
+ if (!isRecord(m) || !Object.prototype.hasOwnProperty.call(m, key)) return void 0;
5408
+ return m[key];
5409
+ }
5410
+ function sprintf(format, ...args) {
5411
+ let i = 0;
5412
+ return format.replace(/%[sqv]/g, (verb) => {
5413
+ const arg = args[i++] ?? "";
5414
+ return verb === "%q" ? JSON.stringify(arg) : arg;
5415
+ });
5416
+ }
5417
+ function literalOrEmpty(s) {
5418
+ const t = goTrimSpace2(s);
5419
+ return t.includes(TEMPLATE_ACTION_OPEN) ? "" : t;
5420
+ }
5421
+ function euOnlyResidency(flow, issues) {
5422
+ const raw = own2(own2(flow, "compliance"), "residency");
5423
+ if (!isArray(raw)) return null;
5424
+ const codes = [];
5425
+ for (let i = 0; i < raw.length; i++) {
5426
+ if (raw[i] === null) continue;
5427
+ const code = issues.stringAt(raw[i], `compliance.residency[${i}]`);
5428
+ if (code === null) return null;
5429
+ codes.push(code);
5430
+ }
5431
+ if (codes.length === 0) return null;
5432
+ const eu = new Set(COMPLIANCE_RESIDENCY.euResidencyCodes);
5433
+ return codes.every((c) => eu.has(goTrimSpace2(c).toUpperCase())) ? codes : null;
5434
+ }
5435
+ function aiProvider(executor) {
5436
+ const prefix = COMPLIANCE_RESIDENCY.aiProtocol + COMPLIANCE_RESIDENCY.protocolSeparator;
5437
+ if (!executor.startsWith(prefix)) return "";
5438
+ const rest = executor.slice(prefix.length);
5439
+ const slash = rest.indexOf("/");
5440
+ const provider = slash > 0 ? rest.slice(0, slash) : "";
5441
+ return provider.includes(TEMPLATE_ACTION_OPEN) ? "" : provider;
5442
+ }
5443
+ function isRegionLane(provider) {
5444
+ const literal = literalOrEmpty(provider);
5445
+ return literal !== "" && COMPLIANCE_RESIDENCY.regionLaneProviders.includes(literal.toLowerCase());
5446
+ }
5447
+ function nonBlankString(m, key) {
5448
+ const v = own2(m, key);
5449
+ return typeof v === "string" && goTrimSpace2(v) !== "";
5450
+ }
5451
+ function queryEnforcesRegion(query) {
5452
+ const v = own2(query, COMPLIANCE_RESIDENCY.enforceRegionParam);
5453
+ if (typeof v === "boolean") return v;
5454
+ return typeof v === "string" && COMPLIANCE_RESIDENCY.enforceRegionTrueStrings.includes(v);
5455
+ }
5456
+ function flowDirectsEndpoint(flow, provider, issues) {
5457
+ const key = provider.toLowerCase();
5458
+ const inst = own2(own2(flow, "executor_config"), key);
5459
+ if (!isRecord(inst)) return false;
5460
+ const baseUrl = issues.stringOf(inst, "base_url", `executor_config.${key}`);
5461
+ return baseUrl !== null && goTrimSpace2(baseUrl) !== "";
5462
+ }
5463
+ function callPinsEndpoint(flow, provider, query, issues) {
5464
+ if (nonBlankString(query, COMPLIANCE_RESIDENCY.regionParam)) return true;
5465
+ if (queryEnforcesRegion(query)) return true;
5466
+ if (nonBlankString(query, provider.toLowerCase() + COMPLIANCE_RESIDENCY.baseUrlParamSuffix)) return true;
5467
+ return flowDirectsEndpoint(flow, provider, issues);
5468
+ }
5469
+ function validateResidencyEnforcement(flow, issues) {
5470
+ const residency = euOnlyResidency(flow, issues);
5471
+ if (residency === null) return;
5472
+ const warn = (site, field, stepId, provider) => {
5473
+ issues.warn({
5474
+ field,
5475
+ ...stepId === void 0 ? {} : { stepId },
5476
+ code: COMPLIANCE_RESIDENCY.code,
5477
+ message: sprintf(COMPLIANCE_RESIDENCY.messageFormat, site, provider, `[${residency.join(" ")}]`),
5478
+ suggestion: COMPLIANCE_RESIDENCY.suggestion
5479
+ });
5480
+ };
5481
+ const steps = flow.steps;
5482
+ if (isRecord(steps)) {
5483
+ for (const stepId of Object.keys(steps).sort()) {
5484
+ const step = steps[stepId];
5485
+ if (!isRecord(step)) continue;
5486
+ const calls = [
5487
+ {
5488
+ executor: issues.stringOf(step, "executor", `steps.${stepId}`) ?? "",
5489
+ query: own2(step, "query"),
5490
+ subId: null
5491
+ }
5492
+ ];
5493
+ for (const sub of loopSubStepsOfStep(stepId, step)) {
5494
+ calls.push({
5495
+ executor: issues.stringOf(sub.raw, "executor", sub.basePath) ?? "",
5496
+ query: own2(sub.raw, "query"),
5497
+ subId: issues.stringOf(sub.raw, "id", sub.basePath) ?? ""
5498
+ });
5499
+ }
5500
+ for (const call of calls) {
5501
+ const provider = aiProvider(call.executor);
5502
+ if (!isRegionLane(provider)) continue;
5503
+ if (callPinsEndpoint(flow, provider, call.query, issues)) continue;
5504
+ if (call.subId === null) {
5505
+ warn(
5506
+ sprintf(COMPLIANCE_RESIDENCY.siteStepFormat, stepId),
5507
+ sprintf(COMPLIANCE_RESIDENCY.stepFieldFormat, stepId),
5508
+ stepId,
5509
+ provider
5510
+ );
5511
+ } else {
5512
+ warn(
5513
+ sprintf(COMPLIANCE_RESIDENCY.siteLoopStepFormat, call.subId, stepId),
5514
+ sprintf(COMPLIANCE_RESIDENCY.loopStepFieldFormat, stepId, call.subId),
5515
+ stepId,
5516
+ provider
5517
+ );
5518
+ }
5519
+ }
5520
+ }
5521
+ }
5522
+ warnOrchestrator(flow, issues, warn);
5523
+ }
5524
+ function warnOrchestrator(flow, issues, warn) {
5525
+ const orch = flow.orchestrator;
5526
+ if (!isRecord(orch)) return;
5527
+ const source = issues.stringOf(orch, "exons", "orchestrator");
5528
+ if (source === null || source === "") return;
5529
+ const report = inspectExonsFrontmatter(source);
5530
+ if (report.parseError !== null || !report.specRead || !report.hasSpec) return;
5531
+ const provider = literalOrEmpty(report.provider);
5532
+ if (!isRegionLane(provider)) return;
5533
+ const region = issues.stringOf(orch, "region", "orchestrator");
5534
+ if (region !== null && goTrimSpace2(region) !== "") return;
5535
+ if (orch.enforce_region === true) return;
5536
+ if (flowDirectsEndpoint(flow, provider, issues)) return;
5537
+ warn(COMPLIANCE_RESIDENCY.siteOrchestrator, COMPLIANCE_RESIDENCY.orchestratorField, void 0, provider);
5538
+ }
5539
+
5205
5540
  // src/validators/examples.ts
5206
5541
  var KEY_EXAMPLES = "examples";
5207
5542
  var VISIBILITY_PUBLIC = "public";
@@ -5279,7 +5614,7 @@ function num(n) {
5279
5614
  function has(o, key) {
5280
5615
  return Object.prototype.hasOwnProperty.call(o, key) && o[key] !== null && o[key] !== void 0;
5281
5616
  }
5282
- function own2(o, key) {
5617
+ function own3(o, key) {
5283
5618
  return Object.prototype.hasOwnProperty.call(o, key) ? o[key] : void 0;
5284
5619
  }
5285
5620
  function setOwn(o, key, value) {
@@ -5331,7 +5666,7 @@ function mergePatch(target, patch, depth) {
5331
5666
  continue;
5332
5667
  }
5333
5668
  if (isRecord(pv)) {
5334
- const current = own2(target, k);
5669
+ const current = own3(target, k);
5335
5670
  const existing = isRecord(current) ? deepCopy(current, 0) : {};
5336
5671
  mergePatch(existing, pv, depth + 1);
5337
5672
  setOwn(target, k, existing);
@@ -5351,7 +5686,7 @@ function asFileRef(v) {
5351
5686
  if (keys.length === 0) return null;
5352
5687
  for (const k of keys) if (!FILE_REF_KEYS.has(k)) return null;
5353
5688
  const str = (k) => {
5354
- const x = own2(v, k);
5689
+ const x = own3(v, k);
5355
5690
  return typeof x === "string" ? x : "";
5356
5691
  };
5357
5692
  return {
@@ -5419,7 +5754,7 @@ var Walker = class _Walker {
5419
5754
  `the examples block is ${size} bytes; the limit is ${L.maxBlockBytes}. Move large inputs or target outputs to a file reference (https URL).`
5420
5755
  );
5421
5756
  }
5422
- const allHeld = examples.every((e) => isRecord(e) && own2(e, "hold_out") === true);
5757
+ const allHeld = examples.every((e) => isRecord(e) && own3(e, "hold_out") === true);
5423
5758
  if (allHeld) {
5424
5759
  this.warn(
5425
5760
  "examples_all_held_out",
@@ -5507,9 +5842,9 @@ var Walker = class _Walker {
5507
5842
  `example ${q(label)} notes are ${notesN} characters; the limit is ${L.maxNotesRunes}`
5508
5843
  );
5509
5844
  }
5510
- this.validateTags(path, label, own2(ex, "tags"));
5511
- this.validateWeight(`${path}.weight`, label, numberOf(own2(ex, "weight")));
5512
- const minScore = numberOf(own2(ex, "min_score"));
5845
+ this.validateTags(path, label, own3(ex, "tags"));
5846
+ this.validateWeight(`${path}.weight`, label, numberOf(own3(ex, "weight")));
5847
+ const minScore = numberOf(own3(ex, "min_score"));
5513
5848
  if (minScore !== void 0 && !scoreInRange(minScore)) {
5514
5849
  this.err(
5515
5850
  "example_min_score_range",
@@ -5525,7 +5860,7 @@ var Walker = class _Walker {
5525
5860
  `example ${q(label)} has side_effects ${q(sideEffects)}; use refuse or allow`
5526
5861
  );
5527
5862
  }
5528
- const holdOut = own2(ex, "hold_out") === true;
5863
+ const holdOut = own3(ex, "hold_out") === true;
5529
5864
  if (holdOut && this.isPublic()) {
5530
5865
  this.err(
5531
5866
  "example_holdout_in_public_flow",
@@ -5548,17 +5883,17 @@ var Walker = class _Walker {
5548
5883
  `example ${q(label)} has neither input nor input_ref; use input: {} for a flow that takes no input`
5549
5884
  );
5550
5885
  }
5551
- const rawInput = own2(ex, "input");
5886
+ const rawInput = own3(ex, "input");
5552
5887
  const baseInput = isRecord(rawInput) ? rawInput : null;
5553
5888
  if (baseInput !== null) {
5554
5889
  this.checkInput(`${path}.input`, label, baseInput, "example_input_invalid");
5555
5890
  }
5556
- const rawInputRef = own2(ex, "input_ref");
5891
+ const rawInputRef = own3(ex, "input_ref");
5557
5892
  if (isRecord(rawInputRef)) {
5558
5893
  this.validateFileRef(`${path}.input_ref`, this.fileRefOf(rawInputRef, `${path}.input_ref`));
5559
5894
  }
5560
5895
  let binaryOnly = false;
5561
- const expected = own2(ex, "expected");
5896
+ const expected = own3(ex, "expected");
5562
5897
  if (!has(ex, "expected")) {
5563
5898
  this.err(
5564
5899
  "example_expected_missing",
@@ -5577,7 +5912,7 @@ var Walker = class _Walker {
5577
5912
  "this example can be run but not scored"
5578
5913
  );
5579
5914
  }
5580
- this.validateCheckpoints(path, label, own2(ex, "checkpoints"));
5915
+ this.validateCheckpoints(path, label, own3(ex, "checkpoints"));
5581
5916
  this.validateVariants(i, path, label, ex, hasInput, baseInput);
5582
5917
  this.scanSecretLike(i, path, ex);
5583
5918
  }
@@ -5637,8 +5972,8 @@ var Walker = class _Walker {
5637
5972
  );
5638
5973
  return;
5639
5974
  }
5640
- const schema = own2(this.flow, "input_schema");
5641
- const query = own2(this.flow, "query");
5975
+ const schema = own3(this.flow, "input_schema");
5976
+ const query = own3(this.flow, "query");
5642
5977
  if (isRecord(schema)) {
5643
5978
  this.checkInputAgainstSchema(field, label, input, schema, code);
5644
5979
  } else if (isRecord(query) && Object.keys(query).length > 0) {
@@ -5706,29 +6041,29 @@ var Walker = class _Walker {
5706
6041
  }
5707
6042
  }
5708
6043
  schemaFields(schema) {
5709
- const raw = own2(schema, "fields");
6044
+ const raw = own3(schema, "fields");
5710
6045
  if (!Array.isArray(raw)) return [];
5711
6046
  const out = [];
5712
6047
  raw.forEach((f, i) => {
5713
6048
  if (!isRecord(f)) return;
5714
6049
  const base = `input_schema.fields[${i}]`;
5715
- const enumRaw = own2(f, "enum");
6050
+ const enumRaw = own3(f, "enum");
5716
6051
  const enumValues = [];
5717
6052
  if (Array.isArray(enumRaw)) {
5718
6053
  enumRaw.forEach((e, j) => {
5719
6054
  enumValues.push(e === null ? "" : this.issues.stringAt(e, `${base}.enum[${j}]`) ?? "");
5720
6055
  });
5721
6056
  }
5722
- const vw = own2(f, "visible_when");
6057
+ const vw = own3(f, "visible_when");
5723
6058
  out.push({
5724
6059
  name: this.s(f, "name", base),
5725
6060
  type: this.s(f, "type", base),
5726
- required: own2(f, "required") === true,
6061
+ required: own3(f, "required") === true,
5727
6062
  enumValues,
5728
6063
  visibleWhen: isRecord(vw) ? {
5729
6064
  field: this.s(vw, "field", `${base}.visible_when`),
5730
- equals: own2(vw, "equals"),
5731
- in: Array.isArray(own2(vw, "in")) ? own2(vw, "in") : []
6065
+ equals: own3(vw, "equals"),
6066
+ in: Array.isArray(own3(vw, "in")) ? own3(vw, "in") : []
5732
6067
  } : null
5733
6068
  });
5734
6069
  });
@@ -5739,7 +6074,7 @@ var Walker = class _Walker {
5739
6074
  const failures = [];
5740
6075
  for (const f of fields) {
5741
6076
  if (!isVisible(f, runInput)) continue;
5742
- const raw = own2(runInput, f.name);
6077
+ const raw = own3(runInput, f.name);
5743
6078
  if (raw === void 0 || raw === null) {
5744
6079
  if (f.required) {
5745
6080
  failures.push({
@@ -5850,7 +6185,7 @@ var Walker = class _Walker {
5850
6185
  /** The names `fields` / `exact` may use, and whether such a list is declared at all. */
5851
6186
  outputNamesFor(kind, stepId) {
5852
6187
  if (kind === "final") {
5853
- const out = own2(this.flow, "output");
6188
+ const out = own3(this.flow, "output");
5854
6189
  const names2 = [];
5855
6190
  if (Array.isArray(out)) {
5856
6191
  out.forEach((item, i) => {
@@ -5859,10 +6194,10 @@ var Walker = class _Walker {
5859
6194
  }
5860
6195
  return { names: names2, declared: names2.length > 0 };
5861
6196
  }
5862
- const steps = own2(this.flow, "steps");
5863
- const step = isRecord(steps) ? own2(steps, stepId) : void 0;
5864
- const schema = isRecord(step) ? own2(step, "output_schema") : void 0;
5865
- const fields = isRecord(schema) ? own2(schema, "fields") : void 0;
6197
+ const steps = own3(this.flow, "steps");
6198
+ const step = isRecord(steps) ? own3(steps, stepId) : void 0;
6199
+ const schema = isRecord(step) ? own3(step, "output_schema") : void 0;
6200
+ const fields = isRecord(schema) ? own3(schema, "fields") : void 0;
5866
6201
  if (!Array.isArray(fields) || fields.length === 0) return { names: [], declared: false };
5867
6202
  const names = [];
5868
6203
  fields.forEach((f, i) => {
@@ -5881,8 +6216,8 @@ var Walker = class _Walker {
5881
6216
  );
5882
6217
  }
5883
6218
  const noOutput = status === STATUS_FAILED || status === STATUS_PAUSED_FOR_HUMAN;
5884
- const fieldsRec = own2(e, "fields");
5885
- const exactRec = own2(e, "exact");
6219
+ const fieldsRec = own3(e, "fields");
6220
+ const exactRec = own3(e, "exact");
5886
6221
  const fieldKeys = isRecord(fieldsRec) ? sortedKeys(fieldsRec) : [];
5887
6222
  const exactKeys = isRecord(exactRec) ? sortedKeys(exactRec) : [];
5888
6223
  const hasFields = fieldKeys.length > 0;
@@ -5900,7 +6235,7 @@ var Walker = class _Walker {
5900
6235
  `a case that ends in ${status} has no output to match; remove fields and exact, or expect status completed`
5901
6236
  );
5902
6237
  }
5903
- const minScore = numberOf(own2(e, "min_score"));
6238
+ const minScore = numberOf(own3(e, "min_score"));
5904
6239
  if (minScore !== void 0 && !scoreInRange(minScore)) {
5905
6240
  this.err(
5906
6241
  "example_min_score_range",
@@ -5927,7 +6262,7 @@ var Walker = class _Walker {
5927
6262
  }
5928
6263
  }
5929
6264
  }
5930
- const reference = own2(e, "reference");
6265
+ const reference = own3(e, "reference");
5931
6266
  if (isRecord(reference)) this.validateReference(`${path}.reference`, reference);
5932
6267
  const { names, declared } = this.outputNamesFor(kind, stepId);
5933
6268
  const checkKey = (field, key) => {
@@ -5954,12 +6289,12 @@ var Walker = class _Walker {
5954
6289
  for (const key of fieldKeys) {
5955
6290
  const fpath = `${path}.fields.${key}`;
5956
6291
  checkKey(fpath, key);
5957
- const matcher = own2(fieldsRec, key);
6292
+ const matcher = own3(fieldsRec, key);
5958
6293
  if (isRecord(matcher)) this.validateFieldMatcher(fpath, matcher);
5959
6294
  }
5960
6295
  for (const key of exactKeys) checkKey(`${path}.exact.${key}`, key);
5961
- const mustNot = this.stringList(own2(e, "must_not"), `${path}.must_not`);
5962
- const mustNotContain = this.stringList(own2(e, "must_not_contain"), `${path}.must_not_contain`);
6296
+ const mustNot = this.stringList(own3(e, "must_not"), `${path}.must_not`);
6297
+ const mustNotContain = this.stringList(own3(e, "must_not_contain"), `${path}.must_not_contain`);
5963
6298
  const mustNotMsg = `must_not takes up to ${L.maxMustNot} statements of at most ${L.maxMustNotRunes} characters each, none empty`;
5964
6299
  if (mustNot.length > L.maxMustNot) {
5965
6300
  this.err("example_must_not_invalid", `${path}.must_not`, mustNotMsg);
@@ -5980,9 +6315,9 @@ var Walker = class _Walker {
5980
6315
  }
5981
6316
  });
5982
6317
  for (const key of fieldKeys) {
5983
- const matcher = own2(fieldsRec, key);
6318
+ const matcher = own3(fieldsRec, key);
5984
6319
  if (!isRecord(matcher)) continue;
5985
- const eq = own2(matcher, "equals");
6320
+ const eq = own3(matcher, "equals");
5986
6321
  if (typeof eq !== "string" || eq === "") continue;
5987
6322
  for (const banned of mustNotContain) {
5988
6323
  if (banned !== "" && equalFold(banned, eq)) {
@@ -6042,7 +6377,7 @@ var Walker = class _Walker {
6042
6377
  }
6043
6378
  return;
6044
6379
  }
6045
- const refRec = own2(r, "ref");
6380
+ const refRec = own3(r, "ref");
6046
6381
  if (!isRecord(refRec)) return;
6047
6382
  const ref = this.fileRefOf(refRec, `${path}.ref`);
6048
6383
  this.validateFileRef(`${path}.ref`, ref);
@@ -6055,22 +6390,22 @@ var Walker = class _Walker {
6055
6390
  }
6056
6391
  }
6057
6392
  expectationIsBinaryReferenceOnly(e, path) {
6058
- const reference = own2(e, "reference");
6059
- const refRec = isRecord(reference) ? own2(reference, "ref") : void 0;
6393
+ const reference = own3(e, "reference");
6394
+ const refRec = isRecord(reference) ? own3(reference, "ref") : void 0;
6060
6395
  if (!isRecord(refRec)) return false;
6061
6396
  const mediaType = this.s(refRec, "media_type", `${path}.reference.ref`);
6062
6397
  if (mediaType === "" || isTextualMediaType(mediaType)) return false;
6063
6398
  const status = this.s(e, "status", path);
6064
- const fields = own2(e, "fields");
6065
- const exact = own2(e, "exact");
6066
- return this.s(e, "rubric", path) === "" && !(isRecord(fields) && Object.keys(fields).length > 0) && !(isRecord(exact) && Object.keys(exact).length > 0) && this.stringList(own2(e, "must_not"), `${path}.must_not`).length === 0 && this.stringList(own2(e, "must_not_contain"), `${path}.must_not_contain`).length === 0 && (status === "" || status === STATUS_COMPLETED);
6399
+ const fields = own3(e, "fields");
6400
+ const exact = own3(e, "exact");
6401
+ return this.s(e, "rubric", path) === "" && !(isRecord(fields) && Object.keys(fields).length > 0) && !(isRecord(exact) && Object.keys(exact).length > 0) && this.stringList(own3(e, "must_not"), `${path}.must_not`).length === 0 && this.stringList(own3(e, "must_not_contain"), `${path}.must_not_contain`).length === 0 && (status === "" || status === STATUS_COMPLETED);
6067
6402
  }
6068
6403
  validateFieldMatcher(path, m) {
6069
6404
  const L = EXAMPLES.limits;
6070
6405
  const matches = this.s(m, "matches", path);
6071
- const oneOf = own2(m, "one_of");
6072
- const approx = numberOf(own2(m, "approx"));
6073
- const tolerance = numberOf(own2(m, "tolerance"));
6406
+ const oneOf = own3(m, "one_of");
6407
+ const approx = numberOf(own3(m, "approx"));
6408
+ const tolerance = numberOf(own3(m, "tolerance"));
6074
6409
  let operators = 0;
6075
6410
  if (has(m, "equals")) operators++;
6076
6411
  if (this.s(m, "contains", path) !== "") operators++;
@@ -6078,7 +6413,7 @@ var Walker = class _Walker {
6078
6413
  if (matches !== "") operators++;
6079
6414
  if (Array.isArray(oneOf) && oneOf.length > 0) operators++;
6080
6415
  if (approx !== void 0) operators++;
6081
- if (typeof own2(m, "present") === "boolean") operators++;
6416
+ if (typeof own3(m, "present") === "boolean") operators++;
6082
6417
  if (operators !== 1) {
6083
6418
  this.err(
6084
6419
  "example_field_matcher_invalid",
@@ -6105,12 +6440,12 @@ var Walker = class _Walker {
6105
6440
  // -- checkpoints ------------------------------------------------------
6106
6441
  validateCheckpoints(path, label, cps) {
6107
6442
  if (!isRecord(cps) || Object.keys(cps).length === 0) return;
6108
- const stepsRaw = own2(this.flow, "steps");
6443
+ const stepsRaw = own3(this.flow, "steps");
6109
6444
  const steps = isRecord(stepsRaw) ? stepsRaw : {};
6110
6445
  const stepIds = sortedKeys(steps);
6111
6446
  for (const id of sortedKeys(cps)) {
6112
6447
  const cpath = `${path}.checkpoints.${id}`;
6113
- const step = own2(steps, id);
6448
+ const step = own3(steps, id);
6114
6449
  if (!isRecord(step)) {
6115
6450
  this.err(
6116
6451
  "example_checkpoint_step_unknown",
@@ -6120,7 +6455,7 @@ var Walker = class _Walker {
6120
6455
  );
6121
6456
  continue;
6122
6457
  }
6123
- const next = own2(step, "next");
6458
+ const next = own3(step, "next");
6124
6459
  if (has(step, "for_each") || has(step, "loop") || isRecord(next) && has(next, "parallel")) {
6125
6460
  this.err(
6126
6461
  "example_checkpoint_step_composite",
@@ -6129,7 +6464,7 @@ var Walker = class _Walker {
6129
6464
  );
6130
6465
  continue;
6131
6466
  }
6132
- const cp = own2(cps, id);
6467
+ const cp = own3(cps, id);
6133
6468
  if (cp === null || cp === void 0) {
6134
6469
  this.validateExpectation(cpath, label, {}, "checkpoint", id);
6135
6470
  } else if (isRecord(cp)) {
@@ -6140,7 +6475,7 @@ var Walker = class _Walker {
6140
6475
  // -- variants ---------------------------------------------------------
6141
6476
  validateVariants(i, path, label, ex, hasInput, baseInput) {
6142
6477
  const L = EXAMPLES.limits;
6143
- const variants = own2(ex, "variants");
6478
+ const variants = own3(ex, "variants");
6144
6479
  if (!Array.isArray(variants) || variants.length === 0) return;
6145
6480
  if (variants.length > L.maxVariants) {
6146
6481
  this.err(
@@ -6203,8 +6538,8 @@ var Walker = class _Walker {
6203
6538
  `example ${q(both)} notes are ${provN} characters; the limit is ${L.maxProvenanceRunes}`
6204
6539
  );
6205
6540
  }
6206
- this.validateWeight(`${vpath}.weight`, both, numberOf(own2(v, "weight")));
6207
- const patch = own2(v, "input_patch");
6541
+ this.validateWeight(`${vpath}.weight`, both, numberOf(own3(v, "weight")));
6542
+ const patch = own3(v, "input_patch");
6208
6543
  const patchRec = isRecord(patch) ? patch : null;
6209
6544
  const hasPatch = patchRec !== null && Object.keys(patchRec).length > 0;
6210
6545
  const hasRef = has(v, "input_ref");
@@ -6221,7 +6556,7 @@ var Walker = class _Walker {
6221
6556
  `variant ${q(vlabel)} of example ${q(label)} changes neither the input nor the expectation`
6222
6557
  );
6223
6558
  }
6224
- const refRec = own2(v, "input_ref");
6559
+ const refRec = own3(v, "input_ref");
6225
6560
  if (isRecord(refRec)) {
6226
6561
  this.validateFileRef(`${vpath}.input_ref`, this.fileRefOf(refRec, `${vpath}.input_ref`));
6227
6562
  }
@@ -6236,7 +6571,7 @@ var Walker = class _Walker {
6236
6571
  this.checkVariantPatch(vpath, label, vlabel, baseInput, patchRec);
6237
6572
  }
6238
6573
  }
6239
- const expected = own2(v, "expected");
6574
+ const expected = own3(v, "expected");
6240
6575
  if (isRecord(expected)) {
6241
6576
  this.validateExpectation(`${vpath}.expected`, both, expected, "final", "");
6242
6577
  }
@@ -6247,11 +6582,11 @@ var Walker = class _Walker {
6247
6582
  * itself supplies. A null patch value deleting a secret is fine.
6248
6583
  */
6249
6584
  checkVariantPatch(vpath, label, vlabel, base, patch) {
6250
- const schema = own2(this.flow, "input_schema");
6585
+ const schema = own3(this.flow, "input_schema");
6251
6586
  if (isRecord(schema)) {
6252
6587
  for (const f of this.schemaFields(schema)) {
6253
6588
  if (f.type !== TYPE_SECRET) continue;
6254
- const val = own2(patch, f.name);
6589
+ const val = own3(patch, f.name);
6255
6590
  if (val !== void 0 && val !== null) {
6256
6591
  this.err(
6257
6592
  "example_secret_value",
@@ -6291,18 +6626,18 @@ var Walker = class _Walker {
6291
6626
  emit(`${path}.title`, this.s(ex, "title", path));
6292
6627
  emit(`${path}.guidance`, this.s(ex, "guidance", path));
6293
6628
  emit(`${path}.notes`, this.s(ex, "notes", path));
6294
- const input = own2(ex, "input");
6629
+ const input = own3(ex, "input");
6295
6630
  if (isRecord(input)) scanLeaves(`${path}.input`, input, 0, emit);
6296
- const expected = own2(ex, "expected");
6631
+ const expected = own3(ex, "expected");
6297
6632
  if (isRecord(expected)) this.scanExpectationLeaves(`${path}.expected`, expected, emit);
6298
- const cps = own2(ex, "checkpoints");
6633
+ const cps = own3(ex, "checkpoints");
6299
6634
  if (isRecord(cps)) {
6300
6635
  for (const id of sortedKeys(cps)) {
6301
- const cp = own2(cps, id);
6636
+ const cp = own3(cps, id);
6302
6637
  if (isRecord(cp)) this.scanExpectationLeaves(`${path}.checkpoints.${id}`, cp, emit);
6303
6638
  }
6304
6639
  }
6305
- const variants = own2(ex, "variants");
6640
+ const variants = own3(ex, "variants");
6306
6641
  if (Array.isArray(variants)) {
6307
6642
  variants.forEach((v, j) => {
6308
6643
  if (!isRecord(v)) return;
@@ -6310,34 +6645,34 @@ var Walker = class _Walker {
6310
6645
  emit(`${vpath}.title`, this.s(v, "title", vpath));
6311
6646
  emit(`${vpath}.guidance`, this.s(v, "guidance", vpath));
6312
6647
  emit(`${vpath}.provenance`, this.s(v, "provenance", vpath));
6313
- scanLeaves(`${vpath}.input_patch`, own2(v, "input_patch"), 0, emit);
6314
- const vexp = own2(v, "expected");
6648
+ scanLeaves(`${vpath}.input_patch`, own3(v, "input_patch"), 0, emit);
6649
+ const vexp = own3(v, "expected");
6315
6650
  if (isRecord(vexp)) this.scanExpectationLeaves(`${vpath}.expected`, vexp, emit);
6316
6651
  });
6317
6652
  }
6318
6653
  }
6319
6654
  scanExpectationLeaves(path, e, emit) {
6320
6655
  emit(`${path}.rubric`, this.s(e, "rubric", path));
6321
- const reference = own2(e, "reference");
6656
+ const reference = own3(e, "reference");
6322
6657
  if (isRecord(reference)) {
6323
6658
  emit(`${path}.reference.text`, this.s(reference, "text", `${path}.reference`));
6324
6659
  }
6325
- this.stringList(own2(e, "must_not"), `${path}.must_not`).forEach(
6660
+ this.stringList(own3(e, "must_not"), `${path}.must_not`).forEach(
6326
6661
  (s, j) => emit(`${path}.must_not[${j}]`, s)
6327
6662
  );
6328
- this.stringList(own2(e, "must_not_contain"), `${path}.must_not_contain`).forEach(
6663
+ this.stringList(own3(e, "must_not_contain"), `${path}.must_not_contain`).forEach(
6329
6664
  (s, j) => emit(`${path}.must_not_contain[${j}]`, s)
6330
6665
  );
6331
- const fields = own2(e, "fields");
6666
+ const fields = own3(e, "fields");
6332
6667
  if (isRecord(fields)) {
6333
6668
  for (const key of sortedKeys(fields)) {
6334
- const m = own2(fields, key);
6669
+ const m = own3(fields, key);
6335
6670
  if (!isRecord(m)) continue;
6336
6671
  const fpath = `${path}.fields.${key}`;
6337
- scanLeaves(`${fpath}.equals`, own2(m, "equals"), 0, emit);
6672
+ scanLeaves(`${fpath}.equals`, own3(m, "equals"), 0, emit);
6338
6673
  emit(`${fpath}.contains`, this.s(m, "contains", fpath));
6339
6674
  emit(`${fpath}.not_contains`, this.s(m, "not_contains", fpath));
6340
- const oneOf = own2(m, "one_of");
6675
+ const oneOf = own3(m, "one_of");
6341
6676
  if (Array.isArray(oneOf)) {
6342
6677
  oneOf.forEach(
6343
6678
  (one, j) => scanLeaves(`${fpath}.one_of[${j}]`, one, 0, emit)
@@ -6345,7 +6680,7 @@ var Walker = class _Walker {
6345
6680
  }
6346
6681
  }
6347
6682
  }
6348
- scanLeaves(`${path}.exact`, own2(e, "exact"), 0, emit);
6683
+ scanLeaves(`${path}.exact`, own3(e, "exact"), 0, emit);
6349
6684
  }
6350
6685
  };
6351
6686
  function scoreInRange(v) {
@@ -6461,7 +6796,7 @@ function inputValueFailures(f, raw) {
6461
6796
  case TYPE_FILE2: {
6462
6797
  if (typeof raw === "string") return raw === "" ? [mismatch(f, TYPE_FILE2)] : [];
6463
6798
  if (isRecord(raw)) {
6464
- const ref = own2(raw, FILE_REF_KEY);
6799
+ const ref = own3(raw, FILE_REF_KEY);
6465
6800
  return typeof ref === "string" && ref !== "" ? [] : [mismatch(f, TYPE_FILE2)];
6466
6801
  }
6467
6802
  return [mismatch(f, TYPE_FILE2)];
@@ -6544,6 +6879,7 @@ function validateParsed(flow, opts, sources) {
6544
6879
  validateCredentialEndpointPairing(f, issues);
6545
6880
  validateExamples(f, issues);
6546
6881
  validateOrchestratorExons(f, issues);
6882
+ validateResidencyEnforcement(f, issues);
6547
6883
  validateUnknownKeys(f, issues);
6548
6884
  const templateStats = validateTemplates(f, issues, opts);
6549
6885
  const totalSteps = f.steps && typeof f.steps === "object" && !Array.isArray(f.steps) ? Object.keys(f.steps).length : 0;