agent-inspect 6.29.5 → 6.30.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.
Files changed (29) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +1 -1
  3. package/docs/CLI.md +27 -5
  4. package/docs/TRACE-CONTRACTS.md +10 -7
  5. package/package.json +1 -1
  6. package/packages/cli/dist/{chunk-XWQEHKGB.mjs → chunk-BDRJENLM.mjs} +2334 -102
  7. package/packages/cli/dist/chunk-BDRJENLM.mjs.map +1 -0
  8. package/packages/cli/dist/index.cjs +3122 -168
  9. package/packages/cli/dist/index.cjs.map +1 -1
  10. package/packages/cli/dist/index.mjs +793 -61
  11. package/packages/cli/dist/index.mjs.map +1 -1
  12. package/packages/cli/dist/{src-XNC4EUN3.mjs → src-ZUGAUXY6.mjs} +3 -3
  13. package/packages/cli/dist/{src-XNC4EUN3.mjs.map → src-ZUGAUXY6.mjs.map} +1 -1
  14. package/packages/core/dist/advanced.cjs +19 -1
  15. package/packages/core/dist/advanced.cjs.map +1 -1
  16. package/packages/core/dist/advanced.d.cts +2 -2
  17. package/packages/core/dist/advanced.d.ts +2 -2
  18. package/packages/core/dist/advanced.mjs +2 -2
  19. package/packages/core/dist/checks.cjs +33 -1
  20. package/packages/core/dist/checks.cjs.map +1 -1
  21. package/packages/core/dist/checks.d.cts +2 -2
  22. package/packages/core/dist/checks.d.ts +2 -2
  23. package/packages/core/dist/checks.mjs +1 -1
  24. package/packages/core/dist/{chunk-TU47EKKS.mjs → chunk-OOX25GTH.mjs} +35 -3
  25. package/packages/core/dist/chunk-OOX25GTH.mjs.map +1 -0
  26. package/packages/core/dist/{index-DvSbXNot.d.ts → index-7hG_qggp.d.ts} +5 -0
  27. package/packages/core/dist/{index-DKv7esIo.d.cts → index-CQJUNPPe.d.cts} +5 -0
  28. package/packages/cli/dist/chunk-XWQEHKGB.mjs.map +0 -1
  29. package/packages/core/dist/chunk-TU47EKKS.mjs.map +0 -1
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { ATTRIBUTION_CONFIDENCES, createSafetyRawContentRule, createSafetyRedactionRule, createSafetySecretPatternRule, createSafetyOversizedAttributeRule, resolveTraceDir, parseDuration, buildSessionIndex, resolveBundleRunIds, getTraceFilePath, openTrace, sha256Hex, collectTraceSchemaVersions, aggregateBundleSafeStatus, bundleFailsOnSafety, bundleRunAssetRelativePath, buildPlaceholderArtifact, EVIDENCE_HTML_FILENAME, EVIDENCE_MANIFEST_FILENAME, buildBundleMetadata, buildBundleSummaryMarkdown, buildEvidenceHtmlShell, buildEvidenceProvenanceViewHtml, EVIDENCE_FORMAT_VERSION, inferEvidenceFileRole, buildEvidenceSafetyViewHtml, buildEvidenceDiffViewHtml, buildEvidenceCircuitViewHtml, buildEvidenceOutcomesViewHtml, buildEvidenceContractsViewHtml, buildEvidenceToolsLlmViewHtml, buildEvidenceCausalFailureViewHtml, buildEvidenceTimelineViewHtml, buildEvidenceTreeViewHtml, buildEvidenceManifest, serializeEvidenceManifest, buildZipArchive, assertBundlePathContained, enrichSessionRunRecord, normalizeBundleOutputPath, sanitizeBundleRunId, defaultBundleOutputPath, runTraceChecks, assertEvidenceRelativePath, TraceDirectory, loadTraceMetadataList, loadSessionRunRecords, TraceReadError, resolveRedactionProfile, applyProfileMetadataCaps, Redactor, flattenTree, escapeHtml, safeString, compactAttributes, stableJson, escapeMarkdown, truncateStringForProfile, extractMetadata, filterTraces, truncateName, buildRunSummary, formatDuration, formatTimestamp, renderErrorLine, isAgentInspectTrace, filterMetasBySessionScope, aggregateSessionCheckResults, createBaselineRegressionRule, summarizeSemanticParity, buildEvidenceCiPackage, verifyEvidenceDirectory, diffTraceEvents, renderRunDiff, buildRunTimeline, renderTimeline, buildTraceStats, renderTraceStats, parseDurationFilter, searchTraces, formatStepLabel, buildActivitySummary, renderActivitySummaryHuman, buildRunWhatSummary, renderRunWhat, buildLocalExplanation, resolveSuiteTemplate, defaultSuiteConfigTemplate, loadSuiteConfig, validateSuiteConfig, runSuite, renderSuiteReport, analyzeCohort, renderCohortReport, gateHasThresholds, runGate, renderGateReport, persistedInspectEventsToTraceEvents, renderStepLine, getIndent, TreeBuilder, zeroKinds, validateEvent, traceEventToPersistedInspectEvent, isPersistedInspectEvent, createRunStatusRule, createStructureOrphanRule, createStructureCycleRule, createRunDurationRule, createMaxStepDurationRule, createRequireCompletedRule, createStallDetectionRule, createObservedOutcomeRule, createRunDepthRule, createToolUsageRule, createLlmUsageRule, createStructureRelationshipRule, createStructureParallelWidthRule, projectLogicalEvents, summarizeObservedOutcomes, extractOutcomesFromTraceEvents, renderObservedOutcomesMarkdown, renderObservedOutcomesHtml, DEFAULT_SUITE_ARTIFACTS_DIR, parseCohortMetricList, COHORT_METRIC_IDS, parseGateList, nanoid, isAttributionConfidence, diffRuns, manualTraceEventsToComparableRun } from './chunk-XWQEHKGB.mjs';
2
+ import { ATTRIBUTION_CONFIDENCES, createSafetyRawContentRule, createSafetyRedactionRule, createSafetySecretPatternRule, createSafetyOversizedAttributeRule, resolveTraceDir, parseDuration, buildSessionIndex, resolveBundleRunIds, getTraceFilePath, openTrace, sha256Hex, collectTraceSchemaVersions, aggregateBundleSafeStatus, bundleFailsOnSafety, bundleRunAssetRelativePath, buildPlaceholderArtifact, EVIDENCE_HTML_FILENAME, EVIDENCE_MANIFEST_FILENAME, buildBundleMetadata, buildBundleSummaryMarkdown, buildEvidenceHtmlShell, buildEvidenceProvenanceViewHtml, EVIDENCE_FORMAT_VERSION, inferEvidenceFileRole, buildEvidenceSafetyViewHtml, buildEvidenceDiffViewHtml, buildEvidenceCircuitViewHtml, buildEvidenceOutcomesViewHtml, buildEvidenceContractsViewHtml, buildEvidenceToolsLlmViewHtml, buildEvidenceCausalFailureViewHtml, buildEvidenceTimelineViewHtml, buildEvidenceTreeViewHtml, buildEvidenceManifest, serializeEvidenceManifest, buildZipArchive, assertBundlePathContained, enrichSessionRunRecord, normalizeBundleOutputPath, sanitizeBundleRunId, defaultBundleOutputPath, runTraceChecks, assertEvidenceRelativePath, TraceDirectory, loadTraceMetadataList, loadSessionRunRecords, TraceReadError, resolveRedactionProfile, applyProfileMetadataCaps, Redactor, flattenTree, escapeHtml, safeString, compactAttributes, stableJson, escapeMarkdown, truncateStringForProfile, extractMetadata, filterTraces, truncateName, buildRunSummary, formatDuration, formatTimestamp, renderErrorLine, isAgentInspectTrace, defineTraceContract, filterMetasBySessionScope, evaluateTraceContract, aggregateSessionCheckResults, createBaselineRegressionRule, summarizeSemanticParity, buildEvidenceCiPackage, verifyEvidenceDirectory, diffTraceEvents, renderRunDiff, buildRunTimeline, renderTimeline, buildTraceStats, renderTraceStats, parseDurationFilter, searchTraces, formatStepLabel, buildActivitySummary, renderActivitySummaryHuman, buildRunWhatSummary, renderRunWhat, buildLocalExplanation, resolveSuiteTemplate, defaultSuiteConfigTemplate, loadSuiteConfig, validateSuiteConfig, runSuite, renderSuiteReport, analyzeCohort, renderCohortReport, gateHasThresholds, runGate, renderGateReport, persistedInspectEventsToTraceEvents, renderStepLine, getIndent, TreeBuilder, zeroKinds, validateEvent, traceEventToPersistedInspectEvent, isPersistedInspectEvent, createRunStatusRule, createStructureOrphanRule, createStructureCycleRule, createRunDurationRule, createMaxStepDurationRule, createRequireCompletedRule, createStallDetectionRule, createObservedOutcomeRule, createRunDepthRule, createToolUsageRule, createLlmUsageRule, createStructureRelationshipRule, createStructureParallelWidthRule, projectLogicalEvents, summarizeObservedOutcomes, extractOutcomesFromTraceEvents, renderObservedOutcomesMarkdown, renderObservedOutcomesHtml, DEFAULT_SUITE_ARTIFACTS_DIR, parseCohortMetricList, COHORT_METRIC_IDS, parseGateList, nanoid, isAttributionConfidence, diffRuns, manualTraceEventsToComparableRun } from './chunk-BDRJENLM.mjs';
3
3
  import { realpathSync, constants as constants$1, existsSync, readFileSync } from 'fs';
