agent-contracts 0.11.7 → 0.12.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.d.ts CHANGED
@@ -346,6 +346,9 @@ declare const DslSchema: z.ZodObject<{
346
346
  mechanical: "mechanical";
347
347
  semantic: "semantic";
348
348
  approval: "approval";
349
+ provenance: "provenance";
350
+ traceability: "traceability";
351
+ fidelity: "fidelity";
349
352
  }>;
350
353
  executor_type: z.ZodEnum<{
351
354
  tool: "tool";
@@ -731,6 +734,9 @@ declare const ValidationSchema: z.ZodObject<{
731
734
  mechanical: "mechanical";
732
735
  semantic: "semantic";
733
736
  approval: "approval";
737
+ provenance: "provenance";
738
+ traceability: "traceability";
739
+ fidelity: "fidelity";
734
740
  }>;
735
741
  executor_type: z.ZodEnum<{
736
742
  tool: "tool";
@@ -1028,8 +1034,18 @@ interface ResolvedConfig {
1028
1034
  paths?: Record<string, string>;
1029
1035
  }
1030
1036
 
1031
- declare function renderFromConfig(dsl: Dsl, renderTargets: ResolvedRenderTarget[]): Promise<string[]>;
1032
- declare function checkDriftFromConfig(dsl: Dsl, renderTargets: ResolvedRenderTarget[]): Promise<{
1037
+ interface LoadedBinding {
1038
+ filePath: string;
1039
+ binding: SoftwareBinding;
1040
+ }
1041
+ declare function loadBindings(bindingPaths: string[]): Promise<LoadedBinding[]>;
1042
+
1043
+ interface RenderOptions {
1044
+ loadedBindings?: LoadedBinding[];
1045
+ activeGuardrailPolicy?: string;
1046
+ }
1047
+ declare function renderFromConfig(dsl: Dsl, renderTargets: ResolvedRenderTarget[], options?: RenderOptions): Promise<string[]>;
1048
+ declare function checkDriftFromConfig(dsl: Dsl, renderTargets: ResolvedRenderTarget[], options?: RenderOptions): Promise<{
1033
1049
  hasDrift: boolean;
1034
1050
  diffs: string[];
1035
1051
  }>;
@@ -1048,9 +1064,29 @@ interface GlobalContext {
1048
1064
  guardrail_policies: Dsl["guardrail_policies"];
1049
1065
  [key: string]: unknown;
1050
1066
  }
1067
+ interface GuardrailEnforcementEntry {
1068
+ guardrail_id: string;
1069
+ description: string;
1070
+ severity: string;
1071
+ action: string;
1072
+ scoped_agents: string[];
1073
+ scoped_tasks: string[];
1074
+ scoped_workflows: string[];
1075
+ scoped_tools: string[];
1076
+ scoped_artifacts: string[];
1077
+ allow_override: boolean;
1078
+ override_requires: string[];
1079
+ trigger: string | null;
1080
+ escalation: {
1081
+ target: string;
1082
+ condition?: string;
1083
+ } | null;
1084
+ }
1051
1085
  interface SystemContext {
1052
1086
  system: System;
1053
1087
  dsl: Dsl;
1088
+ guardrailEnforcement?: GuardrailEnforcementEntry[];
1089
+ bindings?: SoftwareBinding[];
1054
1090
  [key: string]: unknown;
1055
1091
  }
1056
1092
  interface PerTaskContext {
@@ -1177,7 +1213,10 @@ interface PerAgentContext {
1177
1213
  [key: string]: unknown;
1178
1214
  }
1179
1215
  declare function buildGlobalContext(dsl: Dsl): GlobalContext;
1180
- declare function buildSystemContext(dsl: Dsl): SystemContext;
1216
+ declare function buildSystemContext(dsl: Dsl, options?: {
1217
+ loadedBindings?: LoadedBinding[];
1218
+ activeGuardrailPolicy?: string;
1219
+ }): SystemContext;
1181
1220
  declare function buildTaskContext(dsl: Dsl, taskId: string): PerTaskContext;
1182
1221
  declare function buildArtifactContext(dsl: Dsl, artifactId: string): PerArtifactContext;
1183
1222
  declare function buildToolContext(dsl: Dsl, toolId: string): PerToolContext;
@@ -1191,12 +1230,6 @@ declare function buildPerAgentContext(dsl: Dsl, agent: Agent & {
1191
1230
  id: string;
1192
1231
  }): PerAgentContext;
1193
1232
 
1194
- interface LoadedBinding {
1195
- filePath: string;
1196
- binding: SoftwareBinding;
1197
- }
1198
- declare function loadBindings(bindingPaths: string[]): Promise<LoadedBinding[]>;
1199
-
1200
1233
  declare class ConfigLoadError extends Error {
1201
1234
  readonly filePath?: string | undefined;
1202
1235
  constructor(message: string, filePath?: string | undefined);
package/dist/index.js CHANGED
@@ -50660,7 +50660,7 @@ var ToolSchema = z9.object({
50660
50660
  import { z as z10 } from "zod";
50661
50661
  var ValidationSchema = z10.object({
50662
50662
  target_artifact: z10.string(),
50663
- kind: z10.enum(["schema", "mechanical", "semantic", "approval"]),
50663
+ kind: z10.enum(["schema", "mechanical", "semantic", "approval", "provenance", "traceability", "fidelity"]),
50664
50664
  executor_type: z10.enum(["tool", "agent"]),
50665
50665
  executor: z10.string(),
50666
50666
  blocking: z10.boolean(),
@@ -52388,6 +52388,68 @@ var taskOutputValidationCompletenessRule = {
52388
52388
  }
52389
52389
  };
52390
52390
 
52391
+ // src/linter/rules/semantic-validation-phase-coverage.ts
52392
+ var SEMANTIC_KINDS = /* @__PURE__ */ new Set(["semantic", "fidelity"]);
52393
+ var semanticValidationPhaseCoverageRule = {
52394
+ id: "semantic-validation-phase-coverage",
52395
+ description: "Semantic and fidelity validations should appear in early workflow phases, not only in late phases.",
52396
+ run(dsl) {
52397
+ const diagnostics = [];
52398
+ const semanticValIds = /* @__PURE__ */ new Set();
52399
+ for (const [valId, val] of Object.entries(dsl.validations)) {
52400
+ if (SEMANTIC_KINDS.has(val.kind)) {
52401
+ semanticValIds.add(valId);
52402
+ }
52403
+ }
52404
+ if (semanticValIds.size === 0) {
52405
+ return diagnostics;
52406
+ }
52407
+ const phaseOrder = dsl.system.default_workflow_order;
52408
+ if (phaseOrder.length < 2) {
52409
+ return diagnostics;
52410
+ }
52411
+ const phaseValidations = /* @__PURE__ */ new Map();
52412
+ for (const phase of phaseOrder) {
52413
+ phaseValidations.set(phase, /* @__PURE__ */ new Set());
52414
+ }
52415
+ for (const [phase, wf] of Object.entries(dsl.workflow)) {
52416
+ if (!phaseValidations.has(phase)) continue;
52417
+ for (const step of wf.steps) {
52418
+ if (step.type === "validation" && semanticValIds.has(step.validation)) {
52419
+ phaseValidations.get(phase).add(step.validation);
52420
+ }
52421
+ }
52422
+ }
52423
+ for (const task of Object.values(dsl.tasks)) {
52424
+ const phase = task.workflow;
52425
+ if (!phaseValidations.has(phase)) continue;
52426
+ for (const valId of task.validations) {
52427
+ if (semanticValIds.has(valId)) {
52428
+ phaseValidations.get(phase).add(valId);
52429
+ }
52430
+ }
52431
+ }
52432
+ const earlyBoundary = Math.ceil(phaseOrder.length / 2);
52433
+ const earlyPhases = phaseOrder.slice(0, earlyBoundary);
52434
+ const latePhases = phaseOrder.slice(earlyBoundary);
52435
+ const earlyHasAny = earlyPhases.some(
52436
+ (p2) => (phaseValidations.get(p2)?.size ?? 0) > 0
52437
+ );
52438
+ const lateWithSemantic = latePhases.filter(
52439
+ (p2) => (phaseValidations.get(p2)?.size ?? 0) > 0
52440
+ );
52441
+ if (!earlyHasAny && lateWithSemantic.length > 0) {
52442
+ diagnostics.push({
52443
+ ruleId: "semantic-validation-phase-coverage",
52444
+ severity: "warning",
52445
+ path: "validations",
52446
+ message: `Semantic validations are only referenced in workflow phases [${lateWithSemantic.join(", ")}]. Consider adding semantic review to earlier phases [${earlyPhases.join(", ")}] to catch issues before implementation.`
52447
+ });
52448
+ }
52449
+ return diagnostics;
52450
+ }
52451
+ };
52452
+
52391
52453
  // src/linter/linter.ts
52392
52454
  var builtinRules = [
52393
52455
  validationCoverageRule,
@@ -52399,7 +52461,8 @@ var builtinRules = [
52399
52461
  guardrailPolicyCoverageRule,
52400
52462
  yamlReservedKeySafetyRule,
52401
52463
  artifactRequiredValidationWiringRule,
52402
- taskOutputValidationCompletenessRule
52464
+ taskOutputValidationCompletenessRule,
52465
+ semanticValidationPhaseCoverageRule
52403
52466
  ];
52404
52467
  function lint(dsl, rules = builtinRules) {
52405
52468
  const diagnostics = [];
@@ -53066,8 +53129,52 @@ function buildGlobalContext(dsl) {
53066
53129
  guardrail_policies: dsl.guardrail_policies
53067
53130
  };
53068
53131
  }
53069
- function buildSystemContext(dsl) {
53070
- return { system: dsl.system, dsl };
53132
+ function buildSystemContext(dsl, options) {
53133
+ const ctx = { system: dsl.system, dsl };
53134
+ if (options?.loadedBindings && options.loadedBindings.length > 0) {
53135
+ ctx.bindings = options.loadedBindings.map((lb) => lb.binding);
53136
+ const policyName = options.activeGuardrailPolicy;
53137
+ const policy = policyName ? dsl.guardrail_policies[policyName] : void 0;
53138
+ if (policy) {
53139
+ ctx.guardrailEnforcement = buildGuardrailEnforcement(dsl, policy, options.loadedBindings);
53140
+ }
53141
+ }
53142
+ return ctx;
53143
+ }
53144
+ function buildGuardrailEnforcement(dsl, policy, loadedBindings) {
53145
+ const entries = [];
53146
+ const bindingTriggers = /* @__PURE__ */ new Map();
53147
+ for (const lb of loadedBindings) {
53148
+ const impl = lb.binding.guardrail_impl ?? {};
53149
+ for (const [guardrailId, gi] of Object.entries(impl)) {
53150
+ for (const check of gi.checks) {
53151
+ if (check.matcher) {
53152
+ bindingTriggers.set(guardrailId, check.matcher.type);
53153
+ }
53154
+ }
53155
+ }
53156
+ }
53157
+ for (const rule of policy.rules) {
53158
+ const guardrail = dsl.guardrails[rule.guardrail];
53159
+ if (!guardrail) continue;
53160
+ const scope = guardrail.scope ?? {};
53161
+ entries.push({
53162
+ guardrail_id: rule.guardrail,
53163
+ description: guardrail.description,
53164
+ severity: rule.severity,
53165
+ action: rule.action,
53166
+ scoped_agents: scope.agents ?? [],
53167
+ scoped_tasks: scope.tasks ?? [],
53168
+ scoped_workflows: scope.workflows ?? [],
53169
+ scoped_tools: scope.tools ?? [],
53170
+ scoped_artifacts: scope.artifacts ?? [],
53171
+ allow_override: rule.allow_override,
53172
+ override_requires: rule.override_requires ?? [],
53173
+ trigger: bindingTriggers.get(rule.guardrail) ?? null,
53174
+ escalation: rule.escalation ? { target: rule.escalation.target, condition: rule.escalation.condition } : null
53175
+ });
53176
+ }
53177
+ return entries;
53071
53178
  }
53072
53179
  function buildTaskContext(dsl, taskId) {
53073
53180
  const taskDef = dsl.tasks[taskId];
@@ -54122,6 +54229,50 @@ Handlebars.registerHelper(
54122
54229
  return generateOverviewFlowchart(dsl);
54123
54230
  }
54124
54231
  );
54232
+ Handlebars.registerHelper(
54233
+ "guardrailCoverageMatrix",
54234
+ function() {
54235
+ const enforcement = this["guardrailEnforcement"];
54236
+ if (!enforcement || enforcement.length === 0) return "";
54237
+ const header = "| Guardrail | Severity | Action | Agents | Tasks | Workflows | Tools | Artifacts | Trigger | Override | Escalation |";
54238
+ const divider = "|-----------|----------|--------|--------|-------|-----------|-------|-----------|---------|----------|------------|";
54239
+ const rows = enforcement.map((e3) => {
54240
+ const agents = e3["scoped_agents"]?.join(", ") || "\u2014";
54241
+ const tasks = e3["scoped_tasks"]?.join(", ") || "\u2014";
54242
+ const workflows = e3["scoped_workflows"]?.join(", ") || "\u2014";
54243
+ const tools = e3["scoped_tools"]?.join(", ") || "\u2014";
54244
+ const artifacts = e3["scoped_artifacts"]?.join(", ") || "\u2014";
54245
+ const trigger = e3["trigger"] || "\u2014";
54246
+ const override = e3["allow_override"] ? "yes" : "no";
54247
+ const esc = e3["escalation"];
54248
+ const escalation = esc ? esc["target"] : "\u2014";
54249
+ return `| ${e3["guardrail_id"]} | ${e3["severity"]} | ${e3["action"]} | ${agents} | ${tasks} | ${workflows} | ${tools} | ${artifacts} | ${trigger} | ${override} | ${escalation} |`;
54250
+ });
54251
+ return [header, divider, ...rows].join("\n");
54252
+ }
54253
+ );
54254
+ Handlebars.registerHelper(
54255
+ "taskGuardrailMatrix",
54256
+ function() {
54257
+ const dsl = this["dsl"];
54258
+ const enforcement = this["guardrailEnforcement"];
54259
+ if (!dsl || !enforcement || enforcement.length === 0) return "";
54260
+ const taskIds = Object.keys(dsl.tasks);
54261
+ if (taskIds.length === 0) return "";
54262
+ const guardrailIds = enforcement.map((e3) => e3["guardrail_id"]);
54263
+ const header = `| Task | ${guardrailIds.join(" | ")} |`;
54264
+ const divider = `|------|${guardrailIds.map(() => "------").join("|")}|`;
54265
+ const rows = taskIds.map((taskId) => {
54266
+ const cells = enforcement.map((e3) => {
54267
+ const scopedTasks = e3["scoped_tasks"];
54268
+ if (scopedTasks.length > 0 && !scopedTasks.includes(taskId)) return "n/a";
54269
+ return e3["action"];
54270
+ });
54271
+ return `| ${taskId} | ${cells.join(" | ")} |`;
54272
+ });
54273
+ return [header, divider, ...rows].join("\n");
54274
+ }
54275
+ );
54125
54276
  function getDslSection(dsl, context) {
54126
54277
  const sectionMap = {
54127
54278
  agent: dsl.agents,
@@ -54186,13 +54337,13 @@ async function removeIfExists(filePath) {
54186
54337
  } catch {
54187
54338
  }
54188
54339
  }
54189
- async function renderFromConfig(dsl, renderTargets) {
54340
+ async function renderFromConfig(dsl, renderTargets, options) {
54190
54341
  const outputFiles = [];
54191
54342
  for (const target of renderTargets) {
54192
54343
  const templateContent = await loadTemplate(target.template);
54193
54344
  const compiled = Handlebars.compile(templateContent, { noEscape: false });
54194
54345
  if (target.context === "system") {
54195
- const ctx = buildSystemContext(dsl);
54346
+ const ctx = buildSystemContext(dsl, options);
54196
54347
  const output = compiled(ctx);
54197
54348
  if (target.skip_empty && isEffectivelyEmpty(output)) {
54198
54349
  await removeIfExists(target.output);
@@ -54241,13 +54392,13 @@ function checkExpectedVsExisting(expected, outputPath, skipEmpty, diffs) {
54241
54392
  diffs.push(outputPath);
54242
54393
  });
54243
54394
  }
54244
- async function checkDriftFromConfig(dsl, renderTargets) {
54395
+ async function checkDriftFromConfig(dsl, renderTargets, options) {
54245
54396
  const diffs = [];
54246
54397
  for (const target of renderTargets) {
54247
54398
  const templateContent = await loadTemplate(target.template);
54248
54399
  const compiled = Handlebars.compile(templateContent, { noEscape: false });
54249
54400
  if (target.context === "system") {
54250
- const ctx = buildSystemContext(dsl);
54401
+ const ctx = buildSystemContext(dsl, options);
54251
54402
  const expected = compiled(ctx);
54252
54403
  await checkExpectedVsExisting(expected, target.output, target.skip_empty, diffs);
54253
54404
  } else {