@openpond/evals 0.11.16 → 0.11.18

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 (158) hide show
  1. package/dist/connected-evidence/contracts.js +72 -0
  2. package/dist/connected-evidence/imports.js +71 -0
  3. package/dist/connected-evidence/index.js +5 -0
  4. package/dist/connected-evidence/normalize.js +97 -0
  5. package/dist/connected-evidence/python-correctness.js +73 -0
  6. package/dist/connected-evidence/sources/claude-code.js +71 -0
  7. package/dist/connected-evidence/sources/codex.js +52 -0
  8. package/dist/connected-evidence/sources/history.js +86 -0
  9. package/dist/connected-evidence/sources/usage.js +15 -0
  10. package/dist/connected-evidence/usage-summary.js +52 -0
  11. package/dist/experiments.js +16 -4
  12. package/dist/graders.js +9 -6
  13. package/dist/human-review/comparison.js +161 -0
  14. package/dist/human-review/contracts.js +110 -0
  15. package/dist/human-review/execution.js +61 -0
  16. package/dist/human-review/handoff.js +18 -0
  17. package/dist/human-review/index.js +9 -0
  18. package/dist/human-review/local-publication.js +18 -0
  19. package/dist/human-review/repository.js +1 -0
  20. package/dist/human-review/results.js +18 -0
  21. package/dist/human-review/service.js +268 -0
  22. package/dist/human-review/task-proposals.js +39 -0
  23. package/dist/index.js +1 -0
  24. package/dist/javascript-verifier-contract.js +2 -2
  25. package/dist/learning/authoring.js +2 -1
  26. package/dist/learning/contracts.js +353 -81
  27. package/dist/learning/index.js +1 -0
  28. package/dist/learning/reward-authoring.js +5 -2
  29. package/dist/learning/training-handoff.js +32 -0
  30. package/dist/metrics-node.js +2 -0
  31. package/dist/profile-evaluation-target.js +7 -0
  32. package/dist/profile-evaluations.js +7 -10
  33. package/dist/profile-external-evaluation.js +35 -0
  34. package/dist/profile-source-candidate.js +5 -0
  35. package/dist/rewards.js +5 -3
  36. package/dist/taskset-run-contract.js +10 -0
  37. package/dist/tasksets.js +2 -0
  38. package/dist/types/builtin-benchmarks/harness-refiner.d.ts +75 -1
  39. package/dist/types/builtin-benchmarks/harness-refiner.d.ts.map +1 -1
  40. package/dist/types/conformance.d.ts +150 -2
  41. package/dist/types/conformance.d.ts.map +1 -1
  42. package/dist/types/connected-evidence/contracts.d.ts +317 -0
  43. package/dist/types/connected-evidence/contracts.d.ts.map +1 -0
  44. package/dist/types/connected-evidence/imports.d.ts +19 -0
  45. package/dist/types/connected-evidence/imports.d.ts.map +1 -0
  46. package/dist/types/connected-evidence/index.d.ts +6 -0
  47. package/dist/types/connected-evidence/index.d.ts.map +1 -0
  48. package/dist/types/connected-evidence/normalize.d.ts +25 -0
  49. package/dist/types/connected-evidence/normalize.d.ts.map +1 -0
  50. package/dist/types/connected-evidence/python-correctness.d.ts +196 -0
  51. package/dist/types/connected-evidence/python-correctness.d.ts.map +1 -0
  52. package/dist/types/connected-evidence/sources/claude-code.d.ts +74 -0
  53. package/dist/types/connected-evidence/sources/claude-code.d.ts.map +1 -0
  54. package/dist/types/connected-evidence/sources/codex.d.ts +74 -0
  55. package/dist/types/connected-evidence/sources/codex.d.ts.map +1 -0
  56. package/dist/types/connected-evidence/sources/history.d.ts +146 -0
  57. package/dist/types/connected-evidence/sources/history.d.ts.map +1 -0
  58. package/dist/types/connected-evidence/sources/usage.d.ts +3 -0
  59. package/dist/types/connected-evidence/sources/usage.d.ts.map +1 -0
  60. package/dist/types/connected-evidence/usage-summary.d.ts +162 -0
  61. package/dist/types/connected-evidence/usage-summary.d.ts.map +1 -0
  62. package/dist/types/evidence/conformance.d.ts +28 -28
  63. package/dist/types/evidence/contracts.d.ts +27 -27
  64. package/dist/types/execution-contracts.d.ts +159 -5
  65. package/dist/types/execution-contracts.d.ts.map +1 -1
  66. package/dist/types/experiments.d.ts +476 -7
  67. package/dist/types/experiments.d.ts.map +1 -1
  68. package/dist/types/graders.d.ts +21 -1
  69. package/dist/types/graders.d.ts.map +1 -1
  70. package/dist/types/human-review/comparison.d.ts +1959 -0
  71. package/dist/types/human-review/comparison.d.ts.map +1 -0
  72. package/dist/types/human-review/contracts.d.ts +2719 -0
  73. package/dist/types/human-review/contracts.d.ts.map +1 -0
  74. package/dist/types/human-review/execution.d.ts +298 -0
  75. package/dist/types/human-review/execution.d.ts.map +1 -0
  76. package/dist/types/human-review/handoff.d.ts +124 -0
  77. package/dist/types/human-review/handoff.d.ts.map +1 -0
  78. package/dist/types/human-review/index.d.ts +10 -0
  79. package/dist/types/human-review/index.d.ts.map +1 -0
  80. package/dist/types/human-review/local-publication.d.ts +165 -0
  81. package/dist/types/human-review/local-publication.d.ts.map +1 -0
  82. package/dist/types/human-review/repository.d.ts +43 -0
  83. package/dist/types/human-review/repository.d.ts.map +1 -0
  84. package/dist/types/human-review/results.d.ts +118 -0
  85. package/dist/types/human-review/results.d.ts.map +1 -0
  86. package/dist/types/human-review/service.d.ts +878 -0
  87. package/dist/types/human-review/service.d.ts.map +1 -0
  88. package/dist/types/human-review/task-proposals.d.ts +70 -0
  89. package/dist/types/human-review/task-proposals.d.ts.map +1 -0
  90. package/dist/types/index.d.ts +1 -0
  91. package/dist/types/index.d.ts.map +1 -1
  92. package/dist/types/javascript-environment-contract.d.ts +1 -1
  93. package/dist/types/javascript-verifier-contract.d.ts +1 -1
  94. package/dist/types/javascript-verifier-contract.d.ts.map +1 -1
  95. package/dist/types/learned-preference.d.ts +2 -2
  96. package/dist/types/learning/acceptance-group.d.ts +13 -13
  97. package/dist/types/learning/acceptance-plan.d.ts +1 -1
  98. package/dist/types/learning/admission.d.ts +78 -1
  99. package/dist/types/learning/admission.d.ts.map +1 -1
  100. package/dist/types/learning/authoring-service.d.ts +2 -0
  101. package/dist/types/learning/authoring-service.d.ts.map +1 -1
  102. package/dist/types/learning/authoring.d.ts +20 -0
  103. package/dist/types/learning/authoring.d.ts.map +1 -1
  104. package/dist/types/learning/batch-service.d.ts +76 -2
  105. package/dist/types/learning/batch-service.d.ts.map +1 -1
  106. package/dist/types/learning/contracts.d.ts +759 -24
  107. package/dist/types/learning/contracts.d.ts.map +1 -1
  108. package/dist/types/learning/index.d.ts +1 -0
  109. package/dist/types/learning/index.d.ts.map +1 -1
  110. package/dist/types/learning/iteration-candidate-decision.d.ts +2 -2
  111. package/dist/types/learning/iteration-dispatch-contracts.d.ts +2 -2
  112. package/dist/types/learning/operations.d.ts +1118 -8
  113. package/dist/types/learning/operations.d.ts.map +1 -1
  114. package/dist/types/learning/repository.d.ts +402 -15
  115. package/dist/types/learning/repository.d.ts.map +1 -1
  116. package/dist/types/learning/reward-authoring.d.ts.map +1 -1
  117. package/dist/types/learning/reward-calibration.d.ts +74 -0
  118. package/dist/types/learning/reward-calibration.d.ts.map +1 -1
  119. package/dist/types/learning/reward-checks.d.ts +14 -2
  120. package/dist/types/learning/reward-checks.d.ts.map +1 -1
  121. package/dist/types/learning/training-handoff.d.ts +201 -0
  122. package/dist/types/learning/training-handoff.d.ts.map +1 -0
  123. package/dist/types/learning/transport.d.ts +963 -21
  124. package/dist/types/learning/transport.d.ts.map +1 -1
  125. package/dist/types/metrics-node.d.ts +3 -1
  126. package/dist/types/metrics-node.d.ts.map +1 -1
  127. package/dist/types/model-improvement-qualification.d.ts +3 -3
  128. package/dist/types/native-harness-experiment-attempt.d.ts +2 -2
  129. package/dist/types/profile-evaluation-comparisons.d.ts +230 -0
  130. package/dist/types/profile-evaluation-comparisons.d.ts.map +1 -1
  131. package/dist/types/profile-evaluation-target.d.ts +14 -0
  132. package/dist/types/profile-evaluation-target.d.ts.map +1 -0
  133. package/dist/types/profile-evaluations.d.ts +117 -14
  134. package/dist/types/profile-evaluations.d.ts.map +1 -1
  135. package/dist/types/profile-external-evaluation.d.ts +404 -0
  136. package/dist/types/profile-external-evaluation.d.ts.map +1 -0
  137. package/dist/types/profile-source-candidate.d.ts +15 -0
  138. package/dist/types/profile-source-candidate.d.ts.map +1 -0
  139. package/dist/types/review-conformance.d.ts +7 -7
  140. package/dist/types/rewards.d.ts +253 -0
  141. package/dist/types/rewards.d.ts.map +1 -1
  142. package/dist/types/rollouts.d.ts +3 -3
  143. package/dist/types/taskset-run-contract.d.ts +230 -0
  144. package/dist/types/taskset-run-contract.d.ts.map +1 -1
  145. package/dist/types/tasksets.d.ts +311 -3
  146. package/dist/types/tasksets.d.ts.map +1 -1
  147. package/dist/types/telemetry-analysis.d.ts +2 -2
  148. package/dist/types/telemetry-bundle.d.ts +6 -6
  149. package/dist/types/telemetry.d.ts +3 -3
  150. package/package.json +13 -1
  151. package/schemas/learning/v1/command-request.schema.json +1745 -409
  152. package/schemas/learning/v1/decision.schema.json +11 -0
  153. package/schemas/learning/v1/draft.schema.json +11 -0
  154. package/schemas/learning/v1/grade.schema.json +11 -0
  155. package/schemas/learning/v1/package.schema.json +532 -12
  156. package/schemas/learning/v1/policy.schema.json +836 -28
  157. package/schemas/learning/v1/reward.schema.json +520 -0
  158. package/schemas/learning/v1/reward_check.schema.json +9 -0
