@tangle-network/agent-interface 0.27.2 → 0.29.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 (31) hide show
  1. package/dist/agent-candidate-artifact-schema.d.ts +0 -3
  2. package/dist/agent-candidate-artifact-schema.js +0 -2
  3. package/dist/agent-candidate-code-schema.d.ts +0 -10
  4. package/dist/agent-candidate-code-schema.js +0 -1
  5. package/dist/agent-candidate-execution-plan-schema.d.ts +173 -382
  6. package/dist/agent-candidate-execution-plan-schema.js +100 -138
  7. package/dist/agent-candidate-lineage-schema.d.ts +1 -31
  8. package/dist/agent-candidate-lineage-schema.js +3 -34
  9. package/dist/agent-candidate-outcome-schema.d.ts +48 -36
  10. package/dist/agent-candidate-outcome-schema.js +23 -32
  11. package/dist/agent-candidate-promotion-schema.d.ts +11021 -2411
  12. package/dist/agent-candidate-promotion-schema.js +495 -109
  13. package/dist/agent-candidate-receipt-schema.d.ts +260 -344
  14. package/dist/agent-candidate-receipt-schema.js +82 -11
  15. package/dist/agent-candidate-schema-common.d.ts +8 -0
  16. package/dist/agent-candidate-schema-common.js +35 -1
  17. package/dist/agent-candidate-schema.d.ts +2 -44
  18. package/dist/agent-candidate-schema.js +3 -29
  19. package/dist/agent-candidate-task-schema.d.ts +643 -0
  20. package/dist/agent-candidate-task-schema.js +191 -0
  21. package/dist/agent-candidate.d.ts +173 -94
  22. package/dist/agent-candidate.test-fixture.d.ts +0 -32
  23. package/dist/agent-candidate.test-fixture.js +0 -32
  24. package/dist/index.d.ts +0 -1
  25. package/dist/index.js +0 -1
  26. package/dist/profile-diff.d.ts +0 -1
  27. package/dist/profile-schema.d.ts +9 -0
  28. package/dist/profile-schema.js +14 -6
  29. package/package.json +2 -2
  30. package/dist/agent-candidate-compat.d.ts +0 -1918
  31. package/dist/agent-candidate-compat.js +0 -340
@@ -1,17 +1,9 @@
1
1
  import { z } from "zod";
2
2
  import { agentCandidateArtifactRefSchema, agentCandidateCapturedArtifactSchema, agentCandidateWorkspaceSnapshotEvidenceSchema, } from "./agent-candidate-artifact-schema.js";
3
3
  import { agentCandidateContainerSchema, agentCandidateInstructionDeliverySchema, agentCandidateWorkingDirectorySchema, } from "./agent-candidate-code-schema.js";
4
+ import { reasoningEffortSchema } from "./profile-schema.js";
4
5
  import { addDuplicateIssues, agentCandidateConfigValueSchema, agentCandidateMediaTypeSchema, environmentConfigSchema, gitObjectSchema, isCanonicalJsonValue, isObviouslyPrivateHostname, isSafeExecutable, isSafeRelativePath, isWellFormedUnicode, sameGitObjectFormat, sha256Utf8, sha256DigestSchema, } from "./agent-candidate-schema-common.js";
5
6
  import { harnessTypeSchema } from "./harness.js";
6
- const reasoningEffortSchema = z.enum([
7
- "none",
8
- "minimal",
9
- "low",
10
- "medium",
11
- "high",
12
- "xhigh",
13
- "ultracode",
14
- ]);
15
7
  function isCanonicalAbsolutePath(value) {
16
8
  return (value.startsWith("/") &&
17
9
  value !== "/" &&
@@ -58,9 +50,59 @@ export const agentCandidateResolvedModelSchema = z
58
50
  reasoningEffort: reasoningEffortSchema,
59
51
  })
60
52
  .strict();
