agent-contracts 0.11.5 → 0.11.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1234,7 +1234,9 @@ Checks:
1234
1234
  Checks:
1235
1235
 
1236
1236
  * bidirectional consistency
1237
- * validation coverage
1237
+ * validation coverage — warns when artifacts lack validations or have empty `required_validations` (fails under `--strict`)
1238
+ * artifact-required-validation wiring — verifies every entry in `artifact.required_validations` exists, targets the correct artifact, and is referenced in a workflow step or task
1239
+ * task-output-validation completeness — checks that tasks producing artifacts (via `execution_steps.produces_artifact` or agent `can_write_artifacts`) cover those artifacts' `required_validations`
1238
1240
  * workflow graph completeness
1239
1241
  * merge integrity
1240
1242
  * read-only write violations
@@ -1244,6 +1246,10 @@ Checks:
1244
1246
  * YAML safety — warns when YAML 1.1 reserved words (`on`, `yes`, `no`, `true`, `false`, etc.) are used in positions where they may be misinterpreted by non-1.2 parsers
1245
1247
  * naming/style issues through Spectral rules
1246
1248
 
1249
+ #### `--strict` mode
1250
+
1251
+ When `--strict` is passed to `lint` or `check`, warnings are treated as failures (exit code 1). This is particularly relevant for artifact-centric validation rules — empty `required_validations`, orphaned validation wiring, and incomplete task coverage are all warnings that become blocking under `--strict`.
1252
+
1247
1253
  ---
1248
1254
 
1249
1255
  ## Best used with runtime frameworks
package/dist/cli.js CHANGED
@@ -52288,6 +52288,7 @@ var validationCoverageRule = {
52288
52288
  }
52289
52289
  validationsByArtifact.get(val.target_artifact).add(val.kind);
52290
52290
  }
52291
+ const strictArtifactTypes = ["code", "config", "schema"];
52291
52292
  for (const [artId, art] of Object.entries(dsl.artifacts)) {
52292
52293
  const kinds = validationsByArtifact.get(artId);
52293
52294
  if (!kinds || kinds.size === 0) {
@@ -52299,8 +52300,7 @@ var validationCoverageRule = {
52299
52300
  });
52300
52301
  continue;
52301
52302
  }