@@ -1,15 +1,20 @@
1
+ import { TrainingHandoffOriginSchema } from "./training-handoff.js";
1
2
  import { LearningDomainError } from "./errors.js";
2
3
  import { z } from "zod";
3
- import { ImmutableAssetRefSchema, ImmutableReleaseRefSchema, ReleaseHashSchema, ReleaseIdSchema, ReleaseTimestampSchema, contentHash } from "@openpond/harness";
4
- import { RewardBindingSchema, RewardCompositionSchema, RewardReleaseRefSchema, RewardReleaseSchema } from "../rewards.js";
4
+ import { ImmutableAssetRefSchema, ImmutableReleaseRefSchema, ReleaseHashSchema, ReleaseIdSchema, ReleaseTimestampSchema, contentHash, } from "@openpond/harness";
5
+ import { RewardBindingSchema, RewardCompositionSchema, RewardReleaseRefSchema, RewardReleaseSchema, } from "../rewards.js";
5
6
  import { TaskRecordSchema, TaskSplitSchema, TasksetReleaseContentSchema } from "../tasksets.js";
6
7
  import { assertBoundedTaskJson, validateTaskSchema } from "../task-schema.js";
7
8
  import { JudgeCallReservationSchema } from "./judge-budget.js";
8
9
  import { NightlyScheduleSchema } from "./nightly-schedule.js";
9
10
  export const LearningJsonObjectSchema = z.record(z.string(), z.json());
10
11
  export const LearningRevisionRefSchema = RewardReleaseRefSchema;