53
+ export const agentCandidateBenchmarkGraderIdentitySchema = z
54
+ .object({
55
+ name: z.string().min(1),
56
+ version: z.string().min(1),
57
+ format: z.literal("tangle-grader"),
58
+ artifact: agentCandidateArtifactRefSchema,
59
+ })
60
+ .strict()
61
+ .superRefine((grader, ctx) => {
62
+ if (grader.artifact.byteLength === 0) {
63
+ ctx.addIssue({
64
+ code: "custom",
65
+ path: ["artifact", "byteLength"],
66
+ message: "pinned grader artifact must contain executable grader bytes",
67
+ });
68
+ }
69
+ });
70
+ export const agentCandidateTaskRepositorySchema = z
71
+ .object({
72
+ identity: z.string().min(1).max(512),
73
+ rootIdentity: z.string().min(1).max(512),
74
+ baseCommit: gitObjectSchema,
75
+ baseTree: gitObjectSchema,
76
+ })
77
+ .strict()
78
+ .superRefine((repository, ctx) => {
79
+ if (!sameGitObjectFormat(repository.baseCommit, repository.baseTree)) {
80
+ ctx.addIssue({
81
+ code: "custom",
82
+ message: "task Git object ids must use one object format",
83
+ });
84
+ }
85
+ });
86
+ export const agentCandidateResolvedTaskContainerSchema = agentCandidateContainerSchema
87
+ .extend({
88
+ source: z.literal("evaluator-task-container"),
89
+ manifestDigest: sha256DigestSchema,
90
+ platform: z
91
+ .object({
92
+ os: z.string().min(1).max(100),
93
+ architecture: z.string().min(1).max(100),
94
+ variant: z.string().min(1).max(100).optional(),
95
+ })
96
+ .strict(),
97
+ })
98
+ .strict();
99
+ export const agentCandidateRetryPolicySchema = z.enum([
100
+ "pre-model-infrastructure-only",
101
+ "none",
102
+ ]);
61
103
  export const agentCandidateProfilePlanMaterialSchema = z
