@vaudience/aigentflow-flow-validator 0.18.0 → 0.20.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
@@ -430,7 +430,7 @@ function validateBasicStructure(flow, issues) {
430
430
 
431
431
  // src/spec/aigentflow-spec.json
432
432
  var aigentflow_spec_default = {
433
- specVersion: "2.819.0",
433
+ specVersion: "2.821.0",
434
434
  inputSchemaVersion: 1,
435
435
  executorSchemes: [
436
436
  "a2a",
@@ -1255,6 +1255,34 @@ var aigentflow_spec_default = {
1255
1255
  }
1256
1256
  }
1257
1257
  },
1258
+ complianceResidency: {
1259
+ code: "compliance_residency_unenforced",
1260
+ euResidencyCodes: ["EU", "DE", "FR", "IE", "NL", "IT", "ES"],
1261
+ regionLaneProviders: [
1262
+ "bedrock",
1263
+ "google",
1264
+ "azure",
1265
+ "openai",
1266
+ "assemblyai",
1267
+ "speechmatics",
1268
+ "deepgram",
1269
+ "mistral"
1270
+ ],
1271
+ aiProtocol: "ai",
1272
+ protocolSeparator: "://",
1273
+ regionParam: "region",
1274
+ enforceRegionParam: "enforce_region",
1275
+ baseUrlParamSuffix: "_base_url",
1276
+ enforceRegionTrueStrings: ["true", "1", "yes"],
1277
+ stepFieldFormat: "steps.%s.executor",
1278
+ loopStepFieldFormat: "steps.%s.loop.steps.%s.executor",
1279
+ orchestratorField: "orchestrator.exons",
1280
+ siteStepFormat: "step %q",
1281
+ siteLoopStepFormat: "loop sub-step %q of step %q",
1282
+ siteOrchestrator: "the orchestrator",
1283
+ 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",
1284
+ 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."
1285
+ },
1258
1286
  examples: {
1259
1287
  limits: {
1260
1288
  maxPerFlow: 50,
@@ -1642,6 +1670,7 @@ var aigentflow_spec_default = {
1642
1670
  deny_tools: "list<scalar>",
1643
1671
  discoverable_tools: "list<scalar>",
1644
1672
  enable_signals: "scalar",
1673
+ enforce_region: "scalar",
1645
1674
  engram_scope: "scalar",
1646
1675
  exons: "scalar",
1647
1676
  human_question_timeout: "scalar",
@@ -1650,6 +1679,7 @@ var aigentflow_spec_default = {
1650
1679
  max_tool_turns: "scalar",
1651
1680
  max_turns: "scalar",
1652
1681
  mode: "scalar",
1682
+ region: "scalar",
1653
1683
  require_approval_for: "list<scalar>",
1654
1684
  timeout_seconds: "scalar",
1655
1685
  tool_discovery: "scalar",
@@ -1848,6 +1878,25 @@ var CREDENTIAL_ENDPOINT_PAIRING = {
1848
1878
  familyKeySeparator: aigentflow_spec_default.credentialEndpointPairing.familyKeySeparator,
1849
1879
  families: aigentflow_spec_default.credentialEndpointPairing.families
1850
1880
  };
1881
+ var COMPLIANCE_RESIDENCY = {
1882
+ code: aigentflow_spec_default.complianceResidency.code,
1883
+ euResidencyCodes: aigentflow_spec_default.complianceResidency.euResidencyCodes,
1884
+ regionLaneProviders: aigentflow_spec_default.complianceResidency.regionLaneProviders,
1885
+ aiProtocol: aigentflow_spec_default.complianceResidency.aiProtocol,
1886
+ protocolSeparator: aigentflow_spec_default.complianceResidency.protocolSeparator,
1887
+ regionParam: aigentflow_spec_default.complianceResidency.regionParam,
1888
+ enforceRegionParam: aigentflow_spec_default.complianceResidency.enforceRegionParam,
1889
+ baseUrlParamSuffix: aigentflow_spec_default.complianceResidency.baseUrlParamSuffix,
1890
+ enforceRegionTrueStrings: aigentflow_spec_default.complianceResidency.enforceRegionTrueStrings,
1891
+ stepFieldFormat: aigentflow_spec_default.complianceResidency.stepFieldFormat,
1892
+ loopStepFieldFormat: aigentflow_spec_default.complianceResidency.loopStepFieldFormat,
1893
+ orchestratorField: aigentflow_spec_default.complianceResidency.orchestratorField,
1894
+ siteStepFormat: aigentflow_spec_default.complianceResidency.siteStepFormat,
1895
+ siteLoopStepFormat: aigentflow_spec_default.complianceResidency.siteLoopStepFormat,
1896
+ siteOrchestrator: aigentflow_spec_default.complianceResidency.siteOrchestrator,
1897
+ messageFormat: aigentflow_spec_default.complianceResidency.messageFormat,
1898
+ suggestion: aigentflow_spec_default.complianceResidency.suggestion
1899
+ };
1851
1900
  var EXAMPLES = {
1852
1901
  limits: aigentflow_spec_default.examples.limits,
1853
1902
  idPattern: new RegExp(aigentflow_spec_default.examples.idPattern),
@@ -3062,6 +3111,17 @@ function validateOrchestratorCampaign(flow, issues, opts) {
3062
3111
  code: "orchestrator_owner_needs_yield"
3063
3112
  });
3064
3113
  }
3114
+ if (orch.enforce_region === true) {
3115
+ const region = issues.stringOf(orch, "region", "orchestrator");
3116
+ if (region === null || region.trim() === "") {
3117
+ issues.error({
3118
+ field: "orchestrator.enforce_region",
3119
+ message: "orchestrator: enforce_region requires region (name the region the model must run in, e.g. region: eu)",
3120
+ code: "orchestrator_enforce_region_needs_region",
3121
+ suggestion: "Add `region: eu` (or the region the model must run in), or drop enforce_region"
3122
+ });
3123
+ }
3124
+ }
3065
3125
  if (Array.isArray(orch.triggers)) {
3066
3126
  orch.triggers.forEach((rawTrigger, i) => {
3067
3127
  if (!isRecord(rawTrigger)) return;
@@ -5189,6 +5249,141 @@ function warnOrchestratorToolWithheld(flow, orch, report, issues) {
5189
5249
  }
5190
5250
  }
5191
5251
 
5252
+ // src/validators/complianceResidency.ts
5253
+ function own2(m, key) {
5254
+ if (!isRecord(m) || !Object.prototype.hasOwnProperty.call(m, key)) return void 0;
5255
+ return m[key];
5256
+ }
5257
+ function sprintf(format, ...args) {
5258
+ let i = 0;
5259
+ return format.replace(/%[sqv]/g, (verb) => {
5260
+ const arg = args[i++] ?? "";
5261
+ return verb === "%q" ? JSON.stringify(arg) : arg;
5262
+ });
5263
+ }
5264
+ function literalOrEmpty(s) {
5265
+ const t = goTrimSpace2(s);
5266
+ return t.includes(TEMPLATE_ACTION_OPEN) ? "" : t;
5267
+ }
5268
+ function euOnlyResidency(flow, issues) {
5269
+ const raw = own2(own2(flow, "compliance"), "residency");
5270
+ if (!isArray(raw)) return null;
5271
+ const codes = [];
5272
+ for (let i = 0; i < raw.length; i++) {
5273
+ if (raw[i] === null) continue;
5274
+ const code = issues.stringAt(raw[i], `compliance.residency[${i}]`);
5275
+ if (code === null) return null;
5276
+ codes.push(code);
5277
+ }
5278
+ if (codes.length === 0) return null;
5279
+ const eu = new Set(COMPLIANCE_RESIDENCY.euResidencyCodes);
5280
+ return codes.every((c) => eu.has(goTrimSpace2(c).toUpperCase())) ? codes : null;
5281
+ }
5282
+ function aiProvider(executor) {
5283
+ const prefix = COMPLIANCE_RESIDENCY.aiProtocol + COMPLIANCE_RESIDENCY.protocolSeparator;
5284
+ if (!executor.startsWith(prefix)) return "";
5285
+ const rest = executor.slice(prefix.length);
5286
+ const slash = rest.indexOf("/");
5287
+ const provider = slash > 0 ? rest.slice(0, slash) : "";
5288
+ return provider.includes(TEMPLATE_ACTION_OPEN) ? "" : provider;
5289
+ }
5290
+ function isRegionLane(provider) {
5291
+ const literal = literalOrEmpty(provider);
5292
+ return literal !== "" && COMPLIANCE_RESIDENCY.regionLaneProviders.includes(literal.toLowerCase());
5293
+ }
5294
+ function nonBlankString(m, key) {
5295
+ const v = own2(m, key);
5296
+ return typeof v === "string" && goTrimSpace2(v) !== "";
5297
+ }
5298
+ function queryEnforcesRegion(query) {
5299
+ const v = own2(query, COMPLIANCE_RESIDENCY.enforceRegionParam);
5300
+ if (typeof v === "boolean") return v;
5301
+ return typeof v === "string" && COMPLIANCE_RESIDENCY.enforceRegionTrueStrings.includes(v);
5302
+ }
5303
+ function flowDirectsEndpoint(flow, provider, issues) {
5304
+ const key = provider.toLowerCase();
5305
+ const inst = own2(own2(flow, "executor_config"), key);
5306
+ if (!isRecord(inst)) return false;
5307
+ const baseUrl = issues.stringOf(inst, "base_url", `executor_config.${key}`);
5308
+ return baseUrl !== null && goTrimSpace2(baseUrl) !== "";
5309
+ }
5310
+ function callPinsEndpoint(flow, provider, query, issues) {
5311
+ if (nonBlankString(query, COMPLIANCE_RESIDENCY.regionParam)) return true;
5312
+ if (queryEnforcesRegion(query)) return true;
5313
+ if (nonBlankString(query, provider.toLowerCase() + COMPLIANCE_RESIDENCY.baseUrlParamSuffix)) return true;
5314
+ return flowDirectsEndpoint(flow, provider, issues);
5315
+ }
5316
+ function validateResidencyEnforcement(flow, issues) {
5317
+ const residency = euOnlyResidency(flow, issues);
5318
+ if (residency === null) return;
5319
+ const warn = (site, field, stepId, provider) => {
5320
+ issues.warn({
5321
+ field,
5322
+ ...stepId === void 0 ? {} : { stepId },
5323
+ code: COMPLIANCE_RESIDENCY.code,
5324
+ message: sprintf(COMPLIANCE_RESIDENCY.messageFormat, site, provider, `[${residency.join(" ")}]`),
5325
+ suggestion: COMPLIANCE_RESIDENCY.suggestion
5326
+ });
5327
+ };
5328
+ const steps = flow.steps;
5329
+ if (isRecord(steps)) {
5330
+ for (const stepId of Object.keys(steps).sort()) {
5331
+ const step = steps[stepId];
5332
+ if (!isRecord(step)) continue;
5333
+ const calls = [
5334
+ {
5335
+ executor: issues.stringOf(step, "executor", `steps.${stepId}`) ?? "",
5336
+ query: own2(step, "query"),
5337
+ subId: null
5338
+ }
5339
+ ];
5340
+ for (const sub of loopSubStepsOfStep(stepId, step)) {
5341
+ calls.push({
5342
+ executor: issues.stringOf(sub.raw, "executor", sub.basePath) ?? "",
5343
+ query: own2(sub.raw, "query"),
5344
+ subId: issues.stringOf(sub.raw, "id", sub.basePath) ?? ""
5345
+ });
5346
+ }
5347
+ for (const call of calls) {
5348
+ const provider = aiProvider(call.executor);
5349
+ if (!isRegionLane(provider)) continue;
5350
+ if (callPinsEndpoint(flow, provider, call.query, issues)) continue;
5351
+ if (call.subId === null) {
5352
+ warn(
5353
+ sprintf(COMPLIANCE_RESIDENCY.siteStepFormat, stepId),
5354
+ sprintf(COMPLIANCE_RESIDENCY.stepFieldFormat, stepId),
5355
+ stepId,
5356
+ provider
5357
+ );
5358
+ } else {
5359
+ warn(
5360
+ sprintf(COMPLIANCE_RESIDENCY.siteLoopStepFormat, call.subId, stepId),
5361
+ sprintf(COMPLIANCE_RESIDENCY.loopStepFieldFormat, stepId, call.subId),
5362
+ stepId,
5363
+ provider
5364
+ );
5365
+ }
5366
+ }
5367
+ }
5368
+ }
5369
+ warnOrchestrator(flow, issues, warn);
5370
+ }
5371
+ function warnOrchestrator(flow, issues, warn) {
5372
+ const orch = flow.orchestrator;
5373
+ if (!isRecord(orch)) return;
5374
+ const source = issues.stringOf(orch, "exons", "orchestrator");
5375
+ if (source === null || source === "") return;
5376
+ const report = inspectExonsFrontmatter(source);
5377
+ if (report.parseError !== null || !report.specRead || !report.hasSpec) return;
5378
+ const provider = literalOrEmpty(report.provider);
5379
+ if (!isRegionLane(provider)) return;
5380
+ const region = issues.stringOf(orch, "region", "orchestrator");
5381
+ if (region !== null && goTrimSpace2(region) !== "") return;
5382
+ if (orch.enforce_region === true) return;
5383
+ if (flowDirectsEndpoint(flow, provider, issues)) return;
5384
+ warn(COMPLIANCE_RESIDENCY.siteOrchestrator, COMPLIANCE_RESIDENCY.orchestratorField, void 0, provider);
5385
+ }
5386
+
5192
5387
  // src/validators/examples.ts
5193
5388
  var KEY_EXAMPLES = "examples";
5194
5389
  var VISIBILITY_PUBLIC = "public";
@@ -5266,7 +5461,7 @@ function num(n) {
5266
5461
  function has(o, key) {
5267
5462
  return Object.prototype.hasOwnProperty.call(o, key) && o[key] !== null && o[key] !== void 0;
5268
5463
  }
5269
- function own2(o, key) {
5464
+ function own3(o, key) {
5270
5465
  return Object.prototype.hasOwnProperty.call(o, key) ? o[key] : void 0;
5271
5466
  }
5272
5467
  function setOwn(o, key, value) {
@@ -5318,7 +5513,7 @@ function mergePatch(target, patch, depth) {
5318
5513
  continue;
5319
5514
  }
5320
5515
  if (isRecord(pv)) {
5321
- const current = own2(target, k);
5516
+ const current = own3(target, k);
5322
5517
  const existing = isRecord(current) ? deepCopy(current, 0) : {};
5323
5518
  mergePatch(existing, pv, depth + 1);
5324
5519
  setOwn(target, k, existing);
@@ -5338,7 +5533,7 @@ function asFileRef(v) {
5338
5533
  if (keys.length === 0) return null;
5339
5534
  for (const k of keys) if (!FILE_REF_KEYS.has(k)) return null;
5340
5535
  const str = (k) => {
5341
- const x = own2(v, k);
5536
+ const x = own3(v, k);
5342
5537
  return typeof x === "string" ? x : "";
5343
5538
  };
5344
5539
  return {
@@ -5406,7 +5601,7 @@ var Walker = class _Walker {
5406
5601
  `the examples block is ${size} bytes; the limit is ${L.maxBlockBytes}. Move large inputs or target outputs to a file reference (https URL).`
5407
5602
  );
5408
5603
  }
5409
- const allHeld = examples.every((e) => isRecord(e) && own2(e, "hold_out") === true);
5604
+ const allHeld = examples.every((e) => isRecord(e) && own3(e, "hold_out") === true);
5410
5605
  if (allHeld) {
5411
5606
  this.warn(
5412
5607
  "examples_all_held_out",
@@ -5494,9 +5689,9 @@ var Walker = class _Walker {
5494
5689
  `example ${q(label)} notes are ${notesN} characters; the limit is ${L.maxNotesRunes}`
5495
5690
  );
5496
5691
  }
5497
- this.validateTags(path, label, own2(ex, "tags"));
5498
- this.validateWeight(`${path}.weight`, label, numberOf(own2(ex, "weight")));
5499
- const minScore = numberOf(own2(ex, "min_score"));
5692
+ this.validateTags(path, label, own3(ex, "tags"));
5693
+ this.validateWeight(`${path}.weight`, label, numberOf(own3(ex, "weight")));
5694
+ const minScore = numberOf(own3(ex, "min_score"));
5500
5695
  if (minScore !== void 0 && !scoreInRange(minScore)) {
5501
5696
  this.err(
5502
5697
  "example_min_score_range",
@@ -5512,7 +5707,7 @@ var Walker = class _Walker {
5512
5707
  `example ${q(label)} has side_effects ${q(sideEffects)}; use refuse or allow`
5513
5708
  );
5514
5709
  }
5515
- const holdOut = own2(ex, "hold_out") === true;
5710
+ const holdOut = own3(ex, "hold_out") === true;
5516
5711
  if (holdOut && this.isPublic()) {
5517
5712
  this.err(
5518
5713
  "example_holdout_in_public_flow",
@@ -5535,17 +5730,17 @@ var Walker = class _Walker {
5535
5730
  `example ${q(label)} has neither input nor input_ref; use input: {} for a flow that takes no input`
5536
5731
  );
5537
5732
  }
5538
- const rawInput = own2(ex, "input");
5733
+ const rawInput = own3(ex, "input");
5539
5734
  const baseInput = isRecord(rawInput) ? rawInput : null;
5540
5735
  if (baseInput !== null) {
5541
5736
  this.checkInput(`${path}.input`, label, baseInput, "example_input_invalid");
5542
5737
  }
5543
- const rawInputRef = own2(ex, "input_ref");
5738
+ const rawInputRef = own3(ex, "input_ref");
5544
5739
  if (isRecord(rawInputRef)) {
5545
5740
  this.validateFileRef(`${path}.input_ref`, this.fileRefOf(rawInputRef, `${path}.input_ref`));
5546
5741
  }
5547
5742
  let binaryOnly = false;
5548
- const expected = own2(ex, "expected");
5743
+ const expected = own3(ex, "expected");
5549
5744
  if (!has(ex, "expected")) {
5550
5745
  this.err(
5551
5746
  "example_expected_missing",
@@ -5564,7 +5759,7 @@ var Walker = class _Walker {
5564
5759
  "this example can be run but not scored"
5565
5760
  );
5566
5761
  }
5567
- this.validateCheckpoints(path, label, own2(ex, "checkpoints"));
5762
+ this.validateCheckpoints(path, label, own3(ex, "checkpoints"));
5568
5763
  this.validateVariants(i, path, label, ex, hasInput, baseInput);
5569
5764
  this.scanSecretLike(i, path, ex);
5570
5765
  }
@@ -5624,8 +5819,8 @@ var Walker = class _Walker {
5624
5819
  );
5625
5820
  return;
5626
5821
  }
5627
- const schema = own2(this.flow, "input_schema");
5628
- const query = own2(this.flow, "query");
5822
+ const schema = own3(this.flow, "input_schema");
5823
+ const query = own3(this.flow, "query");
5629
5824
  if (isRecord(schema)) {
5630
5825
  this.checkInputAgainstSchema(field, label, input, schema, code);
5631
5826
  } else if (isRecord(query) && Object.keys(query).length > 0) {
@@ -5693,29 +5888,29 @@ var Walker = class _Walker {
5693
5888
  }
5694
5889
  }
5695
5890
  schemaFields(schema) {
5696
- const raw = own2(schema, "fields");
5891
+ const raw = own3(schema, "fields");
5697
5892
  if (!Array.isArray(raw)) return [];
5698
5893
  const out = [];
5699
5894
  raw.forEach((f, i) => {
5700
5895
  if (!isRecord(f)) return;
5701
5896
  const base = `input_schema.fields[${i}]`;
5702
- const enumRaw = own2(f, "enum");
5897
+ const enumRaw = own3(f, "enum");
5703
5898
  const enumValues = [];
5704
5899
  if (Array.isArray(enumRaw)) {
5705
5900
  enumRaw.forEach((e, j) => {
5706
5901
  enumValues.push(e === null ? "" : this.issues.stringAt(e, `${base}.enum[${j}]`) ?? "");
5707
5902
  });
5708
5903
  }
5709
- const vw = own2(f, "visible_when");
5904
+ const vw = own3(f, "visible_when");
5710
5905
  out.push({
5711
5906
  name: this.s(f, "name", base),
5712
5907
  type: this.s(f, "type", base),
5713
- required: own2(f, "required") === true,
5908
+ required: own3(f, "required") === true,
5714
5909
  enumValues,
5715
5910
  visibleWhen: isRecord(vw) ? {
5716
5911
  field: this.s(vw, "field", `${base}.visible_when`),
5717
- equals: own2(vw, "equals"),
5718
- in: Array.isArray(own2(vw, "in")) ? own2(vw, "in") : []
5912
+ equals: own3(vw, "equals"),
5913
+ in: Array.isArray(own3(vw, "in")) ? own3(vw, "in") : []
5719
5914
  } : null
5720
5915
  });
5721
5916
  });
@@ -5726,7 +5921,7 @@ var Walker = class _Walker {
5726
5921
  const failures = [];
5727
5922
  for (const f of fields) {
5728
5923
  if (!isVisible(f, runInput)) continue;
5729
- const raw = own2(runInput, f.name);
5924
+ const raw = own3(runInput, f.name);
5730
5925
  if (raw === void 0 || raw === null) {
5731
5926
  if (f.required) {
5732
5927
  failures.push({
@@ -5837,7 +6032,7 @@ var Walker = class _Walker {
5837
6032
  /** The names `fields` / `exact` may use, and whether such a list is declared at all. */
5838
6033
  outputNamesFor(kind, stepId) {
5839
6034
  if (kind === "final") {
5840
- const out = own2(this.flow, "output");
6035
+ const out = own3(this.flow, "output");
5841
6036
  const names2 = [];
5842
6037
  if (Array.isArray(out)) {
5843
6038
  out.forEach((item, i) => {
@@ -5846,10 +6041,10 @@ var Walker = class _Walker {
5846
6041
  }
5847
6042
  return { names: names2, declared: names2.length > 0 };
5848
6043
  }
5849
- const steps = own2(this.flow, "steps");
5850
- const step = isRecord(steps) ? own2(steps, stepId) : void 0;
5851
- const schema = isRecord(step) ? own2(step, "output_schema") : void 0;
5852
- const fields = isRecord(schema) ? own2(schema, "fields") : void 0;
6044
+ const steps = own3(this.flow, "steps");
6045
+ const step = isRecord(steps) ? own3(steps, stepId) : void 0;
6046
+ const schema = isRecord(step) ? own3(step, "output_schema") : void 0;
6047
+ const fields = isRecord(schema) ? own3(schema, "fields") : void 0;
5853
6048
  if (!Array.isArray(fields) || fields.length === 0) return { names: [], declared: false };
5854
6049
  const names = [];
5855
6050
  fields.forEach((f, i) => {
@@ -5868,8 +6063,8 @@ var Walker = class _Walker {
5868
6063
  );
5869
6064
  }
5870
6065
  const noOutput = status === STATUS_FAILED || status === STATUS_PAUSED_FOR_HUMAN;
5871
- const fieldsRec = own2(e, "fields");
5872
- const exactRec = own2(e, "exact");
6066
+ const fieldsRec = own3(e, "fields");
6067
+ const exactRec = own3(e, "exact");
5873
6068
  const fieldKeys = isRecord(fieldsRec) ? sortedKeys(fieldsRec) : [];
5874
6069
  const exactKeys = isRecord(exactRec) ? sortedKeys(exactRec) : [];
5875
6070
  const hasFields = fieldKeys.length > 0;
@@ -5887,7 +6082,7 @@ var Walker = class _Walker {
5887
6082
  `a case that ends in ${status} has no output to match; remove fields and exact, or expect status completed`
5888
6083
  );
5889
6084
  }
5890
- const minScore = numberOf(own2(e, "min_score"));
6085
+ const minScore = numberOf(own3(e, "min_score"));
5891
6086
  if (minScore !== void 0 && !scoreInRange(minScore)) {
5892
6087
  this.err(
5893
6088
  "example_min_score_range",
@@ -5914,7 +6109,7 @@ var Walker = class _Walker {
5914
6109
  }
5915
6110
  }
5916
6111
  }
5917
- const reference = own2(e, "reference");
6112
+ const reference = own3(e, "reference");
5918
6113
  if (isRecord(reference)) this.validateReference(`${path}.reference`, reference);
5919
6114
  const { names, declared } = this.outputNamesFor(kind, stepId);
5920
6115
  const checkKey = (field, key) => {
@@ -5941,12 +6136,12 @@ var Walker = class _Walker {
5941
6136
  for (const key of fieldKeys) {
5942
6137
  const fpath = `${path}.fields.${key}`;
5943
6138
  checkKey(fpath, key);
5944
- const matcher = own2(fieldsRec, key);
6139
+ const matcher = own3(fieldsRec, key);
5945
6140
  if (isRecord(matcher)) this.validateFieldMatcher(fpath, matcher);
5946
6141
  }
5947
6142
  for (const key of exactKeys) checkKey(`${path}.exact.${key}`, key);
5948
- const mustNot = this.stringList(own2(e, "must_not"), `${path}.must_not`);
5949
- const mustNotContain = this.stringList(own2(e, "must_not_contain"), `${path}.must_not_contain`);
6143
+ const mustNot = this.stringList(own3(e, "must_not"), `${path}.must_not`);
6144
+ const mustNotContain = this.stringList(own3(e, "must_not_contain"), `${path}.must_not_contain`);
5950
6145
  const mustNotMsg = `must_not takes up to ${L.maxMustNot} statements of at most ${L.maxMustNotRunes} characters each, none empty`;
5951
6146
  if (mustNot.length > L.maxMustNot) {
5952
6147
  this.err("example_must_not_invalid", `${path}.must_not`, mustNotMsg);
@@ -5967,9 +6162,9 @@ var Walker = class _Walker {
5967
6162
  }
5968
6163
  });
5969
6164
  for (const key of fieldKeys) {
5970
- const matcher = own2(fieldsRec, key);
6165
+ const matcher = own3(fieldsRec, key);
5971
6166
  if (!isRecord(matcher)) continue;
5972
- const eq = own2(matcher, "equals");
6167
+ const eq = own3(matcher, "equals");
5973
6168
  if (typeof eq !== "string" || eq === "") continue;
5974
6169
  for (const banned of mustNotContain) {
5975
6170
  if (banned !== "" && equalFold(banned, eq)) {
@@ -6029,7 +6224,7 @@ var Walker = class _Walker {
6029
6224
  }
6030
6225
  return;
6031
6226
  }
6032
- const refRec = own2(r, "ref");
6227
+ const refRec = own3(r, "ref");
6033
6228
  if (!isRecord(refRec)) return;
6034
6229
  const ref = this.fileRefOf(refRec, `${path}.ref`);
6035
6230
  this.validateFileRef(`${path}.ref`, ref);
@@ -6042,22 +6237,22 @@ var Walker = class _Walker {
6042
6237
  }
6043
6238
  }
6044
6239
  expectationIsBinaryReferenceOnly(e, path) {
6045
- const reference = own2(e, "reference");
6046
- const refRec = isRecord(reference) ? own2(reference, "ref") : void 0;
6240
+ const reference = own3(e, "reference");
6241
+ const refRec = isRecord(reference) ? own3(reference, "ref") : void 0;
6047
6242
  if (!isRecord(refRec)) return false;
6048
6243
  const mediaType = this.s(refRec, "media_type", `${path}.reference.ref`);
6049
6244
  if (mediaType === "" || isTextualMediaType(mediaType)) return false;
6050
6245
  const status = this.s(e, "status", path);
6051
- const fields = own2(e, "fields");
6052
- const exact = own2(e, "exact");
6053
- 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);
6246
+ const fields = own3(e, "fields");
6247
+ const exact = own3(e, "exact");
6248
+ 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);
6054
6249
  }
6055
6250
  validateFieldMatcher(path, m) {
6056
6251
  const L = EXAMPLES.limits;
6057
6252
  const matches = this.s(m, "matches", path);
6058
- const oneOf = own2(m, "one_of");
6059
- const approx = numberOf(own2(m, "approx"));
6060
- const tolerance = numberOf(own2(m, "tolerance"));
6253
+ const oneOf = own3(m, "one_of");
6254
+ const approx = numberOf(own3(m, "approx"));
6255
+ const tolerance = numberOf(own3(m, "tolerance"));
6061
6256
  let operators = 0;
6062
6257
  if (has(m, "equals")) operators++;
6063
6258
  if (this.s(m, "contains", path) !== "") operators++;
@@ -6065,7 +6260,7 @@ var Walker = class _Walker {
6065
6260
  if (matches !== "") operators++;
6066
6261
  if (Array.isArray(oneOf) && oneOf.length > 0) operators++;
6067
6262
  if (approx !== void 0) operators++;
6068
- if (typeof own2(m, "present") === "boolean") operators++;
6263
+ if (typeof own3(m, "present") === "boolean") operators++;
6069
6264
  if (operators !== 1) {
6070
6265
  this.err(
6071
6266
  "example_field_matcher_invalid",
@@ -6092,12 +6287,12 @@ var Walker = class _Walker {
6092
6287
  // -- checkpoints ------------------------------------------------------
6093
6288
  validateCheckpoints(path, label, cps) {
6094
6289
  if (!isRecord(cps) || Object.keys(cps).length === 0) return;
6095
- const stepsRaw = own2(this.flow, "steps");
6290
+ const stepsRaw = own3(this.flow, "steps");
6096
6291
  const steps = isRecord(stepsRaw) ? stepsRaw : {};
6097
6292
  const stepIds = sortedKeys(steps);
6098
6293
  for (const id of sortedKeys(cps)) {
6099
6294
  const cpath = `${path}.checkpoints.${id}`;
6100
- const step = own2(steps, id);
6295
+ const step = own3(steps, id);
6101
6296
  if (!isRecord(step)) {
6102
6297
  this.err(
6103
6298
  "example_checkpoint_step_unknown",
@@ -6107,7 +6302,7 @@ var Walker = class _Walker {
6107
6302
  );
6108
6303
  continue;
6109
6304
  }
6110
- const next = own2(step, "next");
6305
+ const next = own3(step, "next");
6111
6306
  if (has(step, "for_each") || has(step, "loop") || isRecord(next) && has(next, "parallel")) {
6112
6307
  this.err(
6113
6308
  "example_checkpoint_step_composite",
@@ -6116,7 +6311,7 @@ var Walker = class _Walker {
6116
6311
  );
6117
6312
  continue;
6118
6313
  }
6119
- const cp = own2(cps, id);
6314
+ const cp = own3(cps, id);
6120
6315
  if (cp === null || cp === void 0) {
6121
6316
  this.validateExpectation(cpath, label, {}, "checkpoint", id);
6122
6317
  } else if (isRecord(cp)) {
@@ -6127,7 +6322,7 @@ var Walker = class _Walker {
6127
6322
  // -- variants ---------------------------------------------------------
6128
6323
  validateVariants(i, path, label, ex, hasInput, baseInput) {
6129
6324
  const L = EXAMPLES.limits;
6130
- const variants = own2(ex, "variants");
6325
+ const variants = own3(ex, "variants");
6131
6326
  if (!Array.isArray(variants) || variants.length === 0) return;
6132
6327
  if (variants.length > L.maxVariants) {
6133
6328
  this.err(
@@ -6190,8 +6385,8 @@ var Walker = class _Walker {
6190
6385
  `example ${q(both)} notes are ${provN} characters; the limit is ${L.maxProvenanceRunes}`
6191
6386
  );
6192
6387
  }
6193
- this.validateWeight(`${vpath}.weight`, both, numberOf(own2(v, "weight")));
6194
- const patch = own2(v, "input_patch");
6388
+ this.validateWeight(`${vpath}.weight`, both, numberOf(own3(v, "weight")));
6389
+ const patch = own3(v, "input_patch");
6195
6390
  const patchRec = isRecord(patch) ? patch : null;
6196
6391
  const hasPatch = patchRec !== null && Object.keys(patchRec).length > 0;
6197
6392
  const hasRef = has(v, "input_ref");
@@ -6208,7 +6403,7 @@ var Walker = class _Walker {
6208
6403
  `variant ${q(vlabel)} of example ${q(label)} changes neither the input nor the expectation`
6209
6404
  );
6210
6405
  }
6211
- const refRec = own2(v, "input_ref");
6406
+ const refRec = own3(v, "input_ref");
6212
6407
  if (isRecord(refRec)) {
6213
6408
  this.validateFileRef(`${vpath}.input_ref`, this.fileRefOf(refRec, `${vpath}.input_ref`));
6214
6409
  }
@@ -6223,7 +6418,7 @@ var Walker = class _Walker {
6223
6418
  this.checkVariantPatch(vpath, label, vlabel, baseInput, patchRec);
6224
6419
  }
6225
6420
  }
6226
- const expected = own2(v, "expected");
6421
+ const expected = own3(v, "expected");
6227
6422
  if (isRecord(expected)) {
6228
6423
  this.validateExpectation(`${vpath}.expected`, both, expected, "final", "");
6229
6424
  }
@@ -6234,11 +6429,11 @@ var Walker = class _Walker {
6234
6429
  * itself supplies. A null patch value deleting a secret is fine.
6235
6430
  */
6236
6431
  checkVariantPatch(vpath, label, vlabel, base, patch) {
6237
- const schema = own2(this.flow, "input_schema");
6432
+ const schema = own3(this.flow, "input_schema");
6238
6433
  if (isRecord(schema)) {
6239
6434
  for (const f of this.schemaFields(schema)) {
6240
6435
  if (f.type !== TYPE_SECRET) continue;
6241
- const val = own2(patch, f.name);
6436
+ const val = own3(patch, f.name);
6242
6437
  if (val !== void 0 && val !== null) {
6243
6438
  this.err(
6244
6439
  "example_secret_value",
@@ -6278,18 +6473,18 @@ var Walker = class _Walker {
6278
6473
  emit(`${path}.title`, this.s(ex, "title", path));
6279
6474
  emit(`${path}.guidance`, this.s(ex, "guidance", path));
6280
6475
  emit(`${path}.notes`, this.s(ex, "notes", path));
6281
- const input = own2(ex, "input");
6476
+ const input = own3(ex, "input");
6282
6477
  if (isRecord(input)) scanLeaves(`${path}.input`, input, 0, emit);
6283
- const expected = own2(ex, "expected");
6478
+ const expected = own3(ex, "expected");
6284
6479
  if (isRecord(expected)) this.scanExpectationLeaves(`${path}.expected`, expected, emit);
6285
- const cps = own2(ex, "checkpoints");
6480
+ const cps = own3(ex, "checkpoints");
6286
6481
  if (isRecord(cps)) {
6287
6482
  for (const id of sortedKeys(cps)) {
6288
- const cp = own2(cps, id);
6483
+ const cp = own3(cps, id);
6289
6484
  if (isRecord(cp)) this.scanExpectationLeaves(`${path}.checkpoints.${id}`, cp, emit);
6290
6485
  }
6291
6486
  }
6292
- const variants = own2(ex, "variants");
6487
+ const variants = own3(ex, "variants");
6293
6488
  if (Array.isArray(variants)) {
6294
6489
  variants.forEach((v, j) => {
6295
6490
  if (!isRecord(v)) return;
@@ -6297,34 +6492,34 @@ var Walker = class _Walker {
6297
6492
  emit(`${vpath}.title`, this.s(v, "title", vpath));
6298
6493
  emit(`${vpath}.guidance`, this.s(v, "guidance", vpath));
6299
6494
  emit(`${vpath}.provenance`, this.s(v, "provenance", vpath));
6300
- scanLeaves(`${vpath}.input_patch`, own2(v, "input_patch"), 0, emit);
6301
- const vexp = own2(v, "expected");
6495
+ scanLeaves(`${vpath}.input_patch`, own3(v, "input_patch"), 0, emit);
6496
+ const vexp = own3(v, "expected");
6302
6497
  if (isRecord(vexp)) this.scanExpectationLeaves(`${vpath}.expected`, vexp, emit);
6303
6498
  });
6304
6499
  }
6305
6500
  }
6306
6501
  scanExpectationLeaves(path, e, emit) {
6307
6502
  emit(`${path}.rubric`, this.s(e, "rubric", path));
6308
- const reference = own2(e, "reference");
6503
+ const reference = own3(e, "reference");
6309
6504
  if (isRecord(reference)) {
6310
6505
  emit(`${path}.reference.text`, this.s(reference, "text", `${path}.reference`));
6311
6506
  }
6312
- this.stringList(own2(e, "must_not"), `${path}.must_not`).forEach(
6507
+ this.stringList(own3(e, "must_not"), `${path}.must_not`).forEach(
6313
6508
  (s, j) => emit(`${path}.must_not[${j}]`, s)
6314
6509
  );
6315
- this.stringList(own2(e, "must_not_contain"), `${path}.must_not_contain`).forEach(
6510
+ this.stringList(own3(e, "must_not_contain"), `${path}.must_not_contain`).forEach(
6316
6511
  (s, j) => emit(`${path}.must_not_contain[${j}]`, s)
6317
6512
  );
6318
- const fields = own2(e, "fields");
6513
+ const fields = own3(e, "fields");
6319
6514
  if (isRecord(fields)) {
6320
6515
  for (const key of sortedKeys(fields)) {
6321
- const m = own2(fields, key);
6516
+ const m = own3(fields, key);
6322
6517
  if (!isRecord(m)) continue;
6323
6518
  const fpath = `${path}.fields.${key}`;
6324
- scanLeaves(`${fpath}.equals`, own2(m, "equals"), 0, emit);
6519
+ scanLeaves(`${fpath}.equals`, own3(m, "equals"), 0, emit);
6325
6520
  emit(`${fpath}.contains`, this.s(m, "contains", fpath));
6326
6521
  emit(`${fpath}.not_contains`, this.s(m, "not_contains", fpath));
6327
- const oneOf = own2(m, "one_of");
6522
+ const oneOf = own3(m, "one_of");
6328
6523
  if (Array.isArray(oneOf)) {
6329
6524
  oneOf.forEach(
6330
6525
  (one, j) => scanLeaves(`${fpath}.one_of[${j}]`, one, 0, emit)
@@ -6332,7 +6527,7 @@ var Walker = class _Walker {
6332
6527
  }
6333
6528
  }
6334
6529
  }
6335
- scanLeaves(`${path}.exact`, own2(e, "exact"), 0, emit);
6530
+ scanLeaves(`${path}.exact`, own3(e, "exact"), 0, emit);
6336
6531
  }
6337
6532
  };
6338
6533
  function scoreInRange(v) {
@@ -6448,7 +6643,7 @@ function inputValueFailures(f, raw) {
6448
6643
  case TYPE_FILE2: {
6449
6644
  if (typeof raw === "string") return raw === "" ? [mismatch(f, TYPE_FILE2)] : [];
6450
6645
  if (isRecord(raw)) {
6451
- const ref = own2(raw, FILE_REF_KEY);
6646
+ const ref = own3(raw, FILE_REF_KEY);
6452
6647
  return typeof ref === "string" && ref !== "" ? [] : [mismatch(f, TYPE_FILE2)];
6453
6648
  }
6454
6649
  return [mismatch(f, TYPE_FILE2)];
@@ -6531,6 +6726,7 @@ function validateParsed(flow, opts, sources) {
6531
6726
  validateCredentialEndpointPairing(f, issues);
6532
6727
  validateExamples(f, issues);
6533
6728
  validateOrchestratorExons(f, issues);
6729
+ validateResidencyEnforcement(f, issues);
6534
6730
  validateUnknownKeys(f, issues);
6535
6731
  const templateStats = validateTemplates(f, issues, opts);
6536
6732
  const totalSteps = f.steps && typeof f.steps === "object" && !Array.isArray(f.steps) ? Object.keys(f.steps).length : 0;