11
- export const LearningJsonPointerSchema = z.string().max(2_000).refine((value) => value === "" || (value.startsWith("/") && !/~(?![01])/u.test(value)), "Use an RFC 6901 JSON pointer.");
12
- export const TaskDefinitionContentSchema = z.object({
12
+ export const LearningJsonPointerSchema = z
13
+ .string()
14
+ .max(2_000)
15
+ .refine((value) => value === "" || (value.startsWith("/") && !/~(?![01])/u.test(value)), "Use an RFC 6901 JSON pointer.");
16
+ export const TaskDefinitionContentSchema = z
17
+ .object({
13
18
  schemaVersion: z.literal("openpond.taskDefinition.v1"),
14
19
  id: ReleaseIdSchema,
15
20
  revision: z.number().int().positive(),
@@ -24,21 +29,42 @@ export const TaskDefinitionContentSchema = z.object({
24
29
  contextRequirements: z.array(z.string().trim().min(1).max(2_000)).max(100).optional(),
25
30
  rewardBinding: LearningRevisionRefSchema,
26
31
  harness: ImmutableReleaseRefSchema.nullable(),
27
- execution: TasksetReleaseContentSchema.pick({ policy: true, environment: true, environmentRelease: true, tools: true, capabilities: true, verifierSetRelease: true }).strict(),
28
- }).strict().superRefine((definition, context) => {
32
+ execution: TasksetReleaseContentSchema.pick({
33
+ policy: true,
34
+ environment: true,
35
+ environmentRelease: true,
36
+ tools: true,
37
+ capabilities: true,
38
+ verifierSetRelease: true,
39
+ }).strict(),
40
+ })
41
+ .strict()
42
+ .superRefine((definition, context) => {
29
43
  for (const field of ["inputSchema", "outputSchema"]) {
30
44
  const schema = definition[field];
31
45
  if (schema.type !== "object")
32
- context.addIssue({ code: "custom", path: [field], message: "Task input/output use object envelopes; declare type: object." });
46
+ context.addIssue({
47
+ code: "custom",
48
+ path: [field],
49
+ message: "Task input/output use object envelopes; declare type: object.",
50
+ });
33
51
  const report = validateTaskSchema(schema);
34
52
  if (!report.valid)
35
53
  context.addIssue({ code: "custom", path: [field], message: report.issues[0].message });
36
54
  }
37
- if (Boolean(definition.execution.environmentRelease) !== Boolean(definition.execution.verifierSetRelease))
38
- context.addIssue({ code: "custom", path: ["execution"], message: "Bind both the environment and verifier-set releases." });
55
+ if (Boolean(definition.execution.environmentRelease) !==
56
+ Boolean(definition.execution.verifierSetRelease))
57
+ context.addIssue({
58
+ code: "custom",
59
+ path: ["execution"],
60
+ message: "Bind both the environment and verifier-set releases.",
61
+ });
39
62
  });
40
- export const TaskDefinitionSchema = TaskDefinitionContentSchema.safeExtend({ contentHash: ReleaseHashSchema }).strict();
41
- export const TaskSourceMappingSchema = z.object({
63
+ export const TaskDefinitionSchema = TaskDefinitionContentSchema.safeExtend({
64
+ contentHash: ReleaseHashSchema,
65
+ }).strict();
66
+ export const TaskSourceMappingSchema = z
67
+ .object({
42
68
  schemaVersion: z.literal("openpond.taskSourceMapping.v1"),
43
69
  exampleId: LearningJsonPointerSchema,
44
70
  attemptId: LearningJsonPointerSchema,
@@ -49,17 +75,21 @@ export const TaskSourceMappingSchema = z.object({
49
75
  evaluatorContext: LearningJsonPointerSchema.nullable(),
50
76
  familyKey: LearningJsonPointerSchema,
51
77
  split: TaskSplitSchema,
52
- }).strict();
78
+ })
79
+ .strict();
53
80
  /** An explicit Model edit starts new evidence; the original admissions remain
54
81
  * in the exact parent package and are never approvals for this source. */
55
- export const LearningReviewOriginSchema = z.object({
82
+ export const LearningReviewOriginSchema = z
83
+ .object({
56
84
  modelId: ReleaseIdSchema,
57
85
  packageHash: ReleaseHashSchema,
58
86
  taskset: LearningRevisionRefSchema,
59
87
  batch: LearningRevisionRefSchema,
60
88
  rewardBinding: LearningRevisionRefSchema,
61
- }).strict();
62
- export const LearningSourceContentSchema = z.object({
89
+ })
90
+ .strict();
91
+ export const LearningSourceContentSchema = z
92
+ .object({
63
93
  schemaVersion: z.literal("openpond.learningSource.v1"),
64
94
  id: ReleaseIdSchema,
65
95
  revision: z.number().int().positive(),
@@ -71,16 +101,33 @@ export const LearningSourceContentSchema = z.object({
71
101
  mapping: TaskSourceMappingSchema.nullable(),
72
102
  adapterVersion: z.string().trim().min(1).max(200).nullable(),
73
103
  reviewOrigin: LearningReviewOriginSchema.optional(),
74
- }).strict().superRefine((source, context) => {
104
+ })
105
+ .strict()
106
+ .superRefine((source, context) => {
75
107
  if (source.kind !== "direct" && !source.mapping)
76
- context.addIssue({ code: "custom", path: ["mapping"], message: "Mapped sources require an explicit mapping." });
108
+ context.addIssue({
109
+ code: "custom",
110
+ path: ["mapping"],
111
+ message: "Mapped sources require an explicit mapping.",
112
+ });
77
113
  if (source.mapping && !source.allowedSplits.includes(source.mapping.split))
78
- context.addIssue({ code: "custom", path: ["allowedSplits"], message: "The mapping split must be allowed by this source." });
114
+ context.addIssue({
115
+ code: "custom",
116
+ path: ["allowedSplits"],
117
+ message: "The mapping split must be allowed by this source.",
118
+ });
79
119
  if (["opentelemetry", "provider"].includes(source.kind) && !source.adapterVersion)
80
- context.addIssue({ code: "custom", path: ["adapterVersion"], message: "Trace adapters require a pinned version." });
120
+ context.addIssue({
121
+ code: "custom",
122
+ path: ["adapterVersion"],
123
+ message: "Trace adapters require a pinned version.",
124
+ });
81
125
  });
82
- export const LearningSourceSchema = LearningSourceContentSchema.safeExtend({ contentHash: ReleaseHashSchema }).strict();
83
- export const TaskExampleSubmissionSchema = z.object({
126
+ export const LearningSourceSchema = LearningSourceContentSchema.safeExtend({
127
+ contentHash: ReleaseHashSchema,
128
+ }).strict();
129
+ export const TaskExampleSubmissionSchema = z
130
+ .object({
84
131
  schemaVersion: z.literal("openpond.taskExample.v1"),
85
132
  sourceId: ReleaseIdSchema,
86
133
  idempotencyKey: ReleaseIdSchema,
@@ -96,9 +143,16 @@ export const TaskExampleSubmissionSchema = z.object({
96
143
  evaluatorContext: LearningJsonObjectSchema.nullable(),
97
144
  assets: z.array(ImmutableAssetRefSchema).max(1_000),
98
145
  requiredOutputs: TaskRecordSchema.shape.requiredOutputs,
99
- provenance: z.object({ sourceRecordRef: z.string().max(2_000).nullable(), mappingHash: ReleaseHashSchema.nullable() }).strict(),
100
- }).strict();
101
- export const TaskEvidenceContentSchema = z.object({
146
+ provenance: z
147
+ .object({
148
+ sourceRecordRef: z.string().max(2_000).nullable(),
149
+ mappingHash: ReleaseHashSchema.nullable(),
150
+ })
151
+ .strict(),
152
+ })
153
+ .strict();
154
+ export const TaskEvidenceContentSchema = z
155
+ .object({
102
156
  schemaVersion: z.literal("openpond.taskEvidence.v1"),
103
157
  id: ReleaseIdSchema,
104
158
  revision: z.number().int().positive(),
@@ -107,23 +161,38 @@ export const TaskEvidenceContentSchema = z.object({
107
161
  supersedes: LearningRevisionRefSchema.nullable(),
108
162
  correctionFeedbackId: ReleaseIdSchema.nullable(),
109
163
  receivedAt: ReleaseTimestampSchema,
164
+ })
165
+ .strict();
166
+ export const TaskEvidenceSchema = TaskEvidenceContentSchema.extend({
167
+ contentHash: ReleaseHashSchema,
110
168
  }).strict();
111
- export const TaskEvidenceSchema = TaskEvidenceContentSchema.extend({ contentHash: ReleaseHashSchema }).strict();
112
169
  /** A retained judgment of this exact attempt, separate from task admission. */
113
- export const TaskRatingSchema = z.object({
170
+ export const TaskRatingSchema = z
171
+ .object({
114
172
  schemaVersion: z.literal("openpond.taskRating.v1"),
115
173
  criteria: z.string().trim().min(1).max(20_000),
116
174
  scale: z.object({ minimum: z.number().finite(), maximum: z.number().finite() }).strict(),
117
175
  score: z.number().finite(),
118
176
  evidence: z.string().max(20_000),
119
177
  explanation: z.string().max(20_000),
120
- }).strict().superRefine((rating, context) => {
178
+ })
179
+ .strict()
180
+ .superRefine((rating, context) => {
121
181
  if (rating.scale.minimum >= rating.scale.maximum)
122
- context.addIssue({ code: "custom", path: ["scale"], message: "The score scale must have an increasing range." });
182
+ context.addIssue({
183
+ code: "custom",
184
+ path: ["scale"],
185
+ message: "The score scale must have an increasing range.",
186
+ });
123
187
  if (rating.score < rating.scale.minimum || rating.score > rating.scale.maximum)
124
- context.addIssue({ code: "custom", path: ["score"], message: "The score must be within its declared scale." });
188
+ context.addIssue({
189
+ code: "custom",
190
+ path: ["score"],
191
+ message: "The score must be within its declared scale.",
192
+ });
125
193
  });
126
- export const TaskFeedbackSubmissionSchema = z.object({
194
+ export const TaskFeedbackSubmissionSchema = z
195
+ .object({
127
196
  schemaVersion: z.literal("openpond.taskFeedback.v1"),
128
197
  sourceId: ReleaseIdSchema,
129
198
  idempotencyKey: ReleaseIdSchema,
@@ -131,22 +200,43 @@ export const TaskFeedbackSubmissionSchema = z.object({
131
200
  attemptId: ReleaseIdSchema,
132
201
  expectedEvidenceHash: ReleaseHashSchema.nullable(),
133
202
  occurredAt: ReleaseTimestampSchema,
134
- kind: z.enum(["outcome", "target_correction", "ground_truth_correction", "input_correction", "family_resolution"]),
203
+ kind: z.enum([
204
+ "outcome",
205
+ "target_correction",
206
+ "ground_truth_correction",
207
+ "input_correction",
208
+ "family_resolution",
209
+ ]),
135
210
  value: LearningJsonObjectSchema,
136
211
  note: z.string().max(20_000),
137
- }).strict().superRefine((submission, context) => {
212
+ })
213
+ .strict()
214
+ .superRefine((submission, context) => {
138
215
  if (submission.value.schemaVersion !== "openpond.taskRating.v1")
139
216
  return;
140
217
  if (submission.expectedEvidenceHash === null)
141
- context.addIssue({ code: "custom", path: ["expectedEvidenceHash"], message: "A rating must identify the exact evidence revision." });
218
+ context.addIssue({
219
+ code: "custom",
220
+ path: ["expectedEvidenceHash"],
221
+ message: "A rating must identify the exact evidence revision.",
222
+ });
142
223
  if (submission.kind !== "outcome")
143
- context.addIssue({ code: "custom", path: ["kind"], message: "Ratings must be submitted as outcomes." });
224
+ context.addIssue({
225
+ code: "custom",
226
+ path: ["kind"],
227
+ message: "Ratings must be submitted as outcomes.",
228
+ });
144
229
  const rating = TaskRatingSchema.safeParse(submission.value);
145
230
  if (!rating.success)
146
231
  for (const issue of rating.error.issues)
147
- context.addIssue({ code: "custom", path: ["value", ...issue.path], message: issue.message });
232
+ context.addIssue({
233
+ code: "custom",
234
+ path: ["value", ...issue.path],
235
+ message: issue.message,
236
+ });
148
237
  });
149
- export const TaskFeedbackSchema = z.object({
238
+ export const TaskFeedbackSchema = z
239
+ .object({
150
240
  schemaVersion: z.literal("openpond.taskFeedbackRecord.v1"),
151
241
  id: ReleaseIdSchema,
152
242
  submission: TaskFeedbackSubmissionSchema,
@@ -154,16 +244,41 @@ export const TaskFeedbackSchema = z.object({
154
244
  evidence: LearningRevisionRefSchema.nullable(),
155
245
  createdAt: ReleaseTimestampSchema,
156
246
  revision: z.number().int().positive(),
157
- submittedBy: z.object({ id: ReleaseIdSchema, role: z.enum(["editor", "reviewer", "source"]), sourceId: ReleaseIdSchema.nullable() }).strict().nullable().default(null),
158
- review: z.object({ actorId: ReleaseIdSchema, decision: LearningRevisionRefSchema.nullable(), note: z.string().max(20_000), resolvedAt: ReleaseTimestampSchema }).strict().nullable().default(null),
159
- }).strict();
160
- export const TaskAdmissionDecisionContentSchema = z.object({
247
+ submittedBy: z
248
+ .object({
249
+ id: ReleaseIdSchema,
250
+ role: z.enum(["editor", "reviewer", "source"]),
251
+ sourceId: ReleaseIdSchema.nullable(),
252
+ })
253
+ .strict()
254
+ .nullable()
255
+ .default(null),
256
+ review: z
257
+ .object({
258
+ actorId: ReleaseIdSchema,
259
+ decision: LearningRevisionRefSchema.nullable(),
260
+ note: z.string().max(20_000),
261
+ resolvedAt: ReleaseTimestampSchema,
262
+ })
263
+ .strict()
264
+ .nullable()
265
+ .default(null),
266
+ })
267
+ .strict();
268
+ export const TaskAdmissionDecisionContentSchema = z
269
+ .object({
161
270
  schemaVersion: z.literal("openpond.taskAdmissionDecision.v1"),
162
271
  id: ReleaseIdSchema,
163
272
  revision: z.number().int().positive(),
164
273
  evidence: LearningRevisionRefSchema,
165
274
  supersedes: LearningRevisionRefSchema.nullable(),
166
- actor: z.object({ kind: z.enum(["human", "qualified_policy"]), id: ReleaseIdSchema, policy: LearningRevisionRefSchema.nullable() }).strict(),
275
+ actor: z
276
+ .object({
277
+ kind: z.enum(["human", "qualified_policy"]),
278
+ id: ReleaseIdSchema,
279
+ policy: LearningRevisionRefSchema.nullable(),
280
+ })
281
+ .strict(),
167
282
  evidenceValidity: z.enum(["valid", "invalid", "pending"]),
168
283
  taskAdmissibility: z.enum(["approved", "rejected", "pending"]),
169
284
  observedQuality: z.enum(["passed", "failed", "unscored", "unavailable"]),
@@ -173,43 +288,93 @@ export const TaskAdmissionDecisionContentSchema = z.object({
173
288
  targetGrade: RewardCompositionSchema.nullable(),
174
289
  note: z.string().max(20_000),
175
290
  decidedAt: ReleaseTimestampSchema,
176
- }).strict().superRefine((decision, context) => {
291
+ })
292
+ .strict()
293
+ .superRefine((decision, context) => {
177
294
  if (decision.targetApproval === "approved" && decision.approvedTarget === null)
178
- context.addIssue({ code: "custom", path: ["approvedTarget"], message: "Target approval requires an actual target." });
295
+ context.addIssue({
296
+ code: "custom",
297
+ path: ["approvedTarget"],
298
+ message: "Target approval requires an actual target.",
299
+ });
179
300
  if (decision.targetApproval !== "approved" && decision.approvedTarget !== null)
180
- context.addIssue({ code: "custom", path: ["approvedTarget"], message: "Only approved targets may be selected for supervised learning." });
301
+ context.addIssue({
302
+ code: "custom",
303
+ path: ["approvedTarget"],
304
+ message: "Only approved targets may be selected for supervised learning.",
305
+ });
181
306
  if (decision.actor.kind === "qualified_policy" && !decision.actor.policy)
182
- context.addIssue({ code: "custom", path: ["actor"], message: "Automatic admission must pin its qualified policy." });
307
+ context.addIssue({
308
+ code: "custom",
309
+ path: ["actor"],
310
+ message: "Automatic admission must pin its qualified policy.",
311
+ });
183
312
  if (decision.taskAdmissibility === "approved" && decision.evidenceValidity !== "valid")
184
- context.addIssue({ code: "custom", path: ["taskAdmissibility"], message: "Only valid evidence can produce an approved task." });
313
+ context.addIssue({
314
+ code: "custom",
315
+ path: ["taskAdmissibility"],
316
+ message: "Only valid evidence can produce an approved task.",
317
+ });
185
318
  });
186
- export const TaskAdmissionDecisionSchema = TaskAdmissionDecisionContentSchema.safeExtend({ contentHash: ReleaseHashSchema }).strict();
187
- export const TaskBatchContentSchema = z.object({
319
+ export const TaskAdmissionDecisionSchema = TaskAdmissionDecisionContentSchema.safeExtend({
320
+ contentHash: ReleaseHashSchema,
321
+ }).strict();
322
+ export const TaskBatchContentSchema = z
323
+ .object({
188
324
  schemaVersion: z.literal("openpond.taskBatch.v1"),
189
325
  id: ReleaseIdSchema,
190
326
  revision: z.literal(1),
191
327
  taskDefinition: LearningRevisionRefSchema,
192
328
  rewardBinding: LearningRevisionRefSchema,
193
329
  purpose: z.enum(["supervised_training", "reward_training", "evaluation"]),
194
- examples: z.array(z.object({ evidence: LearningRevisionRefSchema, decision: LearningRevisionRefSchema, familyKey: ReleaseIdSchema, inputHash: ReleaseHashSchema, split: TaskSplitSchema }).strict()).min(1).max(10_000),
330
+ examples: z
331
+ .array(z
332
+ .object({
333
+ evidence: LearningRevisionRefSchema,
334
+ decision: LearningRevisionRefSchema,
335
+ familyKey: ReleaseIdSchema,
336
+ inputHash: ReleaseHashSchema,
337
+ split: TaskSplitSchema,
338
+ })
339
+ .strict())
340
+ .min(1)
341
+ .max(10_000),
195
342
  sealedAt: ReleaseTimestampSchema,
196
343
  sealedBy: ReleaseIdSchema,
197
- }).strict().superRefine((batch, context) => {
344
+ })
345
+ .strict()
346
+ .superRefine((batch, context) => {
198
347
  if (new Set(batch.examples.map((entry) => entry.evidence.id)).size !== batch.examples.length)
199
- context.addIssue({ code: "custom", path: ["examples"], message: "Each evidence identity can occur only once in a batch." });
348
+ context.addIssue({
349
+ code: "custom",
350
+ path: ["examples"],
351
+ message: "Each evidence identity can occur only once in a batch.",
352
+ });
200
353
  const splits = new Map();
201
354
  for (const [index, entry] of batch.examples.entries()) {
202
355
  if ((batch.purpose === "evaluation") === (entry.split === "train"))
203
- context.addIssue({ code: "custom", path: ["examples", index, "split"], message: "Training uses train examples; evaluation uses held-out examples." });
356
+ context.addIssue({
357
+ code: "custom",
358
+ path: ["examples", index, "split"],
359
+ message: "Training uses train examples; evaluation uses held-out examples.",
360
+ });
204
361
  for (const key of [`family:${entry.familyKey}`, `input:${entry.inputHash}`]) {
205
362
  if (splits.has(key) && splits.get(key) !== entry.split)
206
- context.addIssue({ code: "custom", path: ["examples", index], message: "A task family or identical input cannot cross splits." });
363
+ context.addIssue({
364
+ code: "custom",
365
+ path: ["examples", index],
366
+ message: "A task family or identical input cannot cross splits.",
367
+ });
207
368
  splits.set(key, entry.split);
208
369
  }
209
370
  }
210
371
  });
211
- export const TaskBatchSchema = TaskBatchContentSchema.safeExtend({ contentHash: ReleaseHashSchema }).strict();
212
- export const LearningPolicyContentSchema = z.object({
372
+ export const TaskBatchSchema = TaskBatchContentSchema.safeExtend({
373
+ contentHash: ReleaseHashSchema,
374
+ }).strict();
375
+ export const LearningPolicyContentSchema = z
376
+ .object({
377
+ origin: TrainingHandoffOriginSchema.optional(),
213
378
  schemaVersion: z.literal("openpond.learningPolicy.v1"),
214
379
  id: ReleaseIdSchema,
215
380
  revision: z.number().int().positive(),
@@ -219,44 +384,127 @@ export const LearningPolicyContentSchema = z.object({
219
384
  sources: z.array(LearningRevisionRefSchema).min(1).max(100),
220
385
  taskDefinition: LearningRevisionRefSchema,
221
386
  rewardBinding: LearningRevisionRefSchema,
222
- admission: z.object({ mode: z.enum(["human", "qualified_automatic"]), qualification: ImmutableReleaseRefSchema.nullable(), minimumApprovedExamples: z.number().int().positive().max(100_000) }).strict(),
387
+ admission: z
388
+ .object({
389
+ mode: z.enum(["human", "qualified_automatic"]),
390
+ qualification: ImmutableReleaseRefSchema.nullable(),
391
+ minimumApprovedExamples: z.number().int().positive().max(100_000),
392
+ })
393
+ .strict(),
223
394
  trigger: z.discriminatedUnion("kind", [
224
395
  z.object({ kind: z.literal("manual") }).strict(),
225
396
  z.object({ kind: z.literal("approved_count") }).strict(),
226
- z.object({ kind: z.literal("schedule"), intervalSeconds: z.number().int().min(60).max(31_536_000) }).strict(),
397
+ z
398
+ .object({
399
+ kind: z.literal("schedule"),
400
+ intervalSeconds: z.number().int().min(60).max(31_536_000),
401
+ })
402
+ .strict(),
227
403
  NightlyScheduleSchema.extend({ kind: z.literal("nightly") }).strict(),
228
404
  z.object({ kind: z.literal("upstream_accepted"), modelProjectId: ReleaseIdSchema }).strict(),
229
405
  ]),
230
406
  trainingParent: ImmutableReleaseRefSchema,
231
407
  teacher: ImmutableReleaseRefSchema.nullable(),
232
- training: z.object({ method: z.enum(["sft", "dpo", "grpo", "ppo", "sdft", "opd", "opsd", "sdpo"]), recipe: ImmutableReleaseRefSchema, retentionEvaluation: ImmutableReleaseRefSchema, replayBatches: z.array(ImmutableReleaseRefSchema).max(100) }).strict(),
233
- limits: z.object({ maxIterationSpendUsd: z.number().positive().max(100_000), maxDailySpendUsd: z.number().positive().max(1_000_000), cooldownSeconds: z.number().int().nonnegative().max(31_536_000), maxRetries: z.number().int().nonnegative().max(10), maxBatchExamples: z.number().int().positive().max(10_000), maxBacklogExamples: z.number().int().positive().max(1_000_000) }).strict(),
234
- automation: z.object({ collect: z.boolean(), train: z.boolean(), accept: z.boolean(), serve: z.boolean() }).strict(),
235
- acceptance: z.object({ minimumScore: z.number().min(0).max(1), maximumRetentionRegression: z.number().min(0).max(1), requireImprovement: z.boolean(), rollbackVersion: ImmutableReleaseRefSchema.nullable() }).strict(),
236
- }).strict().superRefine((policy, context) => {
408
+ training: z
409
+ .object({
410
+ method: z.enum(["sft", "dpo", "grpo", "ppo", "sdft", "opd", "opsd", "sdpo"]),
411
+ recipe: ImmutableReleaseRefSchema,
412
+ retentionEvaluation: ImmutableReleaseRefSchema,
413
+ replayBatches: z.array(ImmutableReleaseRefSchema).max(100),
414
+ })
415
+ .strict(),
416
+ limits: z
417
+ .object({
418
+ maxIterationSpendUsd: z.number().positive().max(100_000),
419
+ maxDailySpendUsd: z.number().positive().max(1_000_000),
420
+ cooldownSeconds: z.number().int().nonnegative().max(31_536_000),
421
+ maxRetries: z.number().int().nonnegative().max(10),
422
+ maxBatchExamples: z.number().int().positive().max(10_000),
423
+ maxBacklogExamples: z.number().int().positive().max(1_000_000),
424
+ })
425
+ .strict(),
426
+ automation: z
427
+ .object({ collect: z.boolean(), train: z.boolean(), accept: z.boolean(), serve: z.boolean() })
428
+ .strict(),
429
+ acceptance: z
430
+ .object({
431
+ minimumScore: z.number().min(0).max(1),
432
+ maximumRetentionRegression: z.number().min(0).max(1),
433
+ requireImprovement: z.boolean(),
434
+ rollbackVersion: ImmutableReleaseRefSchema.nullable(),
435
+ })
436
+ .strict(),
437
+ })
438
+ .strict()
439
+ .superRefine((policy, context) => {
237
440
  if (policy.admission.mode === "qualified_automatic" && !policy.admission.qualification)
238
- context.addIssue({ code: "custom", path: ["admission"], message: "Automatic admission requires qualification evidence." });
441
+ context.addIssue({
442
+ code: "custom",
443
+ path: ["admission"],
444
+ message: "Automatic admission requires qualification evidence.",
445
+ });
239
446
  if (policy.automation.serve && !policy.automation.accept)
240
- context.addIssue({ code: "custom", path: ["automation"], message: "Automatic serving requires configured acceptance." });
447
+ context.addIssue({
448
+ code: "custom",
449
+ path: ["automation"],
450
+ message: "Automatic serving requires configured acceptance.",
451
+ });
241
452
  if (policy.automation.accept && !policy.acceptance.rollbackVersion)
242
- context.addIssue({ code: "custom", path: ["acceptance"], message: "Automatic acceptance requires a rollback version." });
243
- if (policy.trigger.kind === "upstream_accepted" && policy.trigger.modelProjectId === policy.modelProjectId)
244
- context.addIssue({ code: "custom", path: ["trigger"], message: "A model cannot trigger itself through upstream acceptance." });
453
+ context.addIssue({
454
+ code: "custom",
455
+ path: ["acceptance"],
456
+ message: "Automatic acceptance requires a rollback version.",
457
+ });
458
+ if (policy.trigger.kind === "upstream_accepted" &&
459
+ policy.trigger.modelProjectId === policy.modelProjectId)
460
+ context.addIssue({
461
+ code: "custom",
462
+ path: ["trigger"],
463
+ message: "A model cannot trigger itself through upstream acceptance.",
464
+ });
245
465
  if (policy.limits.maxBatchExamples < policy.admission.minimumApprovedExamples)
246
- context.addIssue({ code: "custom", path: ["limits"], message: "The batch limit must permit the minimum approved example count." });
466
+ context.addIssue({
467
+ code: "custom",
468
+ path: ["limits"],
469
+ message: "The batch limit must permit the minimum approved example count.",
470
+ });
247
471
  if (policy.limits.maxDailySpendUsd < policy.limits.maxIterationSpendUsd)
248
- context.addIssue({ code: "custom", path: ["limits"], message: "Daily spend must permit the iteration budget." });
472
+ context.addIssue({
473
+ code: "custom",
474
+ path: ["limits"],
475
+ message: "Daily spend must permit the iteration budget.",
476
+ });
249
477
  });
250
- export const LearningPolicySchema = LearningPolicyContentSchema.safeExtend({ contentHash: ReleaseHashSchema }).strict();
251
- export const LearningAcceptedParentSchema = z.object({
478
+ export const LearningPolicySchema = LearningPolicyContentSchema.safeExtend({
479
+ contentHash: ReleaseHashSchema,
480
+ }).strict();
481
+ export const LearningAcceptedParentSchema = z
482
+ .object({
252
483
  iterationId: ReleaseIdSchema,
253
484
  iterationRevision: z.number().int().positive(),
254
485
  candidate: ImmutableReleaseRefSchema,
255
486
  decision: LearningRevisionRefSchema,
256
487
  decidedAt: ReleaseTimestampSchema,
257
- }).strict();
258
- export const LearningIterationStatusSchema = z.enum(["waiting_for_data", "waiting_for_review", "ready", "dispatching", "training", "evaluating", "candidate_ready", "accepted", "rejected", "paused", "failed", "cancelling", "cancelled", "completed_without_candidate"]);
259
- export const LearningIterationSchema = z.object({
488
+ })
489
+ .strict();
490
+ export const LearningIterationStatusSchema = z.enum([
491
+ "waiting_for_data",
492
+ "waiting_for_review",
493
+ "ready",
494
+ "dispatching",
495
+ "training",
496
+ "evaluating",
497
+ "candidate_ready",
498
+ "accepted",
499
+ "rejected",
500
+ "paused",
501
+ "failed",
502
+ "cancelling",
503
+ "cancelled",
504
+ "completed_without_candidate",
505
+ ]);
506
+ export const LearningIterationSchema = z
507
+ .object({
260
508
  schemaVersion: z.literal("openpond.learningIteration.v1"),
261
509
  id: ReleaseIdSchema,
262
510
  revision: z.number().int().positive(),
@@ -277,11 +525,16 @@ export const LearningIterationSchema = z.object({
277
525
  dispatchId: ReleaseIdSchema,
278
526
  retryCount: z.number().int().nonnegative(),
279
527
  spendUsd: z.number().nonnegative(),
280
- failure: z.object({ code: ReleaseIdSchema, message: z.string().max(20_000) }).strict().nullable(),
528
+ failure: z
529
+ .object({ code: ReleaseIdSchema, message: z.string().max(20_000) })
530
+ .strict()
531
+ .nullable(),
281
532
  createdAt: ReleaseTimestampSchema,
282
533
  updatedAt: ReleaseTimestampSchema,
283
- }).strict();
284
- export const TaskGradeRunSchema = z.object({
534
+ })
535
+ .strict();
536
+ export const TaskGradeRunSchema = z
537
+ .object({
285
538
  schemaVersion: z.literal("openpond.taskGradeRun.v1"),
286
539
  id: ReleaseIdSchema,
287
540
  revision: z.number().int().positive(),
@@ -301,13 +554,32 @@ export const TaskGradeRunSchema = z.object({
301
554
  failure: z.string().max(20_000).nullable(),
302
555
  createdAt: ReleaseTimestampSchema,
303
556
  updatedAt: ReleaseTimestampSchema,
304
- }).strict();
305
- export const LearningResourceSchema = z.union([TaskDefinitionSchema, RewardReleaseSchema, RewardBindingSchema, LearningSourceSchema, TaskEvidenceSchema, TaskFeedbackSchema, TaskAdmissionDecisionSchema, TaskBatchSchema, LearningPolicySchema, LearningIterationSchema, TaskGradeRunSchema]);
557
+ })
558
+ .strict();
559
+ export const LearningResourceSchema = z.union([
560
+ TaskDefinitionSchema,
561
+ RewardReleaseSchema,
562
+ RewardBindingSchema,
563
+ LearningSourceSchema,
564
+ TaskEvidenceSchema,
565
+ TaskFeedbackSchema,
566
+ TaskAdmissionDecisionSchema,
567
+ TaskBatchSchema,
568
+ LearningPolicySchema,
569
+ LearningIterationSchema,
570
+ TaskGradeRunSchema,
571
+ ]);
306
572
  export function learningRef(resource) {
307
- return LearningRevisionRefSchema.parse({ id: resource.id, revision: resource.revision, contentHash: resource.contentHash });
573
+ return LearningRevisionRefSchema.parse({
574
+ id: resource.id,
575
+ revision: resource.revision,
576
+ contentHash: resource.contentHash,
577
+ });
308
578
  }
309
579
  export function sameLearningRef(left, right) {
310
- return left.id === right.id && left.revision === right.revision && left.contentHash === right.contentHash;
580
+ return (left.id === right.id &&
581
+ left.revision === right.revision &&
582
+ left.contentHash === right.contentHash);
311
583
  }
312
584
  export function sealLearningContent(content) {
313
585
  assertBoundedTaskJson(content, 16_777_216);
@@ -34,3 +34,4 @@ export * from "./policy-inspection.js";
34
34
  export * from "./task-queue-inspection.js";
35
35
  export * from "./acceptance-plan.js";
36
36
  export * from "./acceptance-group.js";
37
+ export { TrainingHandoffOriginSchema } from "./training-handoff.js";
@@ -4,6 +4,7 @@ import { RewardAuthoringFieldsSchema, RewardFixtureAuthoringFieldsSchema } from
4
4
  import { createLearningTextAsset, verifyLearningTextAsset } from "./assets.js";
5
5
  import { LearningJsonObjectSchema } from "./contracts.js";
6
6
  import { LearningDomainError } from "./errors.js";
7
+ import { HumanFormSchema } from "../human-review/contracts.js";
7
8
  export const DEFAULT_REWARD_VERIFIER_SOURCE = `export function verify({ output, expectedOutput }) {
8
9
  if (!expectedOutput || !Object.hasOwn(expectedOutput, "answer")) {
9
10
  throw new Error("An expected answer is required.");
@@ -25,14 +26,14 @@ export function compileRewardAuthoring(input) {
25
26
  if (fields.kind === "custom_verifier") {
26
27
  asset = createLearningTextAsset({ text: fields.code, path: "verifier.mjs", mediaType: "application/javascript", visibility: "verifier" });
27
28
  implementation = { kind: fields.kind, verifierRef: asset.asset, exportName: fields.exportName, timeoutMs: authoringNumber(fields.timeout, "Time limit"), networkPolicy: "none",
28
- ...(base?.implementation.kind === "custom_verifier" && base.implementation.runtime !== undefined ? { runtime: base.implementation.runtime } : {}) };
29
+ ...((fields.verifierRuntime ?? (base?.implementation.kind === "custom_verifier" ? base.implementation.runtime : undefined)) ? { runtime: fields.verifierRuntime ?? (base?.implementation.kind === "custom_verifier" ? base.implementation.runtime : undefined) } : {}) };
29
30
  }
30
31
  else if (fields.kind === "model_judge" || fields.kind === "human") {
31
32
  if (!fields.rubric.trim())
32
33
  throw new LearningDomainError("reward_rubric_required", 422, "Write the rubric before checking or publishing this Reward.");
33
34
  asset = createLearningTextAsset({ text: fields.rubric, path: "rubric.md", mediaType: "text/markdown", visibility: "verifier" });
34
35
  if (fields.kind === "human")
35
- implementation = { kind: fields.kind, rubricRef: asset.asset, reviewerRole: fields.reviewerRole };
36
+ implementation = { kind: fields.kind, rubricRef: asset.asset, reviewerRole: fields.reviewerRole, form: HumanFormSchema.parse(JSON.parse(fields.humanForm || JSON.stringify({ schemaVersion: "openpond.humanForm.v1", mode: "individual", instructions: fields.rubric, criteria: [{ id: "quality", label: "Quality", instructions: fields.rubric, required: true, allowAbstain: true, kind: "score", minimum: 0, maximum: 1, step: 0.1 }] }))) };
36
37
  else {
37
38
  const model = { providerId: fields.providerId, modelId: fields.modelId, revision: fields.modelRevision.trim() || null };
38
39
  const temperature = authoringNumber(fields.temperature, "Temperature");
@@ -89,6 +90,7 @@ export function rewardAuthoringFields(reward, sourceAsset, fixtureAsset = null)
89
90
  schema: JSON.stringify(config.jsonSchema ?? { type: "object", properties: { answer: { type: "string" } }, required: ["answer"] }, null, 2),
90
91
  reference: text(config.refIncludes), events: strings(config.requiredEvents).join(", "),
91
92
  code: implementation?.kind === "custom_verifier" ? source : DEFAULT_REWARD_VERIFIER_SOURCE,
93
+ verifierRuntime: implementation?.kind === "custom_verifier" ? implementation.runtime ?? "isolated_javascript" : "isolated_javascript",
92
94
  exportName: implementation?.kind === "custom_verifier" ? implementation.exportName ?? "verify" : "verify",
93
95
  timeout: String(implementation?.kind === "custom_verifier" ? implementation.timeoutMs : 5_000),
94
96
  rubric: implementation?.kind === "model_judge" || implementation?.kind === "human" ? source : "",
@@ -97,6 +99,7 @@ export function rewardAuthoringFields(reward, sourceAsset, fixtureAsset = null)
97
99
  modelRevision: implementation?.kind === "model_judge" ? implementation.model?.revision ?? "" : "",
98
100
  temperature: String(implementation?.kind === "model_judge" ? implementation.temperature ?? 0 : 0),
99
101
  reviewerRole: implementation?.kind === "human" ? implementation.reviewerRole : "Subject matter reviewer",
102
+ humanForm: implementation?.kind === "human" && implementation.form ? JSON.stringify(implementation.form, null, 2) : "",
100
103
  learnedId: implementation?.kind === "learned_model" ? implementation.modelVersion.id : "",
101
104
  learnedHash: implementation?.kind === "learned_model" ? implementation.modelVersion.contentHash : "",
102
105
  inputContract: implementation?.kind === "learned_model" ? source : "{}",