62
104
  .object({
63
- version: z.literal(1),
105
+ sourceProfileDigest: sha256DigestSchema,
64
106
  harness: harnessTypeSchema,
65
107
  files: z.array(z
66
108
  .object({
@@ -150,46 +192,35 @@ export const agentCandidateTaskOutcomeSpecSchema = z.discriminatedUnion("kind",
150
192
  })
151
193
  .strict(),
152
194
  ]);
195
+ export const agentCandidateBenchmarkCellRefSchema = z
196
+ .object({
197
+ suiteDigest: sha256DigestSchema,
198
+ taskIndex: z.number().int().nonnegative(),
199
+ repetition: z.number().int().nonnegative(),
200
+ })
201
+ .strict();
202
+ export const agentCandidateRunCellMaterialSchema = z
203
+ .object({
204
+ kind: z.literal("agent-candidate-run-cell"),
205
+ experimentDigest: sha256DigestSchema,
206
+ arm: z.enum(["baseline", "candidate"]),
207
+ bundleDigest: sha256DigestSchema,
208
+ suiteDigest: sha256DigestSchema,
209
+ taskDigest: sha256DigestSchema,
210
+ taskIndex: z.number().int().nonnegative(),
211
+ repetition: z.number().int().nonnegative(),
212
+ seed: z.number().int().safe(),
213
+ attempt: z.number().int().positive(),
214
+ })
215
+ .strict();
216
+ export const agentCandidateRunCellSchema = agentCandidateRunCellMaterialSchema
217
+ .extend({ digest: sha256DigestSchema })
218
+ .strict();
153
219
  export const agentCandidateExecutionPlanMaterialSchema = z
154
220
  .object({
155
- schemaVersion: z.literal(2),
156
221
  kind: z.literal("agent-candidate-execution-plan-material"),
157
- bundleDigest: sha256DigestSchema,
222
+ runCell: agentCandidateRunCellSchema,
158
223
  executionId: z.string().min(1),
159
- attempt: z
160
- .object({
161
- number: z.number().int().min(1),
162
- maxAttempts: z.number().int().min(1),
163
- retryPolicy: z.enum(["pre-model-infrastructure-only", "none"]),
164
- })
165
- .strict(),
166
- task: z
167
- .object({
168
- benchmark: z.string().min(1),
169
- benchmarkVersion: z.string().min(1),
170
- taskId: z.string().min(1),
171
- splitDigest: sha256DigestSchema,
172
- instruction: z
173
- .object({
174
- encoding: z.literal("utf8"),
175
- sha256: sha256DigestSchema,
176
- byteLength: z.number().int().positive(),
177
- delivery: agentCandidateInstructionDeliverySchema,
178
- })
179
- .strict(),
180
- repository: z
181
- .object({
182
- identity: z.string().min(1),
183
- rootIdentity: z.string().min(1),
184
- baseCommit: gitObjectSchema,
185
- baseTree: gitObjectSchema,
186
- })
187
- .strict()
188
- .optional(),
189
- outcome: agentCandidateTaskOutcomeSpecSchema,
190
- workspace: agentCandidateWorkspaceSnapshotEvidenceSchema,
191
- })
192
- .strict(),
193
224
  workspaces: z
194
225
  .object({
195
226
  taskRoot: z
@@ -214,6 +245,8 @@ export const agentCandidateExecutionPlanMaterialSchema = z
214
245
  .strict(),
215
246
  harness: harnessTypeSchema,
216
247
  harnessVersion: z.string().min(1),
248
+ instructionDelivery: agentCandidateInstructionDeliverySchema,
249
+ limits: agentCandidateExecutionLimitsSchema,
217
250
  container: agentCandidateContainerSchema
218
251
  .extend({
219
252
  source: z.enum(["pinned-container", "evaluator-task-container"]),
@@ -270,13 +303,6 @@ export const agentCandidateExecutionPlanMaterialSchema = z
270
303
  .min(1),
271
304
  })
272
305
  .strict(),
273
- grader: z
274
- .object({
275
- name: z.string().min(1),
276
- version: z.string().min(1),
277
- artifact: agentCandidateArtifactRefSchema,
278
- })
279
- .strict(),
280
306
  launch: z
281
307
  .object({
282
308
  executable: z
@@ -289,42 +315,10 @@ export const agentCandidateExecutionPlanMaterialSchema = z
289
315
  .strict(),
290
316
  knowledgeManifestDigest: sha256DigestSchema.optional(),
291
317
  memory: agentCandidateEffectiveMemorySchema,
292
- limits: agentCandidateExecutionLimitsSchema,
293
318
  network: z.object({ mode: z.literal("disabled") }).strict(),
294
319
  })
295
320
  .strict()
296
321
  .superRefine((material, ctx) => {
297
- if (material.task.repository !== undefined &&
298
- !sameGitObjectFormat(material.task.repository.baseCommit, material.task.repository.baseTree)) {
299
- ctx.addIssue({
300
- code: "custom",
301
- path: ["task", "repository"],
302
- message: "task Git object ids must use one object format",
303
- });
304
- }
305
- if (material.task.outcome.kind === "workspace" &&
306
- material.task.repository === undefined) {
307
- ctx.addIssue({
308
- code: "custom",
309
- path: ["task", "repository"],
310
- message: "workspace outcomes require task repository provenance",
311
- });
312
- }
313
- if (material.attempt.number > material.attempt.maxAttempts) {
314
- ctx.addIssue({
315
- code: "custom",
316
- path: ["attempt", "number"],
317
- message: "attempt number cannot exceed the frozen maximum",
318
- });
319
- }
320
- if (material.attempt.retryPolicy === "none" &&
321
- material.attempt.maxAttempts !== 1) {
322
- ctx.addIssue({
323
- code: "custom",
324
- path: ["attempt", "maxAttempts"],
325
- message: "a no-retry plan must allow exactly one attempt",
326
- });
327
- }
328
322
  const routeIds = material.model.routes.map((route) => route.kind === "mode" || route.kind === "subagent"
329
323
  ? `${route.kind}:${route.name}`
330
324
  : route.kind);
@@ -358,20 +352,6 @@ export const agentCandidateExecutionPlanMaterialSchema = z
358
352
  }
359
353
  }
360
354
  const modelNetwork = material.model.access.network;
361
- if (material.limits.maxModelCalls === 0 && modelNetwork.mode !== "disabled") {
362
- ctx.addIssue({
363
- code: "custom",
364
- path: ["model", "access", "network"],
365
- message: "zero-call plans cannot expose a model gateway",
366
- });
367
- }
368
- if (material.limits.maxModelCalls > 0 && modelNetwork.mode !== "gateway-only") {
369
- ctx.addIssue({
370
- code: "custom",
371
- path: ["model", "access", "network"],
372
- message: "model-calling plans require one frozen gateway allowlist",
373
- });
374
- }
375
355
  if (modelNetwork.mode === "gateway-only") {
376
356
  addDuplicateIssues(modelNetwork.domains, ["model", "access", "network", "domains"], ctx);
377
357
  for (let index = 1; index < modelNetwork.domains.length; index++) {
@@ -407,62 +387,46 @@ export const agentCandidateExecutionPlanMaterialSchema = z
407
387
  message: "task and candidate workspace roots must be disjoint",
408
388
  });
409
389
  }
410
- if (material.launch.cwd.workspace === "candidate" &&
411
- material.workspaces.candidateRoot === undefined) {
412
- ctx.addIssue({
413
- code: "custom",
414
- path: ["launch", "cwd", "workspace"],
415
- message: "candidate cwd requires a pinned candidate workspace root",
416
- });
417
- }
418
- if (material.profile.targetWorkspace === "candidate" &&
419
- material.workspaces.candidateRoot === undefined) {
420
- ctx.addIssue({
421
- code: "custom",
422
- path: ["profile", "targetWorkspace"],
423
- message: "candidate-targeted profile files require a candidate workspace root",
424
- });
425
- }
426
- const delivery = material.task.instruction.delivery;
427
390
  const taskPath = material.launch.env.TANGLE_CANDIDATE_TASK_PATH;
428
- if (delivery.kind === "utf8-file") {
429
- if (taskPath?.value !== delivery.path) {
391
+ if (taskPath !== undefined) {
392
+ if (taskPath.value !== "/tangle/input/task.txt") {
430
393
  ctx.addIssue({
431
394
  code: "custom",
432
395
  path: ["launch", "env", "TANGLE_CANDIDATE_TASK_PATH"],
433
- message: "file delivery requires the signed fixed task path",
396
+ message: "task file delivery must use the fixed evaluator-owned path",
434
397
  });
435
398
  }
436
- if (pathsOverlap(material.workspaces.taskRoot, delivery.path) ||
399
+ if (pathsOverlap(taskPath.value, material.workspaces.taskRoot) ||
437
400
  (material.workspaces.candidateRoot !== undefined &&
438
- pathsOverlap(material.workspaces.candidateRoot, delivery.path))) {
401
+ pathsOverlap(taskPath.value, material.workspaces.candidateRoot))) {
439
402
  ctx.addIssue({
440
403
  code: "custom",
441
- path: ["workspaces"],
442
- message: "the task instruction file must be outside both workspaces",
404
+ path: ["launch", "env", "TANGLE_CANDIDATE_TASK_PATH"],
405
+ message: "task file delivery must be outside both workspaces",
443
406
  });
444
407
  }
445
408
  }
446
- else if (taskPath !== undefined) {
409
+ if (material.launch.cwd.workspace === "candidate" &&
410
+ material.workspaces.candidateRoot === undefined) {
447
411
  ctx.addIssue({
448
412
  code: "custom",
449
- path: ["launch", "env", "TANGLE_CANDIDATE_TASK_PATH"],
450
- message: "non-file delivery cannot expose an instruction path",
413
+ path: ["launch", "cwd", "workspace"],
414
+ message: "candidate cwd requires a pinned candidate workspace root",
451
415
  });
452
416
  }
453
- if (activeCode && material.candidateWorkspace?.material.files.length === 0) {
417
+ if (material.profile.targetWorkspace === "candidate" &&
418
+ material.workspaces.candidateRoot === undefined) {
454
419
  ctx.addIssue({
455
420
  code: "custom",
456
- path: ["candidateWorkspace", "material", "files"],
457
- message: "active candidate workspaces cannot be empty",
421
+ path: ["profile", "targetWorkspace"],
422
+ message: "candidate-targeted profile files require a candidate workspace root",
458
423
  });
459
424
  }
460
- if (material.task.outcome.kind === "workspace" &&
461
- material.task.workspace.material.files.length === 0) {
425
+ if (activeCode && material.candidateWorkspace?.material.files.length === 0) {
462
426
  ctx.addIssue({
463
427
  code: "custom",
464
- path: ["task", "workspace", "material", "files"],
465
- message: "task workspace snapshots cannot be empty",
428
+ path: ["candidateWorkspace", "material", "files"],
429
+ message: "active candidate workspaces cannot be empty",
466
430
  });
467
431
  }
468
432
  if (!isCanonicalJsonValue(material)) {
@@ -472,10 +436,9 @@ export const agentCandidateExecutionPlanMaterialSchema = z
472
436
  });
473
437
  }
474
438
  });
475
- function planEvidenceSchema(schemaVersion, kind, material) {
439
+ function planEvidenceSchema(kind, material) {
476
440
  return z
477
441
  .object({
478
- schemaVersion: z.literal(schemaVersion),
479
442
  kind: z.literal(kind),
480
443
  digest: sha256DigestSchema,
481
444
  material,
@@ -499,10 +462,9 @@ function planEvidenceSchema(schemaVersion, kind, material) {
499
462
  }
500
463
  });
501
464
  }
502
- export const agentCandidateProfilePlanEvidenceSchema = planEvidenceSchema(1, "agent-profile-workspace-plan", agentCandidateProfilePlanMaterialSchema);
465
+ export const agentCandidateProfilePlanEvidenceSchema = planEvidenceSchema("agent-profile-workspace-plan", agentCandidateProfilePlanMaterialSchema);
503
466
  export const agentCandidateProfileActivationSchema = z
504
467
  .object({
505
- schemaVersion: z.literal(1),
506
468
  kind: z.literal("agent-candidate-profile-activation"),
507
469
  profilePlan: agentCandidateProfilePlanEvidenceSchema,
508
470
  files: z.array(z
@@ -550,4 +512,4 @@ export const agentCandidateProfileActivationSchema = z
550
512
  });
551
513
  }
552
514
  });
553
- export const agentCandidateExecutionPlanEvidenceSchema = planEvidenceSchema(2, "agent-candidate-execution-plan", agentCandidateExecutionPlanMaterialSchema);
515
+ export const agentCandidateExecutionPlanEvidenceSchema = planEvidenceSchema("agent-candidate-execution-plan", agentCandidateExecutionPlanMaterialSchema);
@@ -1,7 +1,6 @@
1
1
  import { z } from "zod";
2
2
  export declare const agentCandidateKnowledgeSchema: z.ZodObject<{
3
3
  candidate: z.ZodObject<{
4
- schemaVersion: z.ZodLiteral<1>;
5
4
  kind: z.ZodLiteral<"knowledge-improvement-candidate">;
6
5
  runId: z.ZodString;
7
6
  candidateId: z.ZodString;
@@ -12,11 +11,9 @@ export declare const agentCandidateKnowledgeSchema: z.ZodObject<{
12
11
  promotionPlanHash: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
13
12
  }, z.core.$strict>;
14
13
  snapshot: z.ZodObject<{
15
- schemaVersion: z.ZodLiteral<2>;
16
14
  kind: z.ZodLiteral<"agent-candidate-workspace-snapshot">;
17
15
  digest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
18
16
  material: z.ZodObject<{
19
- schemaVersion: z.ZodLiteral<2>;
20
17
  kind: z.ZodLiteral<"agent-candidate-workspace-manifest">;
21
18
  files: z.ZodArray<z.ZodObject<{
22
19
  path: z.ZodString;
@@ -123,13 +120,6 @@ export declare const agentCandidateMemoryPolicySchema: z.ZodDiscriminatedUnion<[
123
120
  byteLength: z.ZodNumber;
124
121
  }, z.core.$strict>>;
125
122
  }, z.core.$strict>], "mode">;
126
- export declare const agentCandidateSpendSchema: z.ZodObject<{
127
- costUsd: z.ZodNumber;
128
- inputTokens: z.ZodNumber;
129
- outputTokens: z.ZodNumber;
130
- cachedInputTokens: z.ZodOptional<z.ZodNumber>;
131
- modelCalls: z.ZodNumber;
132
- }, z.core.$strict>;
133
123
  export declare const agentCandidateLineageSchema: z.ZodObject<{
134
124
  source: z.ZodEnum<{
135
125
  optimizer: "optimizer";
@@ -141,25 +131,5 @@ export declare const agentCandidateLineageSchema: z.ZodObject<{
141
131
  runIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
142
132
  profileDiffIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
143
133
  modelSnapshots: z.ZodOptional<z.ZodArray<z.ZodString>>;
144
- benchmark: z.ZodOptional<z.ZodObject<{
145
- name: z.ZodString;
146
- version: z.ZodString;
147
- splitDigest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
148
- }, z.core.$strict>>;
149
- spend: z.ZodOptional<z.ZodObject<{
150
- proposal: z.ZodObject<{
151
- costUsd: z.ZodNumber;
152
- inputTokens: z.ZodNumber;
153
- outputTokens: z.ZodNumber;
154
- cachedInputTokens: z.ZodOptional<z.ZodNumber>;
155
- modelCalls: z.ZodNumber;
156
- }, z.core.$strict>;
157
- evaluation: z.ZodObject<{
158
- costUsd: z.ZodNumber;
159
- inputTokens: z.ZodNumber;
160
- outputTokens: z.ZodNumber;
161
- cachedInputTokens: z.ZodOptional<z.ZodNumber>;
162
- modelCalls: z.ZodNumber;
163
- }, z.core.$strict>;
164
- }, z.core.$strict>>;
134
+ developmentSplitDigest: z.ZodOptional<z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>>;
165
135
  }, z.core.$strict>;
@@ -5,7 +5,6 @@ export const agentCandidateKnowledgeSchema = z
5
5
  .object({
6
6
  candidate: z
7
7
  .object({
8
- schemaVersion: z.literal(1),
9
8
  kind: z.literal("knowledge-improvement-candidate"),
10
9
  runId: z.string().min(1),
11
10
  candidateId: z.string().min(1),
@@ -31,15 +30,6 @@ export const agentCandidateMemoryPolicySchema = z.discriminatedUnion("mode", [
31
30
  })
32
31
  .strict(),
33
32
  ]);
34
- export const agentCandidateSpendSchema = z
35
- .object({
36
- costUsd: z.number().finite().nonnegative(),
37
- inputTokens: z.number().int().nonnegative(),
38
- outputTokens: z.number().int().nonnegative(),
39
- cachedInputTokens: z.number().int().nonnegative().optional(),
40
- modelCalls: z.number().int().nonnegative(),
41
- })
42
- .strict();
43
33
  export const agentCandidateLineageSchema = z
44
34
  .object({
45
35
  source: z.enum(["optimizer", "human", "import", "compound"]),
@@ -47,21 +37,7 @@ export const agentCandidateLineageSchema = z
47
37
  runIds: z.array(z.string().min(1)).optional(),
48
38
  profileDiffIds: z.array(z.string().min(1)).optional(),
49
39
  modelSnapshots: z.array(z.string().min(1)).optional(),
50
- benchmark: z
51
- .object({
52
- name: z.string().min(1),
53
- version: z.string().min(1),
54
- splitDigest: sha256DigestSchema,
55
- })
56
- .strict()
57
- .optional(),
58
- spend: z
59
- .object({
60
- proposal: agentCandidateSpendSchema,
61
- evaluation: agentCandidateSpendSchema,
62
- })
63
- .strict()
64
- .optional(),
40
+ developmentSplitDigest: sha256DigestSchema.optional(),
65
41
  })
66
42
  .strict()
67
43
  .superRefine((lineage, ctx) => {
@@ -92,19 +68,12 @@ export const agentCandidateLineageSchema = z
92
68
  message: "generated candidates must name their producing run",
93
69
  });
94
70
  }
95
- if (lineage.benchmark === undefined) {
71
+ if (lineage.developmentSplitDigest === undefined) {
96
72
  ctx.addIssue({
97
73
  code: "custom",
98
- path: ["benchmark"],
74
+ path: ["developmentSplitDigest"],
99
75
  message: "generated candidates must pin their development split",
100
76
  });
101
77
  }
102
- if (lineage.spend === undefined) {
103
- ctx.addIssue({
104
- code: "custom",
105
- path: ["spend"],
106
- message: "generated candidates must record proposal and evaluation spend",
107
- });
108
- }
109
78
  }
110
79
  });