52302
- const mechanicalTypes = ["code", "config", "schema"];
52303
- if (mechanicalTypes.includes(art.type) && !kinds.has("mechanical") && !kinds.has("schema")) {
52303
+ if (strictArtifactTypes.includes(art.type) && !kinds.has("mechanical") && !kinds.has("schema")) {
52304
52304
  diagnostics.push({
52305
52305
  ruleId: "validation-coverage",
52306
52306
  severity: "warning",
@@ -52309,6 +52309,16 @@ var validationCoverageRule = {
52309
52309
  });
52310
52310
  }
52311
52311
  }
52312
+ for (const [artId, art] of Object.entries(dsl.artifacts)) {
52313
+ if (art.required_validations.length === 0) {
52314
+ diagnostics.push({
52315
+ ruleId: "validation-coverage",
52316
+ severity: "warning",
52317
+ path: `artifacts.${artId}`,
52318
+ message: `Artifact "${artId}" has empty required_validations`
52319
+ });
52320
+ }
52321
+ }
52312
52322
  const referencedValidations = /* @__PURE__ */ new Set();
52313
52323
  for (const wf of Object.values(dsl.workflow)) {
52314
52324
  for (const step of wf.steps) {
@@ -52695,6 +52705,101 @@ var yamlReservedKeySafetyRule = {
52695
52705
  }
52696
52706
  };
52697
52707
 
52708
+ // src/linter/rules/artifact-required-validation-wiring.ts
52709
+ var artifactRequiredValidationWiringRule = {
52710
+ id: "artifact-required-validation-wiring",
52711
+ description: "Every validation listed in artifact.required_validations must exist, target the artifact, and be referenced in a workflow step or task.",
52712
+ run(dsl) {
52713
+ const diagnostics = [];
52714
+ const referencedValidations = /* @__PURE__ */ new Set();
52715
+ for (const wf of Object.values(dsl.workflow)) {
52716
+ for (const step of wf.steps) {
52717
+ if (step.type === "validation") {
52718
+ referencedValidations.add(step.validation);
52719
+ }
52720
+ }
52721
+ }
52722
+ for (const task of Object.values(dsl.tasks)) {
52723
+ for (const valId of task.validations) {
52724
+ referencedValidations.add(valId);
52725
+ }
52726
+ }
52727
+ for (const [artId, art] of Object.entries(dsl.artifacts)) {
52728
+ for (const reqValId of art.required_validations) {
52729
+ const val = dsl.validations[reqValId];
52730
+ if (!val) {
52731
+ diagnostics.push({
52732
+ ruleId: "artifact-required-validation-wiring",
52733
+ severity: "error",
52734
+ path: `artifacts.${artId}`,
52735
+ message: `required_validation "${reqValId}" does not exist in validations`
52736
+ });
52737
+ continue;
52738
+ }
52739
+ if (val.target_artifact !== artId) {
52740
+ diagnostics.push({
52741
+ ruleId: "artifact-required-validation-wiring",
52742
+ severity: "error",
52743
+ path: `artifacts.${artId}`,
52744
+ message: `required_validation "${reqValId}" has target_artifact "${val.target_artifact}" instead of "${artId}"`
52745
+ });
52746
+ }
52747
+ if (!referencedValidations.has(reqValId)) {
52748
+ diagnostics.push({
52749
+ ruleId: "artifact-required-validation-wiring",
52750
+ severity: "warning",
52751
+ path: `artifacts.${artId}`,
52752
+ message: `required_validation "${reqValId}" is defined but not referenced in any workflow step or task`
52753
+ });
52754
+ }
52755
+ }
52756
+ }
52757
+ return diagnostics;
52758
+ }
52759
+ };
52760
+
52761
+ // src/linter/rules/task-output-validation-completeness.ts
52762
+ var taskOutputValidationCompletenessRule = {
52763
+ id: "task-output-validation-completeness",
52764
+ description: "Tasks producing artifacts should cover those artifacts' required_validations in their validations list.",
52765
+ run(dsl) {
52766
+ const diagnostics = [];
52767
+ for (const [taskId, task] of Object.entries(dsl.tasks)) {
52768
+ const producedArtifacts = /* @__PURE__ */ new Set();
52769
+ if (task.execution_steps) {
52770
+ for (const step of task.execution_steps) {
52771
+ if (step.produces_artifact) {
52772
+ producedArtifacts.add(step.produces_artifact);
52773
+ }
52774
+ }
52775
+ }
52776
+ const agent = dsl.agents[task.target_agent];
52777
+ if (agent) {
52778
+ for (const artId of agent.can_write_artifacts) {
52779
+ producedArtifacts.add(artId);
52780
+ }
52781
+ }
52782
+ const taskValidations = new Set(task.validations);
52783
+ for (const artId of producedArtifacts) {
52784
+ const art = dsl.artifacts[artId];
52785
+ if (!art || art.required_validations.length === 0) continue;
52786
+ const missing = art.required_validations.filter(
52787
+ (v2) => !taskValidations.has(v2)
52788
+ );
52789
+ if (missing.length > 0) {
52790
+ diagnostics.push({
52791
+ ruleId: "task-output-validation-completeness",
52792
+ severity: "warning",
52793
+ path: `tasks.${taskId}`,
52794
+ message: `Task produces artifact "${artId}" which requires validations [${missing.join(", ")}] but task.validations does not include them`
52795
+ });
52796
+ }
52797
+ }
52798
+ }
52799
+ return diagnostics;
52800
+ }
52801
+ };
52802
+
52698
52803
  // src/linter/linter.ts
52699
52804
  var builtinRules = [
52700
52805
  validationCoverageRule,
@@ -52704,7 +52809,9 @@ var builtinRules = [
52704
52809
  artifactOwnershipRule,
52705
52810
  toolCommandsRule,
52706
52811
  guardrailPolicyCoverageRule,
52707
- yamlReservedKeySafetyRule
52812
+ yamlReservedKeySafetyRule,
52813
+ artifactRequiredValidationWiringRule,
52814
+ taskOutputValidationCompletenessRule
52708
52815
  ];
52709
52816
  function lint(dsl, rules = builtinRules) {
52710
52817
  const diagnostics = [];