@tangle-network/agent-interface 0.25.0 → 0.26.1
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 +2 -2
- package/dist/agent-candidate-artifact-schema.d.ts +5 -5
- package/dist/agent-candidate-artifact-schema.js +30 -5
- package/dist/agent-candidate-code-schema.d.ts +3 -3
- package/dist/agent-candidate-execution-plan-schema.d.ts +149 -46
- package/dist/agent-candidate-execution-plan-schema.js +81 -9
- package/dist/agent-candidate-lineage-schema.d.ts +90 -3
- package/dist/agent-candidate-lineage-schema.js +17 -3
- package/dist/agent-candidate-outcome-schema.d.ts +259 -395
- package/dist/agent-candidate-outcome-schema.js +75 -64
- package/dist/agent-candidate-promotion-schema.d.ts +2708 -0
- package/dist/agent-candidate-promotion-schema.js +409 -0
- package/dist/agent-candidate-receipt-schema.d.ts +238 -1333
- package/dist/agent-candidate-receipt-schema.js +7 -116
- package/dist/agent-candidate-schema-common.d.ts +2 -0
- package/dist/agent-candidate-schema-common.js +8 -0
- package/dist/agent-candidate-schema.d.ts +94 -7
- package/dist/agent-candidate-schema.js +1 -1
- package/dist/agent-candidate.d.ts +251 -87
- package/dist/agent-candidate.test-fixture.d.ts +45 -11
- package/dist/agent-candidate.test-fixture.js +46 -12
- package/dist/agent-profile.js +5 -20
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { agentCandidateBundleSchema } from "./agent-candidate-schema.js";
|
|
3
|
+
import { agentCandidateProfileActivationSchema } from "./agent-candidate-execution-plan-schema.js";
|
|
4
|
+
import { isCanonicalJsonValue, sha256DigestSchema, } from "./agent-candidate-schema-common.js";
|
|
5
|
+
import { agentCandidateMaterializationReceiptSchema, agentCandidateRunReceiptSchema, } from "./agent-candidate-receipt-schema.js";
|
|
6
|
+
import { agentProfileSchema } from "./profile-schema.js";
|
|
7
|
+
const canonicalJsonSchema = z.custom(isCanonicalJsonValue, "value must be finite, acyclic RFC 8785 JSON");
|
|
8
|
+
const canonicalJsonObjectSchema = z
|
|
9
|
+
.record(z.string(), canonicalJsonSchema)
|
|
10
|
+
.refine(isCanonicalJsonValue, "value must be finite, acyclic RFC 8785 JSON");
|
|
11
|
+
const confidenceIntervalSchema = z
|
|
12
|
+
.object({
|
|
13
|
+
level: z.number().finite().gt(0).lt(1),
|
|
14
|
+
lower: z.number().finite(),
|
|
15
|
+
upper: z.number().finite(),
|
|
16
|
+
method: z.literal("paired-bootstrap"),
|
|
17
|
+
statistic: z.literal("mean"),
|
|
18
|
+
resamples: z.number().int().positive(),
|
|
19
|
+
})
|
|
20
|
+
.strict();
|
|
21
|
+
const measuredEstimateFields = {
|
|
22
|
+
baseline: z.number().finite(),
|
|
23
|
+
candidate: z.number().finite(),
|
|
24
|
+
delta: z.number().finite(),
|
|
25
|
+
confidenceInterval: confidenceIntervalSchema,
|
|
26
|
+
n: z.number().int().positive(),
|
|
27
|
+
};
|
|
28
|
+
const qualityObjectiveFields = {
|
|
29
|
+
kind: z.literal("objective"),
|
|
30
|
+
name: z.string().min(1),
|
|
31
|
+
direction: z.literal("higher-is-better"),
|
|
32
|
+
unit: z.literal("score"),
|
|
33
|
+
};
|
|
34
|
+
const qualityDimensionFields = {
|
|
35
|
+
kind: z.literal("dimension"),
|
|
36
|
+
objective: z.string().min(1),
|
|
37
|
+
name: z.string().min(1),
|
|
38
|
+
direction: z.literal("higher-is-better"),
|
|
39
|
+
unit: z.literal("score"),
|
|
40
|
+
};
|
|
41
|
+
const costObjectiveFields = {
|
|
42
|
+
kind: z.literal("cost"),
|
|
43
|
+
name: z.literal("cost"),
|
|
44
|
+
direction: z.literal("lower-is-better"),
|
|
45
|
+
unit: z.literal("usd"),
|
|
46
|
+
};
|
|
47
|
+
const latencyObjectiveFields = {
|
|
48
|
+
kind: z.literal("latency"),
|
|
49
|
+
name: z.literal("latency"),
|
|
50
|
+
direction: z.literal("lower-is-better"),
|
|
51
|
+
unit: z.literal("milliseconds"),
|
|
52
|
+
};
|
|
53
|
+
function measuredObjectiveVariant(fields) {
|
|
54
|
+
return z
|
|
55
|
+
.object({
|
|
56
|
+
...fields,
|
|
57
|
+
availability: z.literal("measured"),
|
|
58
|
+
...measuredEstimateFields,
|
|
59
|
+
})
|
|
60
|
+
.strict();
|
|
61
|
+
}
|
|
62
|
+
function unavailableObjectiveVariant(fields) {
|
|
63
|
+
return z
|
|
64
|
+
.object({
|
|
65
|
+
...fields,
|
|
66
|
+
availability: z.literal("unavailable"),
|
|
67
|
+
reason: z.string().min(1),
|
|
68
|
+
})
|
|
69
|
+
.strict();
|
|
70
|
+
}
|
|
71
|
+
const measuredObjectiveSchema = z.union([
|
|
72
|
+
measuredObjectiveVariant(qualityObjectiveFields),
|
|
73
|
+
unavailableObjectiveVariant(qualityObjectiveFields),
|
|
74
|
+
measuredObjectiveVariant(qualityDimensionFields),
|
|
75
|
+
unavailableObjectiveVariant(qualityDimensionFields),
|
|
76
|
+
measuredObjectiveVariant(costObjectiveFields),
|
|
77
|
+
unavailableObjectiveVariant(costObjectiveFields),
|
|
78
|
+
measuredObjectiveVariant(latencyObjectiveFields),
|
|
79
|
+
unavailableObjectiveVariant(latencyObjectiveFields),
|
|
80
|
+
]);
|
|
81
|
+
const improvementSurfaceSchema = z.enum([
|
|
82
|
+
"prompt",
|
|
83
|
+
"skills",
|
|
84
|
+
"tools",
|
|
85
|
+
"mcp",
|
|
86
|
+
"hooks",
|
|
87
|
+
"subagents",
|
|
88
|
+
"agent-profile",
|
|
89
|
+
"memory",
|
|
90
|
+
"code",
|
|
91
|
+
"knowledge",
|
|
92
|
+
]);
|
|
93
|
+
export const agentImprovementMeasuredComparisonSchema = z
|
|
94
|
+
.object({
|
|
95
|
+
schemaVersion: z.literal(1),
|
|
96
|
+
kind: z.literal("agent-improvement-measured-comparison"),
|
|
97
|
+
benchmark: z
|
|
98
|
+
.object({
|
|
99
|
+
name: z.string().min(1),
|
|
100
|
+
version: z.string().min(1),
|
|
101
|
+
splitDigest: sha256DigestSchema,
|
|
102
|
+
})
|
|
103
|
+
.strict(),
|
|
104
|
+
baselineProfileDigest: sha256DigestSchema,
|
|
105
|
+
candidateBundleDigest: sha256DigestSchema,
|
|
106
|
+
overall: z
|
|
107
|
+
.object({
|
|
108
|
+
name: z.literal("composite"),
|
|
109
|
+
...measuredEstimateFields,
|
|
110
|
+
direction: z.literal("higher-is-better"),
|
|
111
|
+
unit: z.literal("score"),
|
|
112
|
+
})
|
|
113
|
+
.strict(),
|
|
114
|
+
objectives: z.array(measuredObjectiveSchema),
|
|
115
|
+
candidate: z
|
|
116
|
+
.object({
|
|
117
|
+
label: z.string().min(1).optional(),
|
|
118
|
+
rationale: z.string().min(1).optional(),
|
|
119
|
+
})
|
|
120
|
+
.strict()
|
|
121
|
+
.refine((candidate) => candidate.label !== undefined || candidate.rationale !== undefined, "candidate metadata requires a label or rationale")
|
|
122
|
+
.optional(),
|
|
123
|
+
decision: z
|
|
124
|
+
.object({
|
|
125
|
+
outcome: z.enum([
|
|
126
|
+
"ship",
|
|
127
|
+
"hold",
|
|
128
|
+
"need_more_work",
|
|
129
|
+
"model_ceiling",
|
|
130
|
+
"arch_ceiling",
|
|
131
|
+
]),
|
|
132
|
+
reasons: z.array(z.string().min(1)).min(1),
|
|
133
|
+
contributingChecks: z.array(z.object({ name: z.string().min(1), passed: z.boolean() }).strict()),
|
|
134
|
+
})
|
|
135
|
+
.strict(),
|
|
136
|
+
power: z
|
|
137
|
+
.object({
|
|
138
|
+
sufficient: z.boolean(),
|
|
139
|
+
n: z.number().int().positive(),
|
|
140
|
+
minimumDetectableDelta: z.number().finite().nonnegative(),
|
|
141
|
+
confidenceLevel: z.number().finite().gt(0).lt(1),
|
|
142
|
+
scaleAssumed: z.boolean(),
|
|
143
|
+
sharedScorerChannel: z.boolean(),
|
|
144
|
+
reason: z.string().min(1),
|
|
145
|
+
})
|
|
146
|
+
.strict(),
|
|
147
|
+
provenance: z
|
|
148
|
+
.object({
|
|
149
|
+
kind: z.literal("agent-eval-loop"),
|
|
150
|
+
schema: z.string().min(1),
|
|
151
|
+
runId: z.string().min(1),
|
|
152
|
+
recordDigest: sha256DigestSchema,
|
|
153
|
+
baselineContentHash: z.string().regex(/^(?:sha256:)?[a-f0-9]{64}$/),
|
|
154
|
+
candidateContentHash: z.string().regex(/^(?:sha256:)?[a-f0-9]{64}$/),
|
|
155
|
+
})
|
|
156
|
+
.strict(),
|
|
157
|
+
diff: z.string(),
|
|
158
|
+
evaluation: z
|
|
159
|
+
.object({
|
|
160
|
+
generationsExplored: z.number().int().nonnegative(),
|
|
161
|
+
durationMs: z.number().finite().nonnegative(),
|
|
162
|
+
totalCostUsd: z.number().finite().nonnegative(),
|
|
163
|
+
})
|
|
164
|
+
.strict(),
|
|
165
|
+
metadata: canonicalJsonObjectSchema.optional(),
|
|
166
|
+
})
|
|
167
|
+
.strict()
|
|
168
|
+
.superRefine((comparison, ctx) => {
|
|
169
|
+
refineEstimate(comparison.overall, ["overall"], ctx);
|
|
170
|
+
const identities = new Set();
|
|
171
|
+
const qualityObjectives = new Set();
|
|
172
|
+
const dimensionParents = [];
|
|
173
|
+
let costCount = 0;
|
|
174
|
+
let latencyCount = 0;
|
|
175
|
+
for (const [index, objective] of comparison.objectives.entries()) {
|
|
176
|
+
if (objective.availability === "measured") {
|
|
177
|
+
refineEstimate(objective, ["objectives", index], ctx);
|
|
178
|
+
}
|
|
179
|
+
const identity = objective.kind === "dimension"
|
|
180
|
+
? `${objective.kind}:${objective.objective}:${objective.name}`
|
|
181
|
+
: `${objective.kind}:${objective.name}`;
|
|
182
|
+
if (identities.has(identity)) {
|
|
183
|
+
ctx.addIssue({
|
|
184
|
+
code: "custom",
|
|
185
|
+
path: ["objectives", index, "name"],
|
|
186
|
+
message: "measured objective identities must be unique",
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
identities.add(identity);
|
|
190
|
+
if (objective.kind === "objective") {
|
|
191
|
+
qualityObjectives.add(objective.name);
|
|
192
|
+
}
|
|
193
|
+
else if (objective.kind === "dimension") {
|
|
194
|
+
dimensionParents.push({ index, objective: objective.objective });
|
|
195
|
+
}
|
|
196
|
+
else if (objective.kind === "cost") {
|
|
197
|
+
costCount += 1;
|
|
198
|
+
}
|
|
199
|
+
else if (objective.kind === "latency") {
|
|
200
|
+
latencyCount += 1;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
if (costCount !== 1 || latencyCount !== 1) {
|
|
204
|
+
ctx.addIssue({
|
|
205
|
+
code: "custom",
|
|
206
|
+
path: ["objectives"],
|
|
207
|
+
message: "measured comparison must contain exactly one cost and latency objective",
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
if (qualityObjectives.size === 0) {
|
|
211
|
+
ctx.addIssue({
|
|
212
|
+
code: "custom",
|
|
213
|
+
path: ["objectives"],
|
|
214
|
+
message: "measured comparison must contain at least one quality objective",
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
for (const parent of dimensionParents) {
|
|
218
|
+
if (!qualityObjectives.has(parent.objective)) {
|
|
219
|
+
ctx.addIssue({
|
|
220
|
+
code: "custom",
|
|
221
|
+
path: ["objectives", parent.index, "objective"],
|
|
222
|
+
message: "measured dimension must name a present quality objective",
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (comparison.power.n !== comparison.overall.n) {
|
|
227
|
+
ctx.addIssue({
|
|
228
|
+
code: "custom",
|
|
229
|
+
path: ["power", "n"],
|
|
230
|
+
message: "power analysis must use the paired held-out sample",
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
if (!isCanonicalJsonValue(comparison)) {
|
|
234
|
+
ctx.addIssue({
|
|
235
|
+
code: "custom",
|
|
236
|
+
message: "measured comparison must contain only RFC 8785 JSON values",
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
export const agentImprovementProposalSchema = z
|
|
241
|
+
.object({
|
|
242
|
+
schemaVersion: z.literal(1),
|
|
243
|
+
kind: z.literal("agent-improvement-proposal"),
|
|
244
|
+
runId: z.string().min(1).max(200),
|
|
245
|
+
changedSurfaces: z
|
|
246
|
+
.tuple([improvementSurfaceSchema])
|
|
247
|
+
.rest(improvementSurfaceSchema)
|
|
248
|
+
.refine((surfaces) => new Set(surfaces).size === surfaces.length, "changed surfaces must be unique"),
|
|
249
|
+
proposedAt: z.iso.datetime(),
|
|
250
|
+
baselineProfile: agentProfileSchema,
|
|
251
|
+
findings: z.array(canonicalJsonObjectSchema),
|
|
252
|
+
evaluation: agentImprovementMeasuredComparisonSchema,
|
|
253
|
+
candidateBundle: agentCandidateBundleSchema,
|
|
254
|
+
digest: sha256DigestSchema,
|
|
255
|
+
})
|
|
256
|
+
.strict()
|
|
257
|
+
.superRefine((proposal, ctx) => {
|
|
258
|
+
const measuredBenchmark = proposal.evaluation.benchmark;
|
|
259
|
+
const bundleBenchmark = proposal.candidateBundle.lineage.benchmark;
|
|
260
|
+
if (!bundleBenchmark ||
|
|
261
|
+
measuredBenchmark.name !== bundleBenchmark.name ||
|
|
262
|
+
measuredBenchmark.version !== bundleBenchmark.version ||
|
|
263
|
+
measuredBenchmark.splitDigest !== bundleBenchmark.splitDigest) {
|
|
264
|
+
ctx.addIssue({
|
|
265
|
+
code: "custom",
|
|
266
|
+
path: ["evaluation", "benchmark"],
|
|
267
|
+
message: "measured comparison must bind the candidate development split",
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
if (proposal.evaluation.candidateBundleDigest !== proposal.candidateBundle.digest) {
|
|
271
|
+
ctx.addIssue({
|
|
272
|
+
code: "custom",
|
|
273
|
+
path: ["evaluation", "candidateBundleDigest"],
|
|
274
|
+
message: "measured comparison must bind the exact candidate bundle",
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
if (!isCanonicalJsonValue(proposal)) {
|
|
278
|
+
ctx.addIssue({
|
|
279
|
+
code: "custom",
|
|
280
|
+
message: "proposal must contain only RFC 8785 JSON values",
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
function refineEstimate(estimate, path, ctx) {
|
|
285
|
+
const expectedDelta = estimate.candidate - estimate.baseline;
|
|
286
|
+
const tolerance = Number.EPSILON * Math.max(1, Math.abs(expectedDelta)) * 8;
|
|
287
|
+
if (Math.abs(estimate.delta - expectedDelta) > tolerance) {
|
|
288
|
+
ctx.addIssue({
|
|
289
|
+
code: "custom",
|
|
290
|
+
path: [...path, "delta"],
|
|
291
|
+
message: "measured delta must equal candidate minus baseline",
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
if (estimate.confidenceInterval.lower > estimate.confidenceInterval.upper ||
|
|
295
|
+
estimate.delta < estimate.confidenceInterval.lower ||
|
|
296
|
+
estimate.delta > estimate.confidenceInterval.upper) {
|
|
297
|
+
ctx.addIssue({
|
|
298
|
+
code: "custom",
|
|
299
|
+
path: [...path, "confidenceInterval"],
|
|
300
|
+
message: "confidence interval must be ordered and contain the measured delta",
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
export const agentImprovementReviewSchema = z
|
|
305
|
+
.object({
|
|
306
|
+
schemaVersion: z.literal(1),
|
|
307
|
+
kind: z.literal("agent-improvement-review"),
|
|
308
|
+
proposalDigest: sha256DigestSchema,
|
|
309
|
+
candidateBundleDigest: sha256DigestSchema,
|
|
310
|
+
decision: z.enum(["approve", "reject", "request-changes"]),
|
|
311
|
+
reviewedBy: z.string().min(1),
|
|
312
|
+
reviewedAt: z.iso.datetime(),
|
|
313
|
+
reason: z.string().min(1),
|
|
314
|
+
feedback: z.string().optional(),
|
|
315
|
+
digest: sha256DigestSchema,
|
|
316
|
+
})
|
|
317
|
+
.strict()
|
|
318
|
+
.refine(isCanonicalJsonValue, "review must contain only RFC 8785 JSON values");
|
|
319
|
+
export const candidateExecutionEvidenceSchema = z
|
|
320
|
+
.object({
|
|
321
|
+
schemaVersion: z.literal(1),
|
|
322
|
+
kind: z.literal("agent-candidate-execution-evidence"),
|
|
323
|
+
proposalDigest: sha256DigestSchema,
|
|
324
|
+
reviewDigest: sha256DigestSchema,
|
|
325
|
+
executionId: z.string().regex(/^[A-Za-z0-9._:-]{1,200}$/),
|
|
326
|
+
succeeded: z.literal(true),
|
|
327
|
+
materializationReceipt: agentCandidateMaterializationReceiptSchema,
|
|
328
|
+
profileActivation: agentCandidateProfileActivationSchema,
|
|
329
|
+
receipt: agentCandidateRunReceiptSchema,
|
|
330
|
+
digest: sha256DigestSchema,
|
|
331
|
+
})
|
|
332
|
+
.strict()
|
|
333
|
+
.superRefine((evidence, ctx) => {
|
|
334
|
+
const materialization = evidence.materializationReceipt;
|
|
335
|
+
const plan = materialization.executionPlan;
|
|
336
|
+
const plannedOutcome = plan.material.task.outcome;
|
|
337
|
+
const capturedOutcome = evidence.receipt.taskOutcome.material.outcome;
|
|
338
|
+
const checks = [
|
|
339
|
+
[
|
|
340
|
+
evidence.receipt.materializationReceiptDigest === materialization.digest,
|
|
341
|
+
["receipt", "materializationReceiptDigest"],
|
|
342
|
+
"run receipt must bind the included materialization receipt",
|
|
343
|
+
],
|
|
344
|
+
[
|
|
345
|
+
evidence.receipt.executionPlanDigest === plan.digest,
|
|
346
|
+
["receipt", "executionPlanDigest"],
|
|
347
|
+
"run receipt must bind the included execution plan",
|
|
348
|
+
],
|
|
349
|
+
[
|
|
350
|
+
evidence.receipt.bundleDigest === materialization.bundleDigest,
|
|
351
|
+
["receipt", "bundleDigest"],
|
|
352
|
+
"run receipt and materialization must bind one bundle",
|
|
353
|
+
],
|
|
354
|
+
[
|
|
355
|
+
evidence.executionId === plan.material.executionId,
|
|
356
|
+
["executionId"],
|
|
357
|
+
"execution evidence must bind the materialized execution id",
|
|
358
|
+
],
|
|
359
|
+
[
|
|
360
|
+
evidence.profileActivation.profilePlan.digest ===
|
|
361
|
+
materialization.profilePlan.digest,
|
|
362
|
+
["profileActivation", "profilePlan", "digest"],
|
|
363
|
+
"profile activation must bind the materialized profile plan",
|
|
364
|
+
],
|
|
365
|
+
[
|
|
366
|
+
capturedOutcome.kind === plannedOutcome.kind,
|
|
367
|
+
["receipt", "taskOutcome", "material", "outcome", "kind"],
|
|
368
|
+
"task outcome kind must match the signed execution plan",
|
|
369
|
+
],
|
|
370
|
+
[
|
|
371
|
+
evidence.receipt.termination.kind === "exit" &&
|
|
372
|
+
evidence.receipt.termination.exitCode === 0,
|
|
373
|
+
["receipt", "termination"],
|
|
374
|
+
"successful execution evidence requires a zero exit status",
|
|
375
|
+
],
|
|
376
|
+
];
|
|
377
|
+
if (plannedOutcome.kind === "output" && capturedOutcome.kind === "output") {
|
|
378
|
+
checks.push([
|
|
379
|
+
capturedOutcome.spec.mediaType === plannedOutcome.mediaType &&
|
|
380
|
+
capturedOutcome.spec.maxBytes === plannedOutcome.maxBytes,
|
|
381
|
+
["receipt", "taskOutcome", "material", "outcome", "spec"],
|
|
382
|
+
"task output constraints must match the signed execution plan",
|
|
383
|
+
]);
|
|
384
|
+
}
|
|
385
|
+
if (plannedOutcome.kind === "workspace" &&
|
|
386
|
+
capturedOutcome.kind === "workspace" &&
|
|
387
|
+
plan.material.task.repository) {
|
|
388
|
+
const repository = plan.material.task.repository;
|
|
389
|
+
const base = capturedOutcome.baseRepository;
|
|
390
|
+
checks.push([
|
|
391
|
+
base.identity === repository.identity &&
|
|
392
|
+
base.rootIdentity === repository.rootIdentity &&
|
|
393
|
+
base.commit === repository.baseCommit &&
|
|
394
|
+
base.tree === repository.baseTree,
|
|
395
|
+
["receipt", "taskOutcome", "material", "outcome", "baseRepository"],
|
|
396
|
+
"workspace outcome must bind the signed repository base",
|
|
397
|
+
]);
|
|
398
|
+
}
|
|
399
|
+
for (const [valid, path, message] of checks) {
|
|
400
|
+
if (!valid)
|
|
401
|
+
ctx.addIssue({ code: "custom", path, message });
|
|
402
|
+
}
|
|
403
|
+
if (!isCanonicalJsonValue(evidence)) {
|
|
404
|
+
ctx.addIssue({
|
|
405
|
+
code: "custom",
|
|
406
|
+
message: "candidate execution evidence must contain only RFC 8785 JSON values",
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
});
|