4
4
  import path19 from 'path';
5
5
  import { fileURLToPath, pathToFileURL } from 'url';
@@ -13,7 +13,7 @@ import { createServer } from 'http';
13
13
  import { createRequire } from 'module';
14
14
 
15
15
  // package.json
16
- var version = "6.29.5";
16
+ var version = "6.30.0";
17
17
 
18
18
  // packages/cli/src/trace-dir-scale.ts
19
19
  var TRACE_COUNT_WARN = 1e3;
@@ -3397,7 +3397,7 @@ async function newestTraceMtimeMs(traceDir) {
3397
3397
  }
3398
3398
  async function loadSessionRuns(traceDir) {
3399
3399
  try {
3400
- const mod = await import('./src-XNC4EUN3.mjs');
3400
+ const mod = await import('./src-ZUGAUXY6.mjs');
3401
3401
  const dbPath = mod.resolveIndexDbPath(traceDir);
3402
3402
  const status = mod.indexStatus(dbPath);
3403
3403
  if (!status.healthy) {
@@ -5855,7 +5855,8 @@ async function writeLocalEvidence(input3) {
5855
5855
  redactionProfile: profile,
5856
5856
  assessmentStatus,
5857
5857
  checkResultsJson: input3.checkResultsJson,
5858
- ...input3.summaryText !== void 0 ? { summaryText: input3.summaryText } : {}
5858
+ ...input3.summaryText !== void 0 ? { summaryText: input3.summaryText } : {},
5859
+ ...input3.contractPackage !== void 0 ? { contractPackage: input3.contractPackage } : {}
5859
5860
  });
5860
5861
  const files = [
5861
5862
  ["evidence.html", evidencePackage["evidence.html"]],
@@ -5863,6 +5864,10 @@ async function writeLocalEvidence(input3) {
5863
5864
  ["check-results.json", evidencePackage["check-results.json"]],
5864
5865
  ["trace.jsonl", evidencePackage["trace.jsonl"]]
5865
5866
  ];
5867
+ const resolvedContract = evidencePackage["contract.resolved.json"];
5868
+ if (resolvedContract !== void 0) {
5869
+ files.push(["contract.resolved.json", resolvedContract]);
5870
+ }
5866
5871
  const expected = createEvidenceCiArtifacts({
5867
5872
  redactionProfile: profile
5868
5873
  }).map((a) => a.path);
@@ -6824,6 +6829,131 @@ function asStringArray(value) {
6824
6829
  return value;
6825
6830
  }
6826
6831
  var CHECKS_KEYS = /* @__PURE__ */ new Set(["select", "run", "tool", "llm", "structure", "safety"]);
6832
+ var ROOT_CONFIG_KEYS = /* @__PURE__ */ new Set(["checks", "contract"]);
6833
+ var CONTRACT_KEYS = /* @__PURE__ */ new Set([
6834
+ "run",
6835
+ "tools",
6836
+ "llm",
6837
+ "observations",
6838
+ "scope",
6839
+ "alternatives",
6840
+ "controls",
6841
+ "retry"
6842
+ ]);
6843
+ var CONTRACT_BODY_KEYS = /* @__PURE__ */ new Set([
6844
+ "run",
6845
+ "tools",
6846
+ "llm",
6847
+ "observations",
6848
+ "controls",
6849
+ "retry"
6850
+ ]);
6851
+ var CONTRACT_SCOPE_KEYS = /* @__PURE__ */ new Set([
6852
+ "runId",
6853
+ "subAgentId",
6854
+ "groupId",
6855
+ "workflowStep",
6856
+ "rootEventId"
6857
+ ]);
6858
+ var CONTRACT_RUN_KEYS = /* @__PURE__ */ new Set(["requireCompleted", "allowedStatuses", "maxDurationMs"]);
6859
+ var CONTRACT_TOOLS_KEYS = /* @__PURE__ */ new Set([
6860
+ "required",
6861
+ "requiredTools",
6862
+ "forbidden",
6863
+ "forbiddenTools",
6864
+ "allowed",
6865
+ "maxCalls",
6866
+ "requiredOrder",
6867
+ "requiredOrderMode",
6868
+ "arguments",
6869
+ "orderRules",
6870
+ "defaultOccurrenceMode"
6871
+ ]);
6872
+ var CONTRACT_LLM_KEYS = /* @__PURE__ */ new Set(["maxCalls", "maxTotalTokens", "allowedModels"]);
6873
+ var CONTRACT_OBSERVATION_KEYS = /* @__PURE__ */ new Set(["required", "failOn", "requireProvenance"]);
6874
+ var CONTRACT_PROVENANCE_KEYS = /* @__PURE__ */ new Set(["method", "evidence", "sameRunEventReference"]);
6875
+ var CONTRACT_CONTROLS_KEYS = /* @__PURE__ */ new Set([
6876
+ "declaredTools",
6877
+ "enforcedTools",
6878
+ "declaredToolsAttribute",
6879
+ "enforcedToolsAttribute",
6880
+ "requireDeclaredMatchesEnforced",
6881
+ "requireObservedWithinEnforced",
6882
+ "requireObservedWithinDeclared",
6883
+ "requiredStages"
6884
+ ]);
6885
+ var CONTRACT_CONTROL_STAGES = /* @__PURE__ */ new Set([
6886
+ "declared",
6887
+ "presented",
6888
+ "validated",
6889
+ "enforced",
6890
+ "observed",
6891
+ "accepted"
6892
+ ]);
6893
+ var CONTRACT_CONTROL_STAGE_KEYS = /* @__PURE__ */ new Set(["stage", "observation"]);
6894
+ var CONTRACT_RETRY_KEYS = /* @__PURE__ */ new Set([
6895
+ "maxAttempts",
6896
+ "requireTerminalResult",
6897
+ "fallbackOnlyAfterFailure",
6898
+ "nonIdempotentTools",
6899
+ "requireIdempotencyEvidenceForRetry",
6900
+ "requireRecoveredFailureVisible",
6901
+ "operations"
6902
+ ]);
6903
+ var CONTRACT_OPERATION_KEYS = /* @__PURE__ */ new Set([
6904
+ "tool",
6905
+ "maxAttempts",
6906
+ "retryableErrors",
6907
+ "requireFailureBeforeRetry",
6908
+ "requireSameArguments",
6909
+ "requireTerminalSuccess",
6910
+ "requireRecoveredFailureVisible",
6911
+ "successfulResultDependency",
6912
+ "sideEffectClass"
6913
+ ]);
6914
+ var CONTRACT_RETRYABLE_ERRORS_KEYS = /* @__PURE__ */ new Set(["codes"]);
6915
+ var CONTRACT_RESULT_DEP_KEYS = /* @__PURE__ */ new Set(["consumerKind", "requireExplicitReference"]);
6916
+ var CONTRACT_ALT_KEYS = /* @__PURE__ */ new Set(["anyOf"]);
6917
+ var CONTRACT_ALT_BRANCH_KEYS = /* @__PURE__ */ new Set(["id", "description", "contract"]);
6918
+ var CONTRACT_ORDER_RULE_KEYS = /* @__PURE__ */ new Set([
6919
+ "before",
6920
+ "after",
6921
+ "occurrenceMode",
6922
+ "requireEndpoints"
6923
+ ]);
6924
+ var CONTRACT_ARGUMENT_KEYS = /* @__PURE__ */ new Set([
6925
+ "tool",
6926
+ "path",
6927
+ "operator",
6928
+ "occurrence",
6929
+ "expected",
6930
+ "oneOf",
6931
+ "type"
6932
+ ]);
6933
+ var CONTRACT_ARGUMENT_OPERATORS = /* @__PURE__ */ new Set(["exists", "type", "equals", "oneOf"]);
6934
+ var CONTRACT_ARGUMENT_OCCURRENCES = /* @__PURE__ */ new Set(["first", "last", "any", "all"]);
6935
+ var CONTRACT_ARGUMENT_TYPES = /* @__PURE__ */ new Set([
6936
+ "string",
6937
+ "number",
6938
+ "boolean",
6939
+ "object",
6940
+ "array",
6941
+ "null"
6942
+ ]);
6943
+ var CONTRACT_ORDER_MODES = /* @__PURE__ */ new Set([
6944
+ "first-occurrence",
6945
+ "happens-before",
6946
+ "all-occurrences"
6947
+ ]);
6948
+ var CONTRACT_FAIL_ON = /* @__PURE__ */ new Set(["failed", "unknown", "skipped"]);
6949
+ var CONTRACT_SIDE_EFFECT_CLASSES = /* @__PURE__ */ new Set(["read", "write"]);
6950
+ var CONTRACT_MAX_STRING_LIST = 64;
6951
+ var CONTRACT_MAX_ARGUMENTS = 32;
6952
+ var CONTRACT_MAX_ORDER_RULES = 32;
6953
+ var CONTRACT_MAX_ANY_OF = 16;
6954
+ var CONTRACT_MAX_OPERATIONS = 32;
6955
+ var CONTRACT_MAX_REQUIRED_STAGES = 16;
6956
+ var CONTRACT_MAX_ONE_OF = 32;
6827
6957
  var RUN_KEYS = /* @__PURE__ */ new Set(["expected", "allowIncomplete", "maxDurationMs", "maxDepth"]);
6828
6958
  var TOOL_KEYS = /* @__PURE__ */ new Set(["required", "forbidden", "allowed", "minCount", "maxCount"]);
6829
6959
  var LLM_KEYS = /* @__PURE__ */ new Set([
@@ -6930,6 +7060,49 @@ function requireBoolean(value, pathPrefix) {
6930
7060
  }
6931
7061
  return value;
6932
7062
  }
7063
+ function requireNonEmptyString(value, pathPrefix) {
7064
+ if (typeof value !== "string" || value.trim() === "") {
7065
+ throw new CheckConfigError(
7066
+ "AI_CHECK_CONFIG_INVALID_VALUE",
7067
+ `${pathPrefix} must be a non-empty string.`
7068
+ );
7069
+ }
7070
+ return value;
7071
+ }
7072
+ function requireBoundedArray(value, pathPrefix, max) {
7073
+ if (!Array.isArray(value)) {
7074
+ throw new CheckConfigError(
7075
+ "AI_CHECK_CONFIG_INVALID_VALUE",
7076
+ `${pathPrefix} must be an array.`
7077
+ );
7078
+ }
7079
+ if (value.length > max) {
7080
+ throw new CheckConfigError(
7081
+ "AI_CHECK_CONFIG_INVALID_VALUE",
7082
+ `${pathPrefix} exceeds bound of ${max} items.`
7083
+ );
7084
+ }
7085
+ return value;
7086
+ }
7087
+ function requireBoundedStringArray(value, pathPrefix, max = CONTRACT_MAX_STRING_LIST) {
7088
+ const items = requireBoundedArray(value, pathPrefix, max);
7089
+ if (items.some((item) => typeof item !== "string" || item.trim() === "")) {
7090
+ throw new CheckConfigError(
7091
+ "AI_CHECK_CONFIG_INVALID_VALUE",
7092
+ `${pathPrefix} must be an array of non-empty strings.`
7093
+ );
7094
+ }
7095
+ return items;
7096
+ }
7097
+ function requireOrderMode(value, pathPrefix) {
7098
+ if (typeof value !== "string" || !CONTRACT_ORDER_MODES.has(value)) {
7099
+ throw new CheckConfigError(
7100
+ "AI_CHECK_CONFIG_INVALID_VALUE",
7101
+ `${pathPrefix} must be one of: "first-occurrence", "happens-before", "all-occurrences".`
7102
+ );
7103
+ }
7104
+ return value;
7105
+ }
6933
7106
  function parseRunSection(value) {
6934
7107
  const record = requireObject(value, "checks.run");
6935
7108
  rejectUnknownKeys(record, RUN_KEYS, "checks.run");
@@ -7062,6 +7235,7 @@ function sectionHasEffect(section) {
7062
7235
  return Object.keys(section).length > 0;
7063
7236
  }
7064
7237
  function checkConfigHasEffect(config) {
7238
+ if (contractConfigHasEffect(config.contract)) return true;
7065
7239
  const checks2 = config.checks;
7066
7240
  if (checks2 === void 0) return false;
7067
7241
  if ((checks2.select?.length ?? 0) > 0) return true;
@@ -7072,43 +7246,587 @@ function checkConfigHasEffect(config) {
7072
7246
  if (sectionHasEffect(checks2.safety)) return true;
7073
7247
  return false;
7074
7248
  }
7249
+ function contractConfigHasEffect(contract) {
7250
+ if (contract === void 0) return false;
7251
+ if (sectionHasEffect(contract.run)) return true;
7252
+ if (sectionHasEffect(contract.tools)) return true;
7253
+ if (sectionHasEffect(contract.llm)) return true;
7254
+ if (sectionHasEffect(contract.observations)) {
7255
+ return true;
7256
+ }
7257
+ if (sectionHasEffect(contract.controls)) return true;
7258
+ if (sectionHasEffect(contract.retry)) return true;
7259
+ if ((contract.alternatives?.anyOf?.length ?? 0) > 0) return true;
7260
+ return false;
7261
+ }
7262
+ function parseContractRunSection(value, pathPrefix = "contract.run") {
7263
+ const record = requireObject(value, pathPrefix);
7264
+ rejectUnknownKeys(record, CONTRACT_RUN_KEYS, pathPrefix);
7265
+ const out = {};
7266
+ if (record.requireCompleted !== void 0) {
7267
+ out.requireCompleted = requireBoolean(
7268
+ record.requireCompleted,
7269
+ `${pathPrefix}.requireCompleted`
7270
+ );
7271
+ }
7272
+ if (record.allowedStatuses !== void 0) {
7273
+ out.allowedStatuses = requireBoundedStringArray(
7274
+ record.allowedStatuses,
7275
+ `${pathPrefix}.allowedStatuses`
7276
+ );
7277
+ }
7278
+ if (record.maxDurationMs !== void 0) {
7279
+ out.maxDurationMs = requireNonNegativeNumber(
7280
+ record.maxDurationMs,
7281
+ `${pathPrefix}.maxDurationMs`
7282
+ );
7283
+ }
7284
+ return out;
7285
+ }
7286
+ function parseToolArgumentCheck(value, pathPrefix) {
7287
+ const record = requireObject(value, pathPrefix);
7288
+ rejectUnknownKeys(record, CONTRACT_ARGUMENT_KEYS, pathPrefix);
7289
+ const tool = requireNonEmptyString(record.tool, `${pathPrefix}.tool`);
7290
+ if (typeof record.path !== "string") {
7291
+ throw new CheckConfigError(
7292
+ "AI_CHECK_CONFIG_INVALID_VALUE",
7293
+ `${pathPrefix}.path must be a string JSON Pointer ("" or start with "/").`
7294
+ );
7295
+ }
7296
+ const pathValue = record.path;
7297
+ if (typeof record.operator !== "string" || !CONTRACT_ARGUMENT_OPERATORS.has(record.operator)) {
7298
+ throw new CheckConfigError(
7299
+ "AI_CHECK_CONFIG_INVALID_VALUE",
7300
+ `${pathPrefix}.operator must be one of: "exists", "type", "equals", "oneOf".`
7301
+ );
7302
+ }
7303
+ const operator = record.operator;
7304
+ const out = { tool, path: pathValue, operator };
7305
+ if (record.occurrence !== void 0) {
7306
+ if (typeof record.occurrence !== "string" || !CONTRACT_ARGUMENT_OCCURRENCES.has(record.occurrence)) {
7307
+ throw new CheckConfigError(
7308
+ "AI_CHECK_CONFIG_INVALID_VALUE",
7309
+ `${pathPrefix}.occurrence must be one of: "first", "last", "any", "all".`
7310
+ );
7311
+ }
7312
+ out.occurrence = record.occurrence;
7313
+ }
7314
+ if (record.expected !== void 0) {
7315
+ out.expected = record.expected;
7316
+ }
7317
+ if (record.oneOf !== void 0) {
7318
+ out.oneOf = requireBoundedArray(record.oneOf, `${pathPrefix}.oneOf`, CONTRACT_MAX_ONE_OF);
7319
+ }
7320
+ if (record.type !== void 0) {
7321
+ if (typeof record.type !== "string" || !CONTRACT_ARGUMENT_TYPES.has(record.type)) {
7322
+ throw new CheckConfigError(
7323
+ "AI_CHECK_CONFIG_INVALID_VALUE",
7324
+ `${pathPrefix}.type must be one of: "string", "number", "boolean", "object", "array", "null".`
7325
+ );
7326
+ }
7327
+ out.type = record.type;
7328
+ }
7329
+ return out;
7330
+ }
7331
+ function parseOrderRule(value, pathPrefix) {
7332
+ const record = requireObject(value, pathPrefix);
7333
+ rejectUnknownKeys(record, CONTRACT_ORDER_RULE_KEYS, pathPrefix);
7334
+ const out = {
7335
+ before: requireNonEmptyString(record.before, `${pathPrefix}.before`),
7336
+ after: requireNonEmptyString(record.after, `${pathPrefix}.after`)
7337
+ };
7338
+ if (record.occurrenceMode !== void 0) {
7339
+ out.occurrenceMode = requireOrderMode(record.occurrenceMode, `${pathPrefix}.occurrenceMode`);
7340
+ }
7341
+ if (record.requireEndpoints !== void 0) {
7342
+ out.requireEndpoints = requireBoolean(
7343
+ record.requireEndpoints,
7344
+ `${pathPrefix}.requireEndpoints`
7345
+ );
7346
+ }
7347
+ return out;
7348
+ }
7349
+ function parseContractToolsSection(value, pathPrefix = "contract.tools") {
7350
+ const record = requireObject(value, pathPrefix);
7351
+ rejectUnknownKeys(record, CONTRACT_TOOLS_KEYS, pathPrefix);
7352
+ const out = {};
7353
+ if (record.required !== void 0) {
7354
+ out.required = requireBoundedStringArray(record.required, `${pathPrefix}.required`);
7355
+ }
7356
+ if (record.requiredTools !== void 0) {
7357
+ out.requiredTools = requireBoundedStringArray(
7358
+ record.requiredTools,
7359
+ `${pathPrefix}.requiredTools`
7360
+ );
7361
+ }
7362
+ if (record.forbidden !== void 0) {
7363
+ out.forbidden = requireBoundedStringArray(record.forbidden, `${pathPrefix}.forbidden`);
7364
+ }
7365
+ if (record.forbiddenTools !== void 0) {
7366
+ out.forbiddenTools = requireBoundedStringArray(
7367
+ record.forbiddenTools,
7368
+ `${pathPrefix}.forbiddenTools`
7369
+ );
7370
+ }
7371
+ if (record.allowed !== void 0) {
7372
+ out.allowed = requireBoundedStringArray(record.allowed, `${pathPrefix}.allowed`);
7373
+ }
7374
+ if (record.maxCalls !== void 0) {
7375
+ out.maxCalls = requireNonNegativeNumber(record.maxCalls, `${pathPrefix}.maxCalls`);
7376
+ }
7377
+ if (record.requiredOrder !== void 0) {
7378
+ out.requiredOrder = requireBoundedStringArray(
7379
+ record.requiredOrder,
7380
+ `${pathPrefix}.requiredOrder`
7381
+ );
7382
+ }
7383
+ if (record.requiredOrderMode !== void 0) {
7384
+ out.requiredOrderMode = requireOrderMode(
7385
+ record.requiredOrderMode,
7386
+ `${pathPrefix}.requiredOrderMode`
7387
+ );
7388
+ }
7389
+ if (record.defaultOccurrenceMode !== void 0) {
7390
+ out.defaultOccurrenceMode = requireOrderMode(
7391
+ record.defaultOccurrenceMode,
7392
+ `${pathPrefix}.defaultOccurrenceMode`
7393
+ );
7394
+ }
7395
+ if (record.arguments !== void 0) {
7396
+ const items = requireBoundedArray(
7397
+ record.arguments,
7398
+ `${pathPrefix}.arguments`,
7399
+ CONTRACT_MAX_ARGUMENTS
7400
+ );
7401
+ out.arguments = items.map(
7402
+ (item, index) => parseToolArgumentCheck(item, `${pathPrefix}.arguments[${index}]`)
7403
+ );
7404
+ }
7405
+ if (record.orderRules !== void 0) {
7406
+ const items = requireBoundedArray(
7407
+ record.orderRules,
7408
+ `${pathPrefix}.orderRules`,
7409
+ CONTRACT_MAX_ORDER_RULES
7410
+ );
7411
+ out.orderRules = items.map(
7412
+ (item, index) => parseOrderRule(item, `${pathPrefix}.orderRules[${index}]`)
7413
+ );
7414
+ }
7415
+ return out;
7416
+ }
7417
+ function parseContractLlmSection(value, pathPrefix = "contract.llm") {
7418
+ const record = requireObject(value, pathPrefix);
7419
+ rejectUnknownKeys(record, CONTRACT_LLM_KEYS, pathPrefix);
7420
+ const out = {};
7421
+ if (record.maxCalls !== void 0) {
7422
+ out.maxCalls = requireNonNegativeNumber(record.maxCalls, `${pathPrefix}.maxCalls`);
7423
+ }
7424
+ if (record.maxTotalTokens !== void 0) {
7425
+ out.maxTotalTokens = requireNonNegativeNumber(
7426
+ record.maxTotalTokens,
7427
+ `${pathPrefix}.maxTotalTokens`
7428
+ );
7429
+ }
7430
+ if (record.allowedModels !== void 0) {
7431
+ out.allowedModels = requireBoundedStringArray(
7432
+ record.allowedModels,
7433
+ `${pathPrefix}.allowedModels`
7434
+ );
7435
+ }
7436
+ return out;
7437
+ }
7438
+ function parseRequireProvenance(value, pathPrefix) {
7439
+ const record = requireObject(value, pathPrefix);
7440
+ rejectUnknownKeys(record, CONTRACT_PROVENANCE_KEYS, pathPrefix);
7441
+ const out = {};
7442
+ if (record.method !== void 0) {
7443
+ out.method = requireBoolean(record.method, `${pathPrefix}.method`);
7444
+ }
7445
+ if (record.evidence !== void 0) {
7446
+ out.evidence = requireBoolean(record.evidence, `${pathPrefix}.evidence`);
7447
+ }
7448
+ if (record.sameRunEventReference !== void 0) {
7449
+ out.sameRunEventReference = requireBoolean(
7450
+ record.sameRunEventReference,
7451
+ `${pathPrefix}.sameRunEventReference`
7452
+ );
7453
+ }
7454
+ return out;
7455
+ }
7456
+ function parseContractObservationsSection(value, pathPrefix = "contract.observations") {
7457
+ const record = requireObject(value, pathPrefix);
7458
+ rejectUnknownKeys(record, CONTRACT_OBSERVATION_KEYS, pathPrefix);
7459
+ const out = {};
7460
+ if (record.required !== void 0) {
7461
+ out.required = requireBoundedStringArray(record.required, `${pathPrefix}.required`);
7462
+ }
7463
+ if (record.failOn !== void 0) {
7464
+ const items = requireBoundedArray(record.failOn, `${pathPrefix}.failOn`, CONTRACT_MAX_STRING_LIST);
7465
+ for (const item of items) {
7466
+ if (typeof item !== "string" || !CONTRACT_FAIL_ON.has(item)) {
7467
+ throw new CheckConfigError(
7468
+ "AI_CHECK_CONFIG_INVALID_VALUE",
7469
+ `${pathPrefix}.failOn values must be "failed", "unknown", or "skipped".`
7470
+ );
7471
+ }
7472
+ }
7473
+ out.failOn = items;
7474
+ }
7475
+ if (record.requireProvenance !== void 0) {
7476
+ out.requireProvenance = parseRequireProvenance(
7477
+ record.requireProvenance,
7478
+ `${pathPrefix}.requireProvenance`
7479
+ );
7480
+ }
7481
+ return out;
7482
+ }
7483
+ function parseControlRequiredStage(value, pathPrefix) {
7484
+ const record = requireObject(value, pathPrefix);
7485
+ rejectUnknownKeys(record, CONTRACT_CONTROL_STAGE_KEYS, pathPrefix);
7486
+ if (typeof record.stage !== "string" || !CONTRACT_CONTROL_STAGES.has(record.stage)) {
7487
+ throw new CheckConfigError(
7488
+ "AI_CHECK_CONFIG_INVALID_VALUE",
7489
+ `${pathPrefix}.stage must be one of: declared, presented, validated, enforced, observed, accepted.`
7490
+ );
7491
+ }
7492
+ const out = {
7493
+ stage: record.stage
7494
+ };
7495
+ if (record.observation !== void 0) {
7496
+ out.observation = requireNonEmptyString(record.observation, `${pathPrefix}.observation`);
7497
+ }
7498
+ return out;
7499
+ }
7500
+ function parseContractControlsSection(value, pathPrefix = "contract.controls") {
7501
+ const record = requireObject(value, pathPrefix);
7502
+ rejectUnknownKeys(record, CONTRACT_CONTROLS_KEYS, pathPrefix);
7503
+ const out = {};
7504
+ if (record.declaredTools !== void 0) {
7505
+ out.declaredTools = requireBoundedStringArray(
7506
+ record.declaredTools,
7507
+ `${pathPrefix}.declaredTools`
7508
+ );
7509
+ }
7510
+ if (record.enforcedTools !== void 0) {
7511
+ out.enforcedTools = requireBoundedStringArray(
7512
+ record.enforcedTools,
7513
+ `${pathPrefix}.enforcedTools`
7514
+ );
7515
+ }
7516
+ if (record.declaredToolsAttribute !== void 0) {
7517
+ out.declaredToolsAttribute = requireNonEmptyString(
7518
+ record.declaredToolsAttribute,
7519
+ `${pathPrefix}.declaredToolsAttribute`
7520
+ );
7521
+ }
7522
+ if (record.enforcedToolsAttribute !== void 0) {
7523
+ out.enforcedToolsAttribute = requireNonEmptyString(
7524
+ record.enforcedToolsAttribute,
7525
+ `${pathPrefix}.enforcedToolsAttribute`
7526
+ );
7527
+ }
7528
+ if (record.requireDeclaredMatchesEnforced !== void 0) {
7529
+ out.requireDeclaredMatchesEnforced = requireBoolean(
7530
+ record.requireDeclaredMatchesEnforced,
7531
+ `${pathPrefix}.requireDeclaredMatchesEnforced`
7532
+ );
7533
+ }
7534
+ if (record.requireObservedWithinEnforced !== void 0) {
7535
+ out.requireObservedWithinEnforced = requireBoolean(
7536
+ record.requireObservedWithinEnforced,
7537
+ `${pathPrefix}.requireObservedWithinEnforced`
7538
+ );
7539
+ }
7540
+ if (record.requireObservedWithinDeclared !== void 0) {
7541
+ out.requireObservedWithinDeclared = requireBoolean(
7542
+ record.requireObservedWithinDeclared,
7543
+ `${pathPrefix}.requireObservedWithinDeclared`
7544
+ );
7545
+ }
7546
+ if (record.requiredStages !== void 0) {
7547
+ const items = requireBoundedArray(
7548
+ record.requiredStages,
7549
+ `${pathPrefix}.requiredStages`,
7550
+ CONTRACT_MAX_REQUIRED_STAGES
7551
+ );
7552
+ out.requiredStages = items.map(
7553
+ (item, index) => parseControlRequiredStage(item, `${pathPrefix}.requiredStages[${index}]`)
7554
+ );
7555
+ }
7556
+ return out;
7557
+ }
7558
+ function parseRecoveryOperation(value, pathPrefix) {
7559
+ const record = requireObject(value, pathPrefix);
7560
+ rejectUnknownKeys(record, CONTRACT_OPERATION_KEYS, pathPrefix);
7561
+ const out = {
7562
+ tool: requireNonEmptyString(record.tool, `${pathPrefix}.tool`)
7563
+ };
7564
+ if (record.maxAttempts !== void 0) {
7565
+ out.maxAttempts = requireNonNegativeNumber(record.maxAttempts, `${pathPrefix}.maxAttempts`);
7566
+ }
7567
+ if (record.retryableErrors !== void 0) {
7568
+ const errors = requireObject(record.retryableErrors, `${pathPrefix}.retryableErrors`);
7569
+ rejectUnknownKeys(errors, CONTRACT_RETRYABLE_ERRORS_KEYS, `${pathPrefix}.retryableErrors`);
7570
+ const retryableErrors = {};
7571
+ if (errors.codes !== void 0) {
7572
+ retryableErrors.codes = requireBoundedStringArray(
7573
+ errors.codes,
7574
+ `${pathPrefix}.retryableErrors.codes`
7575
+ );
7576
+ }
7577
+ out.retryableErrors = retryableErrors;
7578
+ }
7579
+ if (record.requireFailureBeforeRetry !== void 0) {
7580
+ out.requireFailureBeforeRetry = requireBoolean(
7581
+ record.requireFailureBeforeRetry,
7582
+ `${pathPrefix}.requireFailureBeforeRetry`
7583
+ );
7584
+ }
7585
+ if (record.requireSameArguments !== void 0) {
7586
+ if (record.requireSameArguments === true || record.requireSameArguments === false) {
7587
+ out.requireSameArguments = record.requireSameArguments;
7588
+ } else if (record.requireSameArguments === "structured-or-digest") {
7589
+ out.requireSameArguments = "structured-or-digest";
7590
+ } else {
7591
+ throw new CheckConfigError(
7592
+ "AI_CHECK_CONFIG_INVALID_VALUE",
7593
+ `${pathPrefix}.requireSameArguments must be a boolean or "structured-or-digest".`
7594
+ );
7595
+ }
7596
+ }
7597
+ if (record.requireTerminalSuccess !== void 0) {
7598
+ out.requireTerminalSuccess = requireBoolean(
7599
+ record.requireTerminalSuccess,
7600
+ `${pathPrefix}.requireTerminalSuccess`
7601
+ );
7602
+ }
7603
+ if (record.requireRecoveredFailureVisible !== void 0) {
7604
+ out.requireRecoveredFailureVisible = requireBoolean(
7605
+ record.requireRecoveredFailureVisible,
7606
+ `${pathPrefix}.requireRecoveredFailureVisible`
7607
+ );
7608
+ }
7609
+ if (record.successfulResultDependency !== void 0) {
7610
+ const dep = requireObject(
7611
+ record.successfulResultDependency,
7612
+ `${pathPrefix}.successfulResultDependency`
7613
+ );
7614
+ rejectUnknownKeys(dep, CONTRACT_RESULT_DEP_KEYS, `${pathPrefix}.successfulResultDependency`);
7615
+ if (dep.consumerKind !== "LLM") {
7616
+ throw new CheckConfigError(
7617
+ "AI_CHECK_CONFIG_INVALID_VALUE",
7618
+ `${pathPrefix}.successfulResultDependency.consumerKind must be "LLM".`
7619
+ );
7620
+ }
7621
+ const dependency = { consumerKind: "LLM" };
7622
+ if (dep.requireExplicitReference !== void 0) {
7623
+ dependency.requireExplicitReference = requireBoolean(
7624
+ dep.requireExplicitReference,
7625
+ `${pathPrefix}.successfulResultDependency.requireExplicitReference`
7626
+ );
7627
+ }
7628
+ out.successfulResultDependency = dependency;
7629
+ }
7630
+ if (record.sideEffectClass !== void 0) {
7631
+ if (typeof record.sideEffectClass !== "string" || !CONTRACT_SIDE_EFFECT_CLASSES.has(record.sideEffectClass)) {
7632
+ throw new CheckConfigError(
7633
+ "AI_CHECK_CONFIG_INVALID_VALUE",
7634
+ `${pathPrefix}.sideEffectClass must be "read" or "write".`
7635
+ );
7636
+ }
7637
+ out.sideEffectClass = record.sideEffectClass;
7638
+ }
7639
+ return out;
7640
+ }
7641
+ function parseContractRetrySection(value, pathPrefix = "contract.retry") {
7642
+ const record = requireObject(value, pathPrefix);
7643
+ rejectUnknownKeys(record, CONTRACT_RETRY_KEYS, pathPrefix);
7644
+ const out = {};
7645
+ if (record.maxAttempts !== void 0) {
7646
+ out.maxAttempts = requireNonNegativeNumber(record.maxAttempts, `${pathPrefix}.maxAttempts`);
7647
+ }
7648
+ if (record.requireTerminalResult !== void 0) {
7649
+ out.requireTerminalResult = requireBoolean(
7650
+ record.requireTerminalResult,
7651
+ `${pathPrefix}.requireTerminalResult`
7652
+ );
7653
+ }
7654
+ if (record.fallbackOnlyAfterFailure !== void 0) {
7655
+ out.fallbackOnlyAfterFailure = requireBoolean(
7656
+ record.fallbackOnlyAfterFailure,
7657
+ `${pathPrefix}.fallbackOnlyAfterFailure`
7658
+ );
7659
+ }
7660
+ if (record.nonIdempotentTools !== void 0) {
7661
+ out.nonIdempotentTools = requireBoundedStringArray(
7662
+ record.nonIdempotentTools,
7663
+ `${pathPrefix}.nonIdempotentTools`
7664
+ );
7665
+ }
7666
+ if (record.requireIdempotencyEvidenceForRetry !== void 0) {
7667
+ out.requireIdempotencyEvidenceForRetry = requireBoolean(
7668
+ record.requireIdempotencyEvidenceForRetry,
7669
+ `${pathPrefix}.requireIdempotencyEvidenceForRetry`
7670
+ );
7671
+ }
7672
+ if (record.requireRecoveredFailureVisible !== void 0) {
7673
+ out.requireRecoveredFailureVisible = requireBoolean(
7674
+ record.requireRecoveredFailureVisible,
7675
+ `${pathPrefix}.requireRecoveredFailureVisible`
7676
+ );
7677
+ }
7678
+ if (record.operations !== void 0) {
7679
+ const items = requireBoundedArray(
7680
+ record.operations,
7681
+ `${pathPrefix}.operations`,
7682
+ CONTRACT_MAX_OPERATIONS
7683
+ );
7684
+ out.operations = items.map(
7685
+ (item, index) => parseRecoveryOperation(item, `${pathPrefix}.operations[${index}]`)
7686
+ );
7687
+ }
7688
+ return out;
7689
+ }
7690
+ function parseContractScopeSection(value) {
7691
+ const record = requireObject(value, "contract.scope");
7692
+ rejectUnknownKeys(record, CONTRACT_SCOPE_KEYS, "contract.scope");
7693
+ const out = {};
7694
+ if (record.runId !== void 0) {
7695
+ out.runId = requireNonEmptyString(record.runId, "contract.scope.runId");
7696
+ }
7697
+ if (record.subAgentId !== void 0) {
7698
+ out.subAgentId = requireNonEmptyString(record.subAgentId, "contract.scope.subAgentId");
7699
+ }
7700
+ if (record.groupId !== void 0) {
7701
+ out.groupId = requireNonEmptyString(record.groupId, "contract.scope.groupId");
7702
+ }
7703
+ if (record.workflowStep !== void 0) {
7704
+ out.workflowStep = requireNonEmptyString(
7705
+ record.workflowStep,
7706
+ "contract.scope.workflowStep"
7707
+ );
7708
+ }
7709
+ if (record.rootEventId !== void 0) {
7710
+ out.rootEventId = requireNonEmptyString(record.rootEventId, "contract.scope.rootEventId");
7711
+ }
7712
+ return out;
7713
+ }
7714
+ function parseContractBodySection(value, pathPrefix) {
7715
+ const record = requireObject(value, pathPrefix);
7716
+ rejectUnknownKeys(record, CONTRACT_BODY_KEYS, pathPrefix);
7717
+ const out = {};
7718
+ if (record.run !== void 0) out.run = parseContractRunSection(record.run, `${pathPrefix}.run`);
7719
+ if (record.tools !== void 0) {
7720
+ out.tools = parseContractToolsSection(record.tools, `${pathPrefix}.tools`);
7721
+ }
7722
+ if (record.llm !== void 0) out.llm = parseContractLlmSection(record.llm, `${pathPrefix}.llm`);
7723
+ if (record.observations !== void 0) {
7724
+ out.observations = parseContractObservationsSection(
7725
+ record.observations,
7726
+ `${pathPrefix}.observations`
7727
+ );
7728
+ }
7729
+ if (record.controls !== void 0) {
7730
+ out.controls = parseContractControlsSection(record.controls, `${pathPrefix}.controls`);
7731
+ }
7732
+ if (record.retry !== void 0) {
7733
+ out.retry = parseContractRetrySection(record.retry, `${pathPrefix}.retry`);
7734
+ }
7735
+ return out;
7736
+ }
7737
+ function parseContractAlternativesSection(value) {
7738
+ const record = requireObject(value, "contract.alternatives");
7739
+ rejectUnknownKeys(record, CONTRACT_ALT_KEYS, "contract.alternatives");
7740
+ if (record.anyOf === void 0) {
7741
+ throw new CheckConfigError(
7742
+ "AI_CHECK_CONFIG_INVALID_VALUE",
7743
+ "contract.alternatives.anyOf is required."
7744
+ );
7745
+ }
7746
+ const items = requireBoundedArray(
7747
+ record.anyOf,
7748
+ "contract.alternatives.anyOf",
7749
+ CONTRACT_MAX_ANY_OF
7750
+ );
7751
+ const anyOf = items.map((item, index) => {
7752
+ const pathPrefix = `contract.alternatives.anyOf[${index}]`;
7753
+ const branch = requireObject(item, pathPrefix);
7754
+ rejectUnknownKeys(branch, CONTRACT_ALT_BRANCH_KEYS, pathPrefix);
7755
+ const id = requireNonEmptyString(branch.id, `${pathPrefix}.id`);
7756
+ if (branch.contract === void 0) {
7757
+ throw new CheckConfigError(
7758
+ "AI_CHECK_CONFIG_INVALID_VALUE",
7759
+ `${pathPrefix}.contract is required.`
7760
+ );
7761
+ }
7762
+ const out = {
7763
+ id,
7764
+ contract: parseContractBodySection(branch.contract, `${pathPrefix}.contract`)
7765
+ };
7766
+ if (branch.description !== void 0) {
7767
+ out.description = requireNonEmptyString(branch.description, `${pathPrefix}.description`);
7768
+ }
7769
+ return out;
7770
+ });
7771
+ return { anyOf };
7772
+ }
7773
+ function parseContractSection(value) {
7774
+ const record = requireObject(value, "contract");
7775
+ rejectUnknownKeys(record, CONTRACT_KEYS, "contract");
7776
+ const bodyOnly = {};
7777
+ for (const key of Object.keys(record)) {
7778
+ if (CONTRACT_BODY_KEYS.has(key)) bodyOnly[key] = record[key];
7779
+ }
7780
+ const out = { ...parseContractBodySection(bodyOnly, "contract") };
7781
+ if (record.scope !== void 0) out.scope = parseContractScopeSection(record.scope);
7782
+ if (record.alternatives !== void 0) {
7783
+ out.alternatives = parseContractAlternativesSection(record.alternatives);
7784
+ }
7785
+ return out;
7786
+ }
7075
7787
  function parseCheckConfig(value) {
7076
7788
  if (value === void 0 || value === null) return {};
7077
7789
  if (typeof value !== "object" || Array.isArray(value)) {
7078
7790
  throw new CheckConfigError("AI_CHECK_CONFIG_INVALID_VALUE", "Config must export an object.");
7079
7791
  }
7080
7792
  const root = value;
7081
- if ("contract" in root) {
7082
- throw new CheckConfigError(
7083
- "AI_CHECK_CONFIG_UNKNOWN_KEY",
7084
- 'Top-level "contract" is not supported by `agent-inspect check --config`. Use the TraceContract TypeScript API (`defineTraceContract` / `evaluateTraceContract` from `agent-inspect/checks`), or express tool/run/llm rules under `checks`.'
7085
- );
7086
- }
7087
7793
  const rootKeys = Object.keys(root);
7088
7794
  for (const key of rootKeys) {
7089
- if (key === "checks") continue;
7090
- const suggestion = closestKey(key, ["checks"]);
7795
+ if (ROOT_CONFIG_KEYS.has(key)) continue;
7796
+ const suggestion = closestKey(key, [...ROOT_CONFIG_KEYS]);
7091
7797
  const hint = suggestion ? ` Did you mean "${suggestion}"?` : "";
7092
7798
  throw new CheckConfigError(
7093
7799
  "AI_CHECK_CONFIG_UNKNOWN_KEY",
7094
- `Unknown top-level check config key "${key}". Allowed: checks.${hint}`
7800
+ `Unknown top-level check config key "${key}". Allowed: checks, contract.${hint}`
7095
7801
  );
7096
7802
  }
7097
- if (!("checks" in root)) return {};
7098
- const checksRecord = requireObject(root.checks, "checks");
7099
- rejectUnknownKeys(checksRecord, CHECKS_KEYS, "checks");
7100
- const checks2 = {};
7101
- if (checksRecord.select !== void 0) {
7102
- checks2.select = requireStringArray(checksRecord.select, "checks.select");
7803
+ const out = {};
7804
+ if ("checks" in root) {
7805
+ const checksRecord = requireObject(root.checks, "checks");
7806
+ rejectUnknownKeys(checksRecord, CHECKS_KEYS, "checks");
7807
+ const checks2 = {};
7808
+ if (checksRecord.select !== void 0) {
7809
+ checks2.select = requireStringArray(checksRecord.select, "checks.select");
7810
+ }
7811
+ if (checksRecord.run !== void 0) checks2.run = parseRunSection(checksRecord.run);
7812
+ if (checksRecord.tool !== void 0) checks2.tool = parseToolSection(checksRecord.tool);
7813
+ if (checksRecord.llm !== void 0) checks2.llm = parseLlmSection(checksRecord.llm);
7814
+ if (checksRecord.structure !== void 0) {
7815
+ checks2.structure = parseStructureSection(checksRecord.structure);
7816
+ }
7817
+ if (checksRecord.safety !== void 0) checks2.safety = parseSafetySection(checksRecord.safety);
7818
+ out.checks = checks2;
7103
7819
  }
7104
- if (checksRecord.run !== void 0) checks2.run = parseRunSection(checksRecord.run);
7105
- if (checksRecord.tool !== void 0) checks2.tool = parseToolSection(checksRecord.tool);
7106
- if (checksRecord.llm !== void 0) checks2.llm = parseLlmSection(checksRecord.llm);
7107
- if (checksRecord.structure !== void 0) {
7108
- checks2.structure = parseStructureSection(checksRecord.structure);
7820
+ if ("contract" in root) {
7821
+ out.contract = parseContractSection(root.contract);
7822
+ }
7823
+ if (out.contract !== void 0 && contractConfigHasEffect(out.contract) && checkConfigHasEffect({ checks: out.checks })) {
7824
+ throw new CheckConfigError(
7825
+ "AI_CHECK_CONFIG_INVALID_VALUE",
7826
+ 'Config cannot combine top-level "checks" and "contract". Use one vocabulary per config file.'
7827
+ );
7109
7828
  }
7110
- if (checksRecord.safety !== void 0) checks2.safety = parseSafetySection(checksRecord.safety);
7111
- return { checks: checks2 };
7829
+ return out;
7112
7830
  }
7113
7831
  async function loadConfig(configPath) {
7114
7832
  if (configPath === void 0) return {};
@@ -7436,6 +8154,7 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
7436
8154
  let evidenceRead;
7437
8155
  let evidenceRunIds = [];
7438
8156
  let evidenceSourceContents;
8157
+ let evidenceContract;
7439
8158
  const sessionId = options.session?.trim();
7440
8159
  const groupId = options.group?.trim();
7441
8160
  const useSessionScope = Boolean(sessionId || groupId);
@@ -7444,7 +8163,7 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
7444
8163
  if (options.config !== void 0 && !checkConfigHasEffect(config)) {
7445
8164
  result = errorResult(
7446
8165
  "AI_CHECK_CONFIG_NO_EFFECTIVE_RULES",
7447
- "Explicit --config has no effective check rules. Configure checks.select, checks.run, checks.tool, checks.llm, checks.structure, or checks.safety."
8166
+ "Explicit --config has no effective check rules. Configure checks.select, checks.run, checks.tool, checks.llm, checks.structure, checks.safety, or contract."
7448
8167
  );
7449
8168
  if (options.json) printJson2(result);
7450
8169
  else printHuman2(result, options);
@@ -7452,7 +8171,11 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
7452
8171
  return;
7453
8172
  }
7454
8173
  let effectiveOptions = options;
7455
- const resolved = resolvePreset(options.preset, {
8174
+ const useContract = config.contract !== void 0 && contractConfigHasEffect(config.contract);
8175
+ if (useContract) {
8176
+ evidenceContract = defineTraceContract(config.contract);
8177
+ }
8178
+ const resolved = useContract ? void 0 : resolvePreset(options.preset, {
7456
8179
  hasToolRules: hasToolRulesConfigured(config, options)
7457
8180
  });
7458
8181
  if (resolved !== void 0) {
@@ -7460,7 +8183,7 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
7460
8183
  config = applied.config;
7461
8184
  effectiveOptions = applied.options;
7462
8185
  }
7463
- const built = buildRules(config, effectiveOptions, resolved?.select ?? []);
8186
+ const built = useContract ? { rules: [], select: [], diagnostics: [] } : buildRules(config, effectiveOptions, resolved?.select ?? []);
7464
8187
  if (built.diagnostics.some((item) => item.severity === "error")) {
7465
8188
  result = errorResult("AI_CHECK_INVALID_CONFIG", "Invalid check configuration.");
7466
8189
  result.diagnostics = [...built.diagnostics];
@@ -7482,6 +8205,7 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
7482
8205
  });
7483
8206
  const perRun = [];
7484
8207
  const sourceContents = /* @__PURE__ */ new Map();
8208
+ const definedContract = evidenceContract;
7485
8209
  for (const meta of scoped.metas) {
7486
8210
  const read = await openTrace(
7487
8211
  { type: "file", path: meta.filePath },
@@ -7498,23 +8222,20 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
7498
8222
  `
7499
8223
  );
7500
8224
  }
8225
+ const base = definedContract ? evaluateTraceContract({ read }, definedContract, { runId: meta.runId }) : runTraceChecks(
8226
+ { read },
8227
+ {
8228
+ rules: built.rules,
8229
+ select: built.select,
8230
+ runId: meta.runId
8231
+ }
8232
+ );
7501
8233
  perRun.push(
7502
- mergeSafetyExtensions(
7503
- runTraceChecks(
7504
- { read },
7505
- {
7506
- rules: built.rules,
7507
- select: built.select,
7508
- runId: meta.runId
7509
- }
7510
- ),
7511
- read,
7512
- {
7513
- ...options.guardrails ? { guardrails: options.guardrails } : {},
7514
- ...options.circuit ? { circuits: options.circuit } : {},
7515
- runId: meta.runId
7516
- }
7517
- )
8234
+ mergeSafetyExtensions(base, read, {
8235
+ ...options.guardrails ? { guardrails: options.guardrails } : {},
8236
+ ...options.circuit ? { circuits: options.circuit } : {},
8237
+ runId: meta.runId
8238
+ })
7518
8239
  );
7519
8240
  }
7520
8241
  evidenceRunIds = scoped.runIds;
@@ -7553,22 +8274,25 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
7553
8274
  ])
7554
8275
  );
7555
8276
  }
7556
- result = mergeSafetyExtensions(
7557
- runTraceChecks(
7558
- { read },
7559
- {
7560
- rules: built.rules,
7561
- select: built.select,
7562
- ...options.run !== void 0 ? { runId: options.run } : {}
7563
- }
7564
- ),
7565
- read,
8277
+ const base = useContract && evidenceContract !== void 0 ? evaluateTraceContract(
8278
+ { read },
8279
+ evidenceContract,
8280
+ {
8281
+ ...options.run !== void 0 ? { runId: options.run } : {}
8282
+ }
8283
+ ) : runTraceChecks(
8284
+ { read },
7566
8285
  {
7567
- ...options.guardrails ? { guardrails: options.guardrails } : {},
7568
- ...options.circuit ? { circuits: options.circuit } : {},
8286
+ rules: built.rules,
8287
+ select: built.select,
7569
8288
  ...options.run !== void 0 ? { runId: options.run } : {}
7570
8289
  }
7571
8290
  );
8291
+ result = mergeSafetyExtensions(base, read, {
8292
+ ...options.guardrails ? { guardrails: options.guardrails } : {},
8293
+ ...options.circuit ? { circuits: options.circuit } : {},
8294
+ ...options.run !== void 0 ? { runId: options.run } : {}
8295
+ });
7572
8296
  }
7573
8297
  } catch (error) {
7574
8298
  if (phase === "config") {
@@ -7612,7 +8336,15 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
7612
8336
  checkResultsJson: checkResultToEvidenceJson(result, runIds),
7613
8337
  summaryText: `Check status: ${result.status}`,
7614
8338
  redactionProfile,
7615
- format: evidenceFormat
8339
+ format: evidenceFormat,
8340
+ ...evidenceContract !== void 0 ? {
8341
+ contractPackage: {
8342
+ engineVersion: "",
8343
+ source: "file",
8344
+ contract: evidenceContract,
8345
+ ...options.config !== void 0 ? { path: options.config } : {}
8346
+ }
8347
+ } : {}
7616
8348
  });
7617
8349
  if (!options.json) {
7618
8350
  console.log(`Evidence: ${written}`);
@@ -12173,7 +12905,7 @@ function isModuleNotFound4(e) {
12173
12905
  }
12174
12906
  async function loadIndexSqlite() {
12175
12907
  try {
12176
- return await import('./src-XNC4EUN3.mjs');
12908
+ return await import('./src-ZUGAUXY6.mjs');
12177
12909
  } catch (e) {
12178
12910
  if (isModuleNotFound4(e)) {
12179
12911
  console.error(
@@ -13123,7 +13855,7 @@ function createCliProgram() {
13123
13855
  "add run.maxStepDuration (e.g. 30s, 5m)"
13124
13856
  ).option("--require-completed", "add run.requireCompleted").option("--detect-stalls", "add run.stall for running or incomplete events").option(
13125
13857
  "--fail-on-observation <status>",
13126
- "fail when observed outcomes match status (passed, failed, unknown, skipped; comma-separated)"
13858
+ "outcome gate: require \u22651 OUTCOME and fail when status matches (passed,failed,unknown,skipped; comma-separated). Does not invent outcomes from tool/LLM/run success; use --preset trajectory for structural checks"
13127
13859
  ).option("--session <id>", "check all runs in a workflow session (requires --dir)").option("--group <id>", "check all runs sharing a groupId (requires --dir)").option(
13128
13860
  "--correlate-group",
13129
13861
  "when using --session, also match synthetic group: session keys"
@@ -13136,7 +13868,7 @@ function createCliProgram() {
13136
13868
  "run optional circuit rules (repeatable): same-tool-repetition, max-retries, ...",
13137
13869
  (value, previous = []) => [...previous, value]
13138
13870
  ).addOption(
13139
- new Option("--preset <name>", "additive check preset").choices(["trajectory", "safety", "comprehensive", "behavioral-session"])
13871
+ new Option("--preset <name>", "additive check preset (trajectory=structure only; safety=share checks; not interchangeable)").choices(["trajectory", "safety", "comprehensive", "behavioral-session"])
13140
13872
  ).addOption(
13141
13873
  new Option(
13142
13874
  "--evidence-on <mode>",