@openpond/harness 0.2.3 → 0.2.4
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/CONTRACT.md +11 -3
- package/README.md +141 -2
- package/dist/evaluation-review.js +39 -7
- package/dist/index.js +1 -0
- package/dist/refinement-lifecycle.js +490 -0
- package/dist/refiner-detection.js +11 -3
- package/dist/refiner.js +279 -80
- package/dist/types/evaluation-review.d.ts +14 -0
- package/dist/types/evaluation-review.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/refinement-lifecycle.d.ts +775 -0
- package/dist/types/refinement-lifecycle.d.ts.map +1 -0
- package/dist/types/refiner.d.ts +310 -65
- package/dist/types/refiner.d.ts.map +1 -1
- package/package.json +5 -1
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { contentHash, ImmutableReleaseRefSchema, ReleaseHashSchema, ReleaseIdSchema, ReleaseTimestampSchema, } from "./common.js";
|
|
3
|
+
import { HarnessReviewEvidenceRefSchema, HarnessReviewOwnerScopeSchema, } from "./evaluation-review.js";
|
|
4
|
+
import { HarnessRefinerCapabilitiesSchema, HarnessRefinerEvidenceBasisSchema, } from "./refiner.js";
|
|
5
|
+
import { HarnessImprovementRouteSchema } from "./harness-workspaces.js";
|
|
6
|
+
const ShortTextSchema = z.string().trim().min(1).max(2_000);
|
|
7
|
+
const BoundedTextSchema = z.string().trim().min(1).max(100_000);
|
|
8
|
+
const HarnessRefinerOperationSchema = z.enum(["create", "update", "delete"]);
|
|
9
|
+
const HarnessRefinerInternalRouteSchema = z.enum([
|
|
10
|
+
"memory",
|
|
11
|
+
"prompt",
|
|
12
|
+
"skill",
|
|
13
|
+
"agent",
|
|
14
|
+
]);
|
|
15
|
+
const HarnessRefinerExternalRouteSchema = z.enum([
|
|
16
|
+
"runtime",
|
|
17
|
+
"product",
|
|
18
|
+
"taskset",
|
|
19
|
+
"training",
|
|
20
|
+
]);
|
|
21
|
+
export const HarnessRefinerActivityResultSchema = z.enum([
|
|
22
|
+
"no_action",
|
|
23
|
+
"routed",
|
|
24
|
+
"applied",
|
|
25
|
+
"retained",
|
|
26
|
+
"failed",
|
|
27
|
+
]);
|
|
28
|
+
export const HarnessRefinerCritiqueStatusSchema = z.enum([
|
|
29
|
+
"not_applicable",
|
|
30
|
+
"pending",
|
|
31
|
+
"passed",
|
|
32
|
+
"rejected",
|
|
33
|
+
"failed",
|
|
34
|
+
]);
|
|
35
|
+
export const HarnessRefinerValidationStatusSchema = z.enum([
|
|
36
|
+
"not_applicable",
|
|
37
|
+
"pending",
|
|
38
|
+
"passed",
|
|
39
|
+
"failed",
|
|
40
|
+
]);
|
|
41
|
+
export const HarnessRefinerActivityReceiptContentSchema = z
|
|
42
|
+
.object({
|
|
43
|
+
schemaVersion: z.literal("openpond.harnessRefinerActivityReceipt.v1"),
|
|
44
|
+
id: ReleaseIdSchema,
|
|
45
|
+
runRef: ReleaseIdSchema,
|
|
46
|
+
turnId: ReleaseIdSchema,
|
|
47
|
+
result: HarnessRefinerActivityResultSchema,
|
|
48
|
+
decision: z.enum(["no_action", "route", "propose"]).nullable(),
|
|
49
|
+
route: HarnessImprovementRouteSchema.nullable(),
|
|
50
|
+
operation: HarnessRefinerOperationSchema.nullable(),
|
|
51
|
+
target: z.string().trim().min(1).max(2_000).nullable(),
|
|
52
|
+
summary: ShortTextSchema,
|
|
53
|
+
evidenceBasis: HarnessRefinerEvidenceBasisSchema.nullable(),
|
|
54
|
+
critiqueStatus: HarnessRefinerCritiqueStatusSchema,
|
|
55
|
+
validationStatus: HarnessRefinerValidationStatusSchema,
|
|
56
|
+
trigger: ImmutableReleaseRefSchema,
|
|
57
|
+
outcome: ImmutableReleaseRefSchema.nullable(),
|
|
58
|
+
proposal: ImmutableReleaseRefSchema.nullable(),
|
|
59
|
+
applyReceipt: ImmutableReleaseRefSchema.nullable(),
|
|
60
|
+
inputHarness: ImmutableReleaseRefSchema,
|
|
61
|
+
outputHarness: ImmutableReleaseRefSchema.nullable(),
|
|
62
|
+
createdAt: ReleaseTimestampSchema,
|
|
63
|
+
})
|
|
64
|
+
.strict()
|
|
65
|
+
.superRefine((receipt, context) => {
|
|
66
|
+
const proposalResult = receipt.result === "applied" || receipt.result === "retained";
|
|
67
|
+
if (receipt.result === "no_action") {
|
|
68
|
+
requireFields(context, receipt, {
|
|
69
|
+
decision: "no_action",
|
|
70
|
+
route: null,
|
|
71
|
+
operation: null,
|
|
72
|
+
target: null,
|
|
73
|
+
evidenceBasis: null,
|
|
74
|
+
proposal: null,
|
|
75
|
+
applyReceipt: null,
|
|
76
|
+
outputHarness: null,
|
|
77
|
+
critiqueStatus: "not_applicable",
|
|
78
|
+
validationStatus: "not_applicable",
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
else if (receipt.result === "routed") {
|
|
82
|
+
if (receipt.decision !== "route" ||
|
|
83
|
+
!HarnessRefinerExternalRouteSchema.safeParse(receipt.route).success ||
|
|
84
|
+
receipt.operation !== null ||
|
|
85
|
+
receipt.target !== null ||
|
|
86
|
+
receipt.evidenceBasis === null ||
|
|
87
|
+
receipt.proposal !== null ||
|
|
88
|
+
receipt.applyReceipt !== null ||
|
|
89
|
+
receipt.outputHarness !== null) {
|
|
90
|
+
context.addIssue({
|
|
91
|
+
code: "custom",
|
|
92
|
+
message: "routed activity requires an external route and evidence basis without proposal state",
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
requireFields(context, receipt, {
|
|
96
|
+
critiqueStatus: "not_applicable",
|
|
97
|
+
validationStatus: "not_applicable",
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
else if (proposalResult) {
|
|
101
|
+
if (receipt.decision !== "propose" ||
|
|
102
|
+
!HarnessRefinerInternalRouteSchema.safeParse(receipt.route).success ||
|
|
103
|
+
receipt.operation === null ||
|
|
104
|
+
receipt.target === null ||
|
|
105
|
+
receipt.evidenceBasis === null ||
|
|
106
|
+
receipt.proposal === null ||
|
|
107
|
+
receipt.applyReceipt === null) {
|
|
108
|
+
context.addIssue({
|
|
109
|
+
code: "custom",
|
|
110
|
+
message: "applied and retained activity requires complete proposal state",
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
if (receipt.result === "applied" && receipt.outputHarness === null) {
|
|
114
|
+
context.addIssue({
|
|
115
|
+
code: "custom",
|
|
116
|
+
message: "applied activity requires the advanced Harness release",
|
|
117
|
+
path: ["outputHarness"],
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
if (receipt.result === "applied" &&
|
|
121
|
+
(receipt.critiqueStatus !== "passed" ||
|
|
122
|
+
receipt.validationStatus !== "passed")) {
|
|
123
|
+
context.addIssue({
|
|
124
|
+
code: "custom",
|
|
125
|
+
message: "applied activity requires passed critique and validation",
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
if (receipt.result === "retained" && receipt.outputHarness !== null) {
|
|
129
|
+
context.addIssue({
|
|
130
|
+
code: "custom",
|
|
131
|
+
message: "retained activity cannot report a new Harness release",
|
|
132
|
+
path: ["outputHarness"],
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
else if (receipt.decision !== null ||
|
|
137
|
+
receipt.route !== null ||
|
|
138
|
+
receipt.operation !== null ||
|
|
139
|
+
receipt.target !== null ||
|
|
140
|
+
receipt.evidenceBasis !== null ||
|
|
141
|
+
receipt.outcome !== null ||
|
|
142
|
+
receipt.proposal !== null ||
|
|
143
|
+
receipt.applyReceipt !== null ||
|
|
144
|
+
receipt.outputHarness !== null) {
|
|
145
|
+
context.addIssue({
|
|
146
|
+
code: "custom",
|
|
147
|
+
message: "failed activity cannot claim a decision, route, proposal, or release transition",
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
if (receipt.result !== "failed" && receipt.outcome === null) {
|
|
151
|
+
context.addIssue({
|
|
152
|
+
code: "custom",
|
|
153
|
+
message: "terminal Refiner decisions require an outcome reference",
|
|
154
|
+
path: ["outcome"],
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
export const HarnessRefinerActivityReceiptSchema = HarnessRefinerActivityReceiptContentSchema.extend({
|
|
159
|
+
contentHash: ReleaseHashSchema,
|
|
160
|
+
}).strict();
|
|
161
|
+
export const HarnessRefinementCandidateStatusSchema = z.enum([
|
|
162
|
+
"unresolved",
|
|
163
|
+
"confirmed",
|
|
164
|
+
"resolved",
|
|
165
|
+
"rejected",
|
|
166
|
+
"expired",
|
|
167
|
+
]);
|
|
168
|
+
export const HarnessRefinementCandidateResolutionSchema = z
|
|
169
|
+
.object({
|
|
170
|
+
kind: z.enum([
|
|
171
|
+
"applied_change",
|
|
172
|
+
"later_success",
|
|
173
|
+
"manual_rejection",
|
|
174
|
+
"source_revoked",
|
|
175
|
+
"expired",
|
|
176
|
+
]),
|
|
177
|
+
reason: BoundedTextSchema,
|
|
178
|
+
evidenceRefs: z.array(ImmutableReleaseRefSchema).max(1_000),
|
|
179
|
+
resolvedAt: ReleaseTimestampSchema,
|
|
180
|
+
})
|
|
181
|
+
.strict();
|
|
182
|
+
export const HarnessRefinementCandidateContentSchema = z
|
|
183
|
+
.object({
|
|
184
|
+
schemaVersion: z.literal("openpond.harnessRefinementCandidate.v1"),
|
|
185
|
+
id: ReleaseIdSchema,
|
|
186
|
+
ownerScope: HarnessReviewOwnerScopeSchema,
|
|
187
|
+
workspaceRef: ReleaseIdSchema,
|
|
188
|
+
fingerprint: ReleaseHashSchema,
|
|
189
|
+
recurrenceFamily: z.string().trim().min(1).max(1_000),
|
|
190
|
+
statement: BoundedTextSchema,
|
|
191
|
+
status: HarnessRefinementCandidateStatusSchema,
|
|
192
|
+
occurrences: z.array(HarnessReviewEvidenceRefSchema).max(1_000),
|
|
193
|
+
counterevidence: z.array(HarnessReviewEvidenceRefSchema).max(1_000),
|
|
194
|
+
sourceReviews: z.array(ImmutableReleaseRefSchema).min(1).max(100),
|
|
195
|
+
relatedHarnessReleases: z.array(ImmutableReleaseRefSchema).max(100),
|
|
196
|
+
firstSeenAt: ReleaseTimestampSchema,
|
|
197
|
+
lastSeenAt: ReleaseTimestampSchema,
|
|
198
|
+
lastReviewedAt: ReleaseTimestampSchema,
|
|
199
|
+
expiresAt: ReleaseTimestampSchema,
|
|
200
|
+
resolution: HarnessRefinementCandidateResolutionSchema.nullable(),
|
|
201
|
+
createdAt: ReleaseTimestampSchema,
|
|
202
|
+
updatedAt: ReleaseTimestampSchema,
|
|
203
|
+
})
|
|
204
|
+
.strict()
|
|
205
|
+
.superRefine((candidate, context) => {
|
|
206
|
+
requireUniqueRefs(context, candidate.occurrences, "occurrences");
|
|
207
|
+
requireUniqueRefs(context, candidate.counterevidence, "counterevidence");
|
|
208
|
+
requireUniqueRefs(context, candidate.sourceReviews, "sourceReviews");
|
|
209
|
+
requireUniqueRefs(context, candidate.relatedHarnessReleases, "relatedHarnessReleases");
|
|
210
|
+
const supportingKeys = new Set(candidate.occurrences.map((item) => item.occurrenceKey));
|
|
211
|
+
if (candidate.counterevidence.some((item) => supportingKeys.has(item.occurrenceKey))) {
|
|
212
|
+
context.addIssue({
|
|
213
|
+
code: "custom",
|
|
214
|
+
message: "supporting occurrences and counterevidence must be disjoint",
|
|
215
|
+
path: ["counterevidence"],
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
const actionable = candidate.status === "unresolved" || candidate.status === "confirmed";
|
|
219
|
+
if (actionable && candidate.occurrences.length === 0) {
|
|
220
|
+
context.addIssue({
|
|
221
|
+
code: "custom",
|
|
222
|
+
message: "actionable candidates require at least one supporting occurrence",
|
|
223
|
+
path: ["occurrences"],
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
if (actionable &&
|
|
227
|
+
[...candidate.occurrences, ...candidate.counterevidence].some((item) => item.sourcePolicy.state !== "authorized")) {
|
|
228
|
+
context.addIssue({
|
|
229
|
+
code: "custom",
|
|
230
|
+
message: "actionable candidates may contain only currently authorized evidence",
|
|
231
|
+
path: ["occurrences"],
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
if (actionable !== (candidate.resolution === null)) {
|
|
235
|
+
context.addIssue({
|
|
236
|
+
code: "custom",
|
|
237
|
+
message: "only resolved, rejected, or expired candidates require a resolution",
|
|
238
|
+
path: ["resolution"],
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
if (candidate.status === "expired" &&
|
|
242
|
+
candidate.resolution?.kind !== "expired") {
|
|
243
|
+
context.addIssue({
|
|
244
|
+
code: "custom",
|
|
245
|
+
message: "expired candidates require an expired resolution",
|
|
246
|
+
path: ["resolution", "kind"],
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
if (candidate.status === "rejected" &&
|
|
250
|
+
candidate.resolution &&
|
|
251
|
+
!["manual_rejection", "source_revoked"].includes(candidate.resolution.kind)) {
|
|
252
|
+
context.addIssue({
|
|
253
|
+
code: "custom",
|
|
254
|
+
message: "rejected candidates require a rejection or revocation resolution",
|
|
255
|
+
path: ["resolution", "kind"],
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
if (candidate.status === "resolved" &&
|
|
259
|
+
candidate.resolution &&
|
|
260
|
+
!["applied_change", "later_success"].includes(candidate.resolution.kind)) {
|
|
261
|
+
context.addIssue({
|
|
262
|
+
code: "custom",
|
|
263
|
+
message: "resolved candidates require applied-change or later-success evidence",
|
|
264
|
+
path: ["resolution", "kind"],
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
requireChronology(context, candidate);
|
|
268
|
+
});
|
|
269
|
+
export const HarnessRefinementCandidateSchema = HarnessRefinementCandidateContentSchema.extend({
|
|
270
|
+
contentHash: ReleaseHashSchema,
|
|
271
|
+
}).strict();
|
|
272
|
+
export const HarnessRefinementCandidateLifecycleDecisionSchema = z.enum([
|
|
273
|
+
"created",
|
|
274
|
+
"merged",
|
|
275
|
+
"rejected",
|
|
276
|
+
"expired",
|
|
277
|
+
"reopened",
|
|
278
|
+
"resolved",
|
|
279
|
+
]);
|
|
280
|
+
export const HarnessRefinementCandidateLifecycleReceiptContentSchema = z
|
|
281
|
+
.object({
|
|
282
|
+
schemaVersion: z.literal("openpond.harnessRefinementCandidateLifecycleReceipt.v1"),
|
|
283
|
+
id: ReleaseIdSchema,
|
|
284
|
+
candidateId: ReleaseIdSchema,
|
|
285
|
+
decision: HarnessRefinementCandidateLifecycleDecisionSchema,
|
|
286
|
+
beforeCandidate: ImmutableReleaseRefSchema.nullable(),
|
|
287
|
+
afterCandidate: ImmutableReleaseRefSchema,
|
|
288
|
+
review: ImmutableReleaseRefSchema,
|
|
289
|
+
addedEvidence: z.array(HarnessReviewEvidenceRefSchema).max(1_000),
|
|
290
|
+
removedEvidence: z.array(ImmutableReleaseRefSchema).max(1_000),
|
|
291
|
+
reason: BoundedTextSchema,
|
|
292
|
+
createdAt: ReleaseTimestampSchema,
|
|
293
|
+
})
|
|
294
|
+
.strict()
|
|
295
|
+
.superRefine((receipt, context) => {
|
|
296
|
+
if ((receipt.decision === "created") !== (receipt.beforeCandidate === null)) {
|
|
297
|
+
context.addIssue({
|
|
298
|
+
code: "custom",
|
|
299
|
+
message: "only candidate creation omits the previous candidate reference",
|
|
300
|
+
path: ["beforeCandidate"],
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
if (receipt.beforeCandidate &&
|
|
304
|
+
receipt.beforeCandidate.contentHash === receipt.afterCandidate.contentHash) {
|
|
305
|
+
context.addIssue({
|
|
306
|
+
code: "custom",
|
|
307
|
+
message: "candidate lifecycle transitions must change candidate content",
|
|
308
|
+
path: ["afterCandidate"],
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
if (["created", "reopened"].includes(receipt.decision) &&
|
|
312
|
+
receipt.addedEvidence.length === 0) {
|
|
313
|
+
context.addIssue({
|
|
314
|
+
code: "custom",
|
|
315
|
+
message: `${receipt.decision} candidate transitions require added evidence`,
|
|
316
|
+
path: ["addedEvidence"],
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
if (receipt.addedEvidence.some((item) => item.sourcePolicy.state !== "authorized")) {
|
|
320
|
+
context.addIssue({
|
|
321
|
+
code: "custom",
|
|
322
|
+
message: "candidate transitions may add only authorized evidence",
|
|
323
|
+
path: ["addedEvidence"],
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
requireUniqueRefs(context, receipt.addedEvidence, "addedEvidence");
|
|
327
|
+
requireUniqueRefs(context, receipt.removedEvidence, "removedEvidence");
|
|
328
|
+
const removedKeys = new Set(receipt.removedEvidence.map((item) => refKey(item)));
|
|
329
|
+
if (receipt.addedEvidence.some((item) => removedKeys.has(refKey(item.evidence)))) {
|
|
330
|
+
context.addIssue({
|
|
331
|
+
code: "custom",
|
|
332
|
+
message: "candidate lifecycle evidence cannot be added and removed together",
|
|
333
|
+
path: ["removedEvidence"],
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
export const HarnessRefinementCandidateLifecycleReceiptSchema = HarnessRefinementCandidateLifecycleReceiptContentSchema.extend({
|
|
338
|
+
contentHash: ReleaseHashSchema,
|
|
339
|
+
}).strict();
|
|
340
|
+
export const HarnessCrossRunRefinementRequestContentSchema = z
|
|
341
|
+
.object({
|
|
342
|
+
schemaVersion: z.literal("openpond.harnessCrossRunRefinementRequest.v1"),
|
|
343
|
+
id: ReleaseIdSchema,
|
|
344
|
+
ownerScope: HarnessReviewOwnerScopeSchema,
|
|
345
|
+
workspaceRef: ReleaseIdSchema,
|
|
346
|
+
candidate: ImmutableReleaseRefSchema,
|
|
347
|
+
candidateFingerprint: ReleaseHashSchema,
|
|
348
|
+
review: ImmutableReleaseRefSchema,
|
|
349
|
+
admittedHarness: ImmutableReleaseRefSchema,
|
|
350
|
+
evidence: z.array(HarnessReviewEvidenceRefSchema).min(1).max(1_000),
|
|
351
|
+
capabilities: HarnessRefinerCapabilitiesSchema,
|
|
352
|
+
deduplicationKey: ReleaseHashSchema,
|
|
353
|
+
createdAt: ReleaseTimestampSchema,
|
|
354
|
+
})
|
|
355
|
+
.strict()
|
|
356
|
+
.superRefine((request, context) => {
|
|
357
|
+
if (request.evidence.some((item) => item.sourcePolicy.state !== "authorized")) {
|
|
358
|
+
context.addIssue({
|
|
359
|
+
code: "custom",
|
|
360
|
+
message: "cross-run refinement requires currently authorized evidence",
|
|
361
|
+
path: ["evidence"],
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
requireUniqueRefs(context, request.evidence, "evidence");
|
|
365
|
+
if (!Object.values(request.capabilities).some(Boolean)) {
|
|
366
|
+
context.addIssue({
|
|
367
|
+
code: "custom",
|
|
368
|
+
message: "cross-run refinement requires at least one available Harness capability",
|
|
369
|
+
path: ["capabilities"],
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
const expected = harnessCrossRunRefinementDeduplicationKey(request);
|
|
373
|
+
if (request.deduplicationKey !== expected) {
|
|
374
|
+
context.addIssue({
|
|
375
|
+
code: "custom",
|
|
376
|
+
message: `cross-run refinement deduplicationKey is ${request.deduplicationKey}; expected ${expected}`,
|
|
377
|
+
path: ["deduplicationKey"],
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
export const HarnessCrossRunRefinementRequestSchema = HarnessCrossRunRefinementRequestContentSchema.extend({
|
|
382
|
+
contentHash: ReleaseHashSchema,
|
|
383
|
+
}).strict();
|
|
384
|
+
export function createHarnessRefinerActivityReceipt(input) {
|
|
385
|
+
return createHashedContract(input, HarnessRefinerActivityReceiptContentSchema, HarnessRefinerActivityReceiptSchema);
|
|
386
|
+
}
|
|
387
|
+
export function verifyHarnessRefinerActivityReceipt(value) {
|
|
388
|
+
return verifyHashedContract(value, HarnessRefinerActivityReceiptContentSchema, HarnessRefinerActivityReceiptSchema);
|
|
389
|
+
}
|
|
390
|
+
export function createHarnessRefinementCandidate(input) {
|
|
391
|
+
return createHashedContract(input, HarnessRefinementCandidateContentSchema, HarnessRefinementCandidateSchema);
|
|
392
|
+
}
|
|
393
|
+
export function verifyHarnessRefinementCandidate(value) {
|
|
394
|
+
return verifyHashedContract(value, HarnessRefinementCandidateContentSchema, HarnessRefinementCandidateSchema);
|
|
395
|
+
}
|
|
396
|
+
export function createHarnessRefinementCandidateLifecycleReceipt(input) {
|
|
397
|
+
return createHashedContract(input, HarnessRefinementCandidateLifecycleReceiptContentSchema, HarnessRefinementCandidateLifecycleReceiptSchema);
|
|
398
|
+
}
|
|
399
|
+
export function verifyHarnessRefinementCandidateLifecycleReceipt(value) {
|
|
400
|
+
return verifyHashedContract(value, HarnessRefinementCandidateLifecycleReceiptContentSchema, HarnessRefinementCandidateLifecycleReceiptSchema);
|
|
401
|
+
}
|
|
402
|
+
export function harnessCrossRunRefinementDeduplicationKey(input) {
|
|
403
|
+
return contentHash({
|
|
404
|
+
schemaVersion: "openpond.harnessCrossRunRefinementIdentity.v1",
|
|
405
|
+
workspaceRef: input.workspaceRef,
|
|
406
|
+
candidateFingerprint: input.candidateFingerprint,
|
|
407
|
+
admittedHarness: input.admittedHarness,
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
export function createHarnessCrossRunRefinementRequest(input) {
|
|
411
|
+
return createHashedContract(input, HarnessCrossRunRefinementRequestContentSchema, HarnessCrossRunRefinementRequestSchema);
|
|
412
|
+
}
|
|
413
|
+
export function verifyHarnessCrossRunRefinementRequest(value) {
|
|
414
|
+
return verifyHashedContract(value, HarnessCrossRunRefinementRequestContentSchema, HarnessCrossRunRefinementRequestSchema);
|
|
415
|
+
}
|
|
416
|
+
function createHashedContract(input, contentSchema, resultSchema) {
|
|
417
|
+
const content = contentSchema.parse(input);
|
|
418
|
+
return resultSchema.parse({
|
|
419
|
+
...content,
|
|
420
|
+
contentHash: contentHash(content),
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
function verifyHashedContract(value, contentSchema, resultSchema) {
|
|
424
|
+
const parsed = resultSchema.safeParse(value);
|
|
425
|
+
if (!parsed.success)
|
|
426
|
+
return false;
|
|
427
|
+
const { contentHash: actual, ...content } = parsed.data;
|
|
428
|
+
return contentHash(contentSchema.parse(content)) === actual;
|
|
429
|
+
}
|
|
430
|
+
function requireFields(context, value, expected) {
|
|
431
|
+
for (const [key, expectedValue] of Object.entries(expected)) {
|
|
432
|
+
if (value[key] === expectedValue)
|
|
433
|
+
continue;
|
|
434
|
+
context.addIssue({
|
|
435
|
+
code: "custom",
|
|
436
|
+
message: `${key} must be ${String(expectedValue)}`,
|
|
437
|
+
path: [key],
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
function requireUniqueRefs(context, values, path) {
|
|
442
|
+
const keys = values.map((value) => refKey(value));
|
|
443
|
+
if (new Set(keys).size === keys.length)
|
|
444
|
+
return;
|
|
445
|
+
context.addIssue({
|
|
446
|
+
code: "custom",
|
|
447
|
+
message: `${path} references must be unique`,
|
|
448
|
+
path: [path],
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
function refKey(value) {
|
|
452
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
453
|
+
return String(value);
|
|
454
|
+
const record = value;
|
|
455
|
+
if (typeof record.occurrenceKey === "string")
|
|
456
|
+
return record.occurrenceKey;
|
|
457
|
+
const nested = record.evidence;
|
|
458
|
+
if (nested && typeof nested === "object" && !Array.isArray(nested)) {
|
|
459
|
+
const evidence = nested;
|
|
460
|
+
return `${String(evidence.id)}:${String(evidence.contentHash)}`;
|
|
461
|
+
}
|
|
462
|
+
return `${String(record.id)}:${String(record.contentHash)}`;
|
|
463
|
+
}
|
|
464
|
+
function requireChronology(context, candidate) {
|
|
465
|
+
const chronology = [
|
|
466
|
+
["firstSeenAt", candidate.firstSeenAt],
|
|
467
|
+
["lastSeenAt", candidate.lastSeenAt],
|
|
468
|
+
["lastReviewedAt", candidate.lastReviewedAt],
|
|
469
|
+
["updatedAt", candidate.updatedAt],
|
|
470
|
+
["expiresAt", candidate.expiresAt],
|
|
471
|
+
];
|
|
472
|
+
for (let index = 1; index < chronology.length; index += 1) {
|
|
473
|
+
const previous = chronology[index - 1];
|
|
474
|
+
const current = chronology[index];
|
|
475
|
+
if (Date.parse(previous[1]) <= Date.parse(current[1]))
|
|
476
|
+
continue;
|
|
477
|
+
context.addIssue({
|
|
478
|
+
code: "custom",
|
|
479
|
+
message: `${current[0]} must not precede ${previous[0]}`,
|
|
480
|
+
path: [current[0]],
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
if (Date.parse(candidate.createdAt) > Date.parse(candidate.updatedAt)) {
|
|
484
|
+
context.addIssue({
|
|
485
|
+
code: "custom",
|
|
486
|
+
message: "updatedAt must not precede createdAt",
|
|
487
|
+
path: ["updatedAt"],
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
}
|
|
@@ -400,9 +400,6 @@ function classifyToolFailure(event) {
|
|
|
400
400
|
const result = asRecord(data.result);
|
|
401
401
|
if (result.timedOut === true)
|
|
402
402
|
return "timeout";
|
|
403
|
-
if (typeof result.exitCode === "number" && result.exitCode !== 0) {
|
|
404
|
-
return "command_exit_nonzero";
|
|
405
|
-
}
|
|
406
403
|
const structuredStatus = String(data.status ?? result.status ?? "").toLowerCase();
|
|
407
404
|
if (["timed_out", "timeout"].includes(structuredStatus))
|
|
408
405
|
return "timeout";
|
|
@@ -413,6 +410,14 @@ function classifyToolFailure(event) {
|
|
|
413
410
|
result.stderr,
|
|
414
411
|
result.stdout,
|
|
415
412
|
].filter((value) => typeof value === "string").join("\n").toLowerCase();
|
|
413
|
+
if (text.includes("unicodeencodeerror")
|
|
414
|
+
|| text.includes("unicodedecodeerror")
|
|
415
|
+
|| text.includes("invalid utf-8")
|
|
416
|
+
|| text.includes("invalid utf8")
|
|
417
|
+
|| /codec can't (?:en|de)code/.test(text)
|
|
418
|
+
|| /can't encode character/.test(text)) {
|
|
419
|
+
return "text_encoding_incompatible";
|
|
420
|
+
}
|
|
416
421
|
if (text.includes("modulenotfounderror") ||
|
|
417
422
|
text.includes("module_not_found") ||
|
|
418
423
|
text.includes("cannot find module") ||
|
|
@@ -438,6 +443,9 @@ function classifyToolFailure(event) {
|
|
|
438
443
|
if (text.includes("exit code") || text.includes("non-zero") || text.includes("nonzero")) {
|
|
439
444
|
return "command_exit_nonzero";
|
|
440
445
|
}
|
|
446
|
+
if (typeof result.exitCode === "number" && result.exitCode !== 0) {
|
|
447
|
+
return "command_exit_nonzero";
|
|
448
|
+
}
|
|
441
449
|
return "unclassified_tool_failure";
|
|
442
450
|
}
|
|
443
451
|
function recoveredClass(deterministicClass) {
|