@tangle-network/agent-runtime 0.90.1 → 0.92.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 (86) hide show
  1. package/README.md +4 -2
  2. package/dist/agent.d.ts +3 -3
  3. package/dist/agent.js +88 -9
  4. package/dist/agent.js.map +1 -1
  5. package/dist/{mcp-serve-verifier-XsX8rkB9.d.ts → agentic-generator-B8oeE2Yv.d.ts} +6 -33
  6. package/dist/analyst-loop.d.ts +1 -1
  7. package/dist/candidate-execution/index.d.ts +104 -0
  8. package/dist/candidate-execution/index.js +34 -0
  9. package/dist/candidate-execution/index.js.map +1 -0
  10. package/dist/chunk-3BE7KTMU.js +1229 -0
  11. package/dist/chunk-3BE7KTMU.js.map +1 -0
  12. package/dist/chunk-3D2RHC4K.js +73 -0
  13. package/dist/chunk-3D2RHC4K.js.map +1 -0
  14. package/dist/chunk-3MDZX7YU.js +125 -0
  15. package/dist/chunk-3MDZX7YU.js.map +1 -0
  16. package/dist/{chunk-RYBVU4M3.js → chunk-6O5USWVH.js} +32 -1413
  17. package/dist/chunk-6O5USWVH.js.map +1 -0
  18. package/dist/chunk-6O73TRHW.js +142 -0
  19. package/dist/chunk-6O73TRHW.js.map +1 -0
  20. package/dist/{chunk-R2VAJGR3.js → chunk-7VJJJ2T2.js} +2 -2
  21. package/dist/chunk-A62TP7SK.js +4784 -0
  22. package/dist/chunk-A62TP7SK.js.map +1 -0
  23. package/dist/chunk-APVPRF4Y.js +2166 -0
  24. package/dist/chunk-APVPRF4Y.js.map +1 -0
  25. package/dist/{chunk-QK4DV5PR.js → chunk-AUEIDTR3.js} +2 -2
  26. package/dist/{chunk-OOL3675H.js → chunk-FRBHUNQ7.js} +2 -139
  27. package/dist/chunk-FRBHUNQ7.js.map +1 -0
  28. package/dist/{chunk-7ON74BQO.js → chunk-GDAQUFG6.js} +2 -2
  29. package/dist/{chunk-ZV4LXYCJ.js → chunk-I7WVPJBZ.js} +23 -1231
  30. package/dist/chunk-I7WVPJBZ.js.map +1 -0
  31. package/dist/{chunk-WRUSWK4F.js → chunk-IGGZGKJD.js} +3 -3
  32. package/dist/chunk-PH65PR4F.js +860 -0
  33. package/dist/chunk-PH65PR4F.js.map +1 -0
  34. package/dist/chunk-RSWM2ZKM.js +659 -0
  35. package/dist/chunk-RSWM2ZKM.js.map +1 -0
  36. package/dist/{chunk-BZF3KQ6G.js → chunk-VSWBYWFK.js} +4 -122
  37. package/dist/chunk-VSWBYWFK.js.map +1 -0
  38. package/dist/{completion-gate-DkAnUmpb.d.ts → completion-gate-BLaiN0-X.d.ts} +1 -1
  39. package/dist/{coordination-rRj5hjJK.d.ts → coordination-DxJ83oZA.d.ts} +12 -5
  40. package/dist/environment-provider.d.ts +2 -2
  41. package/dist/environment-provider.js +2 -1
  42. package/dist/improve-CUVCq7xg.d.ts +152 -0
  43. package/dist/{improvement-adapter-CDR8QNVM.d.ts → improvement-adapter-BieWeK5J.d.ts} +16 -0
  44. package/dist/index.d.ts +27 -291
  45. package/dist/index.js +70 -889
  46. package/dist/index.js.map +1 -1
  47. package/dist/intelligence.d.ts +160 -13
  48. package/dist/intelligence.js +535 -59
  49. package/dist/intelligence.js.map +1 -1
  50. package/dist/knowledge.d.ts +6 -6
  51. package/dist/knowledge.js +6 -4
  52. package/dist/lifecycle.d.ts +2 -1
  53. package/dist/lifecycle.js +5 -3
  54. package/dist/lifecycle.js.map +1 -1
  55. package/dist/{loop-runner-bin-DTbZVGfM.d.ts → loop-runner-bin-kKUNGLyV.d.ts} +2 -2
  56. package/dist/loop-runner-bin.d.ts +5 -5
  57. package/dist/loop-runner-bin.js +8 -5
  58. package/dist/loops.d.ts +16 -16
  59. package/dist/loops.js +47 -41
  60. package/dist/mcp/bin.js +6 -4
  61. package/dist/mcp/bin.js.map +1 -1
  62. package/dist/mcp/index.d.ts +8 -8
  63. package/dist/mcp/index.js +9 -6
  64. package/dist/mcp/index.js.map +1 -1
  65. package/dist/mcp-serve-verifier-Bg4C3p5S.d.ts +34 -0
  66. package/dist/{openai-tools-C4ZfUD4L.d.ts → openai-tools-E3woykz9.d.ts} +1 -1
  67. package/dist/prepare-Z08a4heC.d.ts +713 -0
  68. package/dist/profiles.d.ts +1 -1
  69. package/dist/{router-client-DJImUDlm.d.ts → sanitize-C9go6tXj.d.ts} +113 -1
  70. package/dist/{structural-rollout-MwlpgQ-6.d.ts → structural-rollout-DHGDbhvR.d.ts} +3 -3
  71. package/dist/{supervise-DPmYPk0j.d.ts → supervise-T2pazU3G.d.ts} +4 -4
  72. package/dist/{types-SyuwunY_.d.ts → types-B00NtbCs.d.ts} +1 -1
  73. package/dist/{types-eMNgWgFi.d.ts → types-DAdIm4AC.d.ts} +1 -1
  74. package/dist/{worktree-fanout-BDFQIO-Y.d.ts → worktree-fanout-BUb2Ag02.d.ts} +3 -3
  75. package/package.json +26 -36
  76. package/skills/build-with-agent-runtime/SKILL.md +1 -1
  77. package/dist/chunk-BZF3KQ6G.js.map +0 -1
  78. package/dist/chunk-IVGYLCFH.js +0 -381
  79. package/dist/chunk-IVGYLCFH.js.map +0 -1
  80. package/dist/chunk-OOL3675H.js.map +0 -1
  81. package/dist/chunk-RYBVU4M3.js.map +0 -1
  82. package/dist/chunk-ZV4LXYCJ.js.map +0 -1
  83. /package/dist/{chunk-R2VAJGR3.js.map → chunk-7VJJJ2T2.js.map} +0 -0
  84. /package/dist/{chunk-QK4DV5PR.js.map → chunk-AUEIDTR3.js.map} +0 -0
  85. /package/dist/{chunk-7ON74BQO.js.map → chunk-GDAQUFG6.js.map} +0 -0
  86. /package/dist/{chunk-WRUSWK4F.js.map → chunk-IGGZGKJD.js.map} +0 -0
@@ -0,0 +1,4784 @@
1
+ import {
2
+ contentAddress
3
+ } from "./chunk-3D2RHC4K.js";
4
+
5
+ // src/candidate-execution/types.ts
6
+ var verifiedCandidateBrand = /* @__PURE__ */ Symbol("verifiedAgentCandidate");
7
+ var preparedCandidateBrand = /* @__PURE__ */ Symbol("preparedAgentCandidate");
8
+ var verifiedTaskOutcomeBrand = /* @__PURE__ */ Symbol("verifiedTaskOutcome");
9
+ var CANDIDATE_TRACE_TAGS = {
10
+ executionId: "tangle.candidate.execution_id",
11
+ bundleDigest: "tangle.candidate.bundle_digest",
12
+ executionPlanDigest: "tangle.candidate.execution_plan_digest",
13
+ materializationReceiptDigest: "tangle.candidate.materialization_receipt_digest"
14
+ };
15
+ var CANDIDATE_TRACE_ENV = {
16
+ executionId: "TANGLE_CANDIDATE_EXECUTION_ID",
17
+ bundleDigest: "TANGLE_CANDIDATE_BUNDLE_DIGEST",
18
+ executionPlanDigest: "TANGLE_CANDIDATE_EXECUTION_PLAN_DIGEST",
19
+ materializationReceiptDigest: "TANGLE_CANDIDATE_MATERIALIZATION_RECEIPT_DIGEST",
20
+ traceRunId: "TANGLE_TRACE_RUN_ID"
21
+ };
22
+
23
+ // src/candidate-execution/claim.ts
24
+ import { createHash as createHash2, randomBytes, timingSafeEqual } from "crypto";
25
+ import { readFile } from "fs/promises";
26
+ import {
27
+ agentCandidateResolvedModelSchema
28
+ } from "@tangle-network/agent-interface";
29
+
30
+ // src/candidate-execution/claim-file-formats.ts
31
+ var CLAIM_FORMAT_VERSION = 7;
32
+ var PENDING_FORMAT_VERSION = 1;
33
+ var TERMINAL_FORMAT_VERSION = 3;
34
+ var PHASE_FORMAT_VERSION = 1;
35
+
36
+ // src/candidate-execution/claim-terminal.ts
37
+ import { agentCandidateArtifactRefSchema } from "@tangle-network/agent-interface";
38
+
39
+ // src/candidate-execution/digest.ts
40
+ import { createHash } from "crypto";
41
+ import { canonicalJson } from "@tangle-network/agent-eval";
42
+ function sha256Bytes(bytes) {
43
+ return `sha256:${createHash("sha256").update(bytes).digest("hex")}`;
44
+ }
45
+ function canonicalCandidateBytes(value) {
46
+ return Buffer.from(canonicalJson(value), "utf8");
47
+ }
48
+ function canonicalCandidateDigest(value) {
49
+ return contentAddress(value);
50
+ }
51
+ function immutableCandidateValue(value) {
52
+ return deepFreezeCandidate(
53
+ JSON.parse(Buffer.from(canonicalCandidateBytes(value)).toString("utf8"))
54
+ );
55
+ }
56
+ function canonicalCandidateDocument(valueWithoutDigest) {
57
+ const bytes = canonicalCandidateBytes(valueWithoutDigest);
58
+ const digest = canonicalCandidateDigest(valueWithoutDigest);
59
+ if (sha256Bytes(bytes) !== digest) {
60
+ throw new Error("canonical candidate serializers disagree on document digest");
61
+ }
62
+ const storedBytes = Uint8Array.from(bytes);
63
+ const value = immutableCandidateValue({ ...valueWithoutDigest, digest });
64
+ return Object.freeze({
65
+ value,
66
+ get bytes() {
67
+ return Uint8Array.from(storedBytes);
68
+ },
69
+ digest
70
+ });
71
+ }
72
+ function embeddedCandidateArtifact(bytes) {
73
+ return {
74
+ encoding: "base64",
75
+ content: Buffer.from(bytes).toString("base64"),
76
+ sha256: sha256Bytes(bytes),
77
+ byteLength: bytes.byteLength
78
+ };
79
+ }
80
+ function omitTopLevelDigest(value) {
81
+ const { digest: _digest, ...rest } = value;
82
+ return rest;
83
+ }
84
+ function deepFreezeCandidate(value, seen = /* @__PURE__ */ new Set()) {
85
+ if (value === null || typeof value !== "object" || ArrayBuffer.isView(value) || seen.has(value)) {
86
+ return value;
87
+ }
88
+ seen.add(value);
89
+ for (const child of Object.values(value)) {
90
+ deepFreezeCandidate(child, seen);
91
+ }
92
+ return Object.freeze(value);
93
+ }
94
+
95
+ // src/candidate-execution/exact-object.ts
96
+ function assertExactObjectKeys(value, required, label, optional = []) {
97
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
98
+ throw new Error(`${label} must be an object`);
99
+ }
100
+ const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
101
+ if (allowed.size !== required.length + optional.length) {
102
+ throw new Error(`${label} exact-key contract contains duplicate fields`);
103
+ }
104
+ for (const key of Object.keys(value)) {
105
+ if (!allowed.has(key)) throw new Error(`${label} contains unknown field ${key}`);
106
+ }
107
+ for (const key of required) {
108
+ if (!(key in value)) throw new Error(`${label} is missing field ${key}`);
109
+ }
110
+ }
111
+
112
+ // src/candidate-execution/claim-terminal.ts
113
+ var SHA256_PATTERN = /^sha256:[a-f0-9]{64}$/;
114
+ function terminalRecord(claim, result) {
115
+ const terminal = sealTerminalResult(result);
116
+ const value = {
117
+ executionId: claim.executionId,
118
+ attempt: claim.attempt,
119
+ bundleDigest: claim.bundleDigest,
120
+ executionPlanDigest: claim.executionPlanDigest,
121
+ ...terminal
122
+ };
123
+ return immutableCandidateValue({
124
+ ...value,
125
+ terminalDigest: canonicalCandidateDigest(value)
126
+ });
127
+ }
128
+ function recoveredTerminalRecord(claim, phase, evidence) {
129
+ const recovered = sealRecoveryEvidence(evidence, claim);
130
+ return terminalRecord(claim, {
131
+ schemaVersion: 1,
132
+ status: "failed",
133
+ failureClass: recovered.failureClass === "pre-model-infrastructure" && phase !== "claimed" ? "unknown" : recovered.failureClass,
134
+ usage: recovered.usage,
135
+ modelSettlement: recovered.modelSettlement,
136
+ ...recovered.failureEvidence ? { failureEvidence: recovered.failureEvidence } : {}
137
+ });
138
+ }
139
+ function assertTerminalAllowedInPhase(phase, terminal) {
140
+ if (phase === "candidate-may-run" && terminal.status === "failed" && terminal.failureClass === "pre-model-infrastructure") {
141
+ throw new Error("candidate execution crossed candidate-may-run before pre-model failure");
142
+ }
143
+ if (phase === "claimed" && (terminal.status === "succeeded" || terminal.status === "failed" && (terminal.failureClass === "execution" || terminal.failureClass === "post-model-infrastructure"))) {
144
+ throw new Error("candidate execution terminal requires candidate-may-run phase");
145
+ }
146
+ }
147
+ function rejectedFinish(existing, requestedTerminalDigest) {
148
+ return Object.freeze({
149
+ finished: false,
150
+ terminal: existing,
151
+ exactReplay: existing.terminalDigest === requestedTerminalDigest
152
+ });
153
+ }
154
+ function rejectedStage(existing, requested) {
155
+ return Object.freeze({
156
+ staged: false,
157
+ terminal: existing,
158
+ exactReplay: existing.terminalDigest === requested.terminalDigest
159
+ });
160
+ }
161
+ function requireStagedTerminal(staged, terminalDigest) {
162
+ if (!staged) throw new Error("candidate execution terminal has not been staged");
163
+ if (staged.terminalDigest !== terminalDigest) {
164
+ throw new Error("candidate execution terminal digest does not match staged outbox");
165
+ }
166
+ return staged;
167
+ }
168
+ function sealTerminalDigest(value) {
169
+ assertSha256Digest(value, "terminalDigest");
170
+ return value;
171
+ }
172
+ function assertRecoveryMatchesStaged(staged, recovered) {
173
+ if (canonicalCandidateDigest(staged.usage) !== canonicalCandidateDigest(recovered.usage) || canonicalCandidateDigest(staged.modelSettlement) !== canonicalCandidateDigest(recovered.modelSettlement)) {
174
+ throw new Error("candidate execution recovery evidence does not match staged model evidence");
175
+ }
176
+ }
177
+ function sealTerminalRecordValue(value, label) {
178
+ const status = requireTerminalStatus(value.status, label);
179
+ assertExactObjectKeys(
180
+ value,
181
+ status === "succeeded" ? [
182
+ "executionId",
183
+ "attempt",
184
+ "bundleDigest",
185
+ "executionPlanDigest",
186
+ "terminalDigest",
187
+ "schemaVersion",
188
+ "status",
189
+ "usage",
190
+ "modelSettlement",
191
+ "taskOutcome",
192
+ "benchmarkResult",
193
+ "runReceipt"
194
+ ] : [
195
+ "executionId",
196
+ "attempt",
197
+ "bundleDigest",
198
+ "executionPlanDigest",
199
+ "terminalDigest",
200
+ "schemaVersion",
201
+ "status",
202
+ "failureClass",
203
+ "usage",
204
+ "modelSettlement",
205
+ ...value.failureEvidence ? ["failureEvidence"] : []
206
+ ],
207
+ label
208
+ );
209
+ const identity = {
210
+ executionId: requireString(value.executionId, label, "executionId"),
211
+ attempt: requireNumber(value.attempt, label, "attempt"),
212
+ bundleDigest: requireString(value.bundleDigest, label, "bundleDigest"),
213
+ executionPlanDigest: requireString(
214
+ value.executionPlanDigest,
215
+ label,
216
+ "executionPlanDigest"
217
+ )
218
+ };
219
+ assertExecutionId(identity.executionId);
220
+ if (!Number.isSafeInteger(identity.attempt) || identity.attempt < 1) {
221
+ throw new Error(`${label} has invalid attempt`);
222
+ }
223
+ assertSha256Digest(identity.bundleDigest, "bundleDigest");
224
+ assertSha256Digest(identity.executionPlanDigest, "executionPlanDigest");
225
+ const result = sealTerminalResult(
226
+ status === "succeeded" ? {
227
+ schemaVersion: requireNumber(value.schemaVersion, label, "schemaVersion"),
228
+ status,
229
+ usage: requireObject(
230
+ value.usage,
231
+ label,
232
+ "usage"
233
+ ),
234
+ modelSettlement: requireArtifactRef(value.modelSettlement, label, "modelSettlement"),
235
+ taskOutcome: requireArtifactRef(value.taskOutcome, label, "taskOutcome"),
236
+ benchmarkResult: requireArtifactRef(value.benchmarkResult, label, "benchmarkResult"),
237
+ runReceipt: requireArtifactRef(value.runReceipt, label, "runReceipt")
238
+ } : {
239
+ schemaVersion: requireNumber(value.schemaVersion, label, "schemaVersion"),
240
+ status,
241
+ failureClass: requireFailureClass(value.failureClass, label),
242
+ usage: requireObject(
243
+ value.usage,
244
+ label,
245
+ "usage"
246
+ ),
247
+ modelSettlement: requireArtifactRef(value.modelSettlement, label, "modelSettlement"),
248
+ ...value.failureEvidence ? {
249
+ failureEvidence: requireArtifactRef(
250
+ value.failureEvidence,
251
+ label,
252
+ "failureEvidence"
253
+ )
254
+ } : {}
255
+ }
256
+ );
257
+ const material = { ...identity, ...result };
258
+ const terminalDigest = requireString(
259
+ value.terminalDigest,
260
+ label,
261
+ "terminalDigest"
262
+ );
263
+ assertSha256Digest(terminalDigest, "terminalDigest");
264
+ if (terminalDigest !== canonicalCandidateDigest(material)) {
265
+ throw new Error(`${label} has invalid terminalDigest`);
266
+ }
267
+ return immutableCandidateValue({
268
+ ...material,
269
+ terminalDigest
270
+ });
271
+ }
272
+ function assertTerminalMatchesClaim(terminal, claim, path) {
273
+ if (terminal.executionId !== claim.executionId || terminal.attempt !== claim.attempt || terminal.bundleDigest !== claim.bundleDigest || terminal.executionPlanDigest !== claim.executionPlanDigest) {
274
+ throw new Error(`candidate execution terminal record at ${path} does not match its claim`);
275
+ }
276
+ }
277
+ function assertTerminalMatchesStaged(terminal, staged, path) {
278
+ if (terminal.terminalDigest !== staged.terminalDigest || canonicalCandidateDigest(terminal) !== canonicalCandidateDigest(staged)) {
279
+ throw new Error(`candidate execution terminal record at ${path} differs from staged outbox`);
280
+ }
281
+ }
282
+ function sealRecoveryEvidence(evidence, claim) {
283
+ assertExactObjectKeys(
284
+ evidence,
285
+ [
286
+ "failureClass",
287
+ "usage",
288
+ "modelSettlement",
289
+ "process",
290
+ "model",
291
+ ...evidence.failureEvidence ? ["failureEvidence"] : [],
292
+ ...evidence.memory ? ["memory"] : []
293
+ ],
294
+ "candidate execution recovery evidence"
295
+ );
296
+ assertFailureClass(evidence.failureClass);
297
+ const usage = sealUsage(evidence.usage);
298
+ if (evidence.failureClass === "pre-model-infrastructure" && usage.modelCalls !== 0) {
299
+ throw new Error("pre-model infrastructure failure cannot contain model calls");
300
+ }
301
+ const modelSettlement = sealArtifactRef(evidence.modelSettlement, "modelSettlement");
302
+ const failureEvidence = evidence.failureEvidence ? sealArtifactRef(evidence.failureEvidence, "failureEvidence") : void 0;
303
+ assertExactObjectKeys(
304
+ evidence.process,
305
+ ["stopped", "executionPlanDigest"],
306
+ "candidate execution process closure evidence"
307
+ );
308
+ if (evidence.process.stopped !== true || evidence.process.executionPlanDigest !== claim.executionPlanDigest) {
309
+ throw new Error("candidate execution recovery does not prove the claimed process stopped");
310
+ }
311
+ assertExactObjectKeys(
312
+ evidence.model,
313
+ ["closed", "preparationId", "grantDigest"],
314
+ "candidate execution model closure evidence"
315
+ );
316
+ if (evidence.model.closed !== true || evidence.model.preparationId !== claim.cleanup.preparationId || evidence.model.grantDigest !== claim.cleanup.modelGrantDigest) {
317
+ throw new Error("candidate execution recovery does not prove the claimed model grant closed");
318
+ }
319
+ if (claim.cleanup.memory) {
320
+ if (!evidence.memory) {
321
+ throw new Error("candidate execution recovery is missing memory closure evidence");
322
+ }
323
+ assertExactObjectKeys(
324
+ evidence.memory,
325
+ ["closed", "preparationId", "accessDigest", "effectiveNamespace"],
326
+ "candidate execution memory closure evidence"
327
+ );
328
+ if (evidence.memory.closed !== true || evidence.memory.preparationId !== claim.cleanup.preparationId || evidence.memory.accessDigest !== claim.cleanup.memory.accessDigest || evidence.memory.effectiveNamespace !== claim.cleanup.memory.effectiveNamespace) {
329
+ throw new Error(
330
+ "candidate execution recovery does not prove the claimed memory access closed"
331
+ );
332
+ }
333
+ } else if (evidence.memory !== void 0) {
334
+ throw new Error("candidate execution recovery has unexpected memory closure evidence");
335
+ }
336
+ return Object.freeze({
337
+ failureClass: evidence.failureClass,
338
+ usage,
339
+ modelSettlement,
340
+ ...failureEvidence ? { failureEvidence } : {},
341
+ process: Object.freeze({ ...evidence.process }),
342
+ model: Object.freeze({ ...evidence.model }),
343
+ ...evidence.memory ? { memory: Object.freeze({ ...evidence.memory }) } : {}
344
+ });
345
+ }
346
+ function sealTerminalResult(result) {
347
+ if (result.status !== "succeeded" && result.status !== "failed") {
348
+ throw new Error("candidate execution terminal status is invalid");
349
+ }
350
+ assertExactObjectKeys(
351
+ result,
352
+ result.status === "succeeded" ? [
353
+ "schemaVersion",
354
+ "status",
355
+ "usage",
356
+ "modelSettlement",
357
+ "taskOutcome",
358
+ "benchmarkResult",
359
+ "runReceipt"
360
+ ] : [
361
+ "schemaVersion",
362
+ "status",
363
+ "failureClass",
364
+ "usage",
365
+ "modelSettlement",
366
+ ...result.failureEvidence ? ["failureEvidence"] : []
367
+ ],
368
+ "candidate execution terminal result"
369
+ );
370
+ if (result.schemaVersion !== 1) {
371
+ throw new Error("candidate execution terminal schemaVersion must be 1");
372
+ }
373
+ const usage = sealUsage(result.usage);
374
+ const modelSettlement = sealArtifactRef(result.modelSettlement, "modelSettlement");
375
+ if (result.status === "succeeded") {
376
+ return Object.freeze({
377
+ schemaVersion: 1,
378
+ status: "succeeded",
379
+ usage,
380
+ modelSettlement,
381
+ taskOutcome: sealArtifactRef(result.taskOutcome, "taskOutcome"),
382
+ benchmarkResult: sealArtifactRef(result.benchmarkResult, "benchmarkResult"),
383
+ runReceipt: sealArtifactRef(result.runReceipt, "runReceipt")
384
+ });
385
+ }
386
+ assertFailureClass(result.failureClass);
387
+ if (result.failureClass === "pre-model-infrastructure" && usage.modelCalls !== 0) {
388
+ throw new Error("pre-model infrastructure failure cannot contain model calls");
389
+ }
390
+ return Object.freeze({
391
+ schemaVersion: 1,
392
+ status: "failed",
393
+ failureClass: result.failureClass,
394
+ usage,
395
+ modelSettlement,
396
+ ...result.failureEvidence ? { failureEvidence: sealArtifactRef(result.failureEvidence, "failureEvidence") } : {}
397
+ });
398
+ }
399
+ function sealUsage(usage) {
400
+ assertExactObjectKeys(
401
+ usage,
402
+ [
403
+ "costUsdNanos",
404
+ "inputTokens",
405
+ "outputTokens",
406
+ "cachedInputTokens",
407
+ "reasoningTokens",
408
+ "modelCalls"
409
+ ],
410
+ "candidate execution terminal usage"
411
+ );
412
+ for (const [field, value] of Object.entries(usage)) {
413
+ assertCount(value, `terminal usage ${field}`);
414
+ }
415
+ return Object.freeze({
416
+ costUsdNanos: usage.costUsdNanos,
417
+ inputTokens: usage.inputTokens,
418
+ outputTokens: usage.outputTokens,
419
+ cachedInputTokens: usage.cachedInputTokens,
420
+ reasoningTokens: usage.reasoningTokens,
421
+ modelCalls: usage.modelCalls
422
+ });
423
+ }
424
+ function sealArtifactRef(ref, label) {
425
+ const parsed = agentCandidateArtifactRefSchema.parse(ref);
426
+ if (!Number.isSafeInteger(parsed.byteLength)) {
427
+ throw new Error(`candidate execution terminal ${label} byteLength exceeds safe integer range`);
428
+ }
429
+ return immutableCandidateValue(parsed);
430
+ }
431
+ function requireArtifactRef(value, path, field) {
432
+ return requireObject(value, path, field);
433
+ }
434
+ function requireString(value, path, field) {
435
+ if (typeof value !== "string") {
436
+ throw new Error(`candidate execution record at ${path} has invalid ${field}`);
437
+ }
438
+ return value;
439
+ }
440
+ function requireNumber(value, path, field) {
441
+ if (typeof value !== "number") {
442
+ throw new Error(`candidate execution record at ${path} has invalid ${field}`);
443
+ }
444
+ return value;
445
+ }
446
+ function requireObject(value, path, field) {
447
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
448
+ throw new Error(`candidate execution record at ${path} has invalid ${field}`);
449
+ }
450
+ return value;
451
+ }
452
+ function requireTerminalStatus(value, path) {
453
+ if (value !== "succeeded" && value !== "failed") {
454
+ throw new Error(`candidate execution terminal record at ${path} has invalid status`);
455
+ }
456
+ return value;
457
+ }
458
+ function requireFailureClass(value, path) {
459
+ try {
460
+ assertFailureClass(value);
461
+ return value;
462
+ } catch (error) {
463
+ throw new Error(`candidate execution terminal record at ${path} has invalid failureClass`, {
464
+ cause: error
465
+ });
466
+ }
467
+ }
468
+ function assertFailureClass(value) {
469
+ if (value !== "pre-model-infrastructure" && value !== "execution" && value !== "post-model-infrastructure" && value !== "unknown") {
470
+ throw new Error("candidate execution failureClass is invalid");
471
+ }
472
+ }
473
+ function assertExecutionId(value) {
474
+ if (typeof value !== "string" || !/^[A-Za-z0-9._:-]{1,200}$/.test(value)) {
475
+ throw new Error("candidate execution claim executionId is invalid");
476
+ }
477
+ }
478
+ function assertSha256Digest(value, field) {
479
+ if (!SHA256_PATTERN.test(value)) {
480
+ throw new Error(`candidate execution claim ${field} must be a lowercase sha256 digest`);
481
+ }
482
+ }
483
+ function assertCount(value, label) {
484
+ if (!Number.isSafeInteger(value) || value < 0) {
485
+ throw new Error(`candidate execution ${label} must be a non-negative safe integer`);
486
+ }
487
+ }
488
+
489
+ // src/candidate-execution/cleanup.ts
490
+ var DEFAULT_CANDIDATE_CLEANUP_TIMEOUT_MS = 3e4;
491
+ var MAX_CANDIDATE_TIMER_INTERVAL_MS = 2147483647;
492
+ function candidateCleanupTimeout(timeoutMs) {
493
+ const effective = timeoutMs ?? DEFAULT_CANDIDATE_CLEANUP_TIMEOUT_MS;
494
+ if (!Number.isSafeInteger(effective) || effective <= 0 || effective > MAX_CANDIDATE_TIMER_INTERVAL_MS) {
495
+ throw new Error("candidate cleanup timeout is outside the supported timer range");
496
+ }
497
+ return effective;
498
+ }
499
+ function candidateCleanupDeadline(timeoutMs) {
500
+ return Date.now() + candidateCleanupTimeout(timeoutMs);
501
+ }
502
+ function candidateResultTimeout(timeoutMs, taskTimeoutMs) {
503
+ const effective = timeoutMs ?? taskTimeoutMs;
504
+ if (!Number.isSafeInteger(effective) || effective <= 0 || effective > MAX_CANDIDATE_TIMER_INTERVAL_MS) {
505
+ throw new Error("candidate result timeout is outside the supported timer range");
506
+ }
507
+ return effective;
508
+ }
509
+ async function withinCandidateCleanupDeadline(operation, deadlineAtMs, label) {
510
+ const remainingMs = deadlineAtMs - Date.now();
511
+ if (remainingMs <= 0) throw new CandidateCleanupTimeoutError(label);
512
+ const pending = Promise.resolve().then(operation);
513
+ void pending.catch(() => void 0);
514
+ let timer;
515
+ try {
516
+ const result = await Promise.race([
517
+ pending,
518
+ new Promise((_resolve, reject) => {
519
+ timer = setTimeout(() => reject(new CandidateCleanupTimeoutError(label)), remainingMs);
520
+ })
521
+ ]);
522
+ if (Date.now() >= deadlineAtMs) throw new CandidateCleanupTimeoutError(label);
523
+ return result;
524
+ } finally {
525
+ if (timer) clearTimeout(timer);
526
+ }
527
+ }
528
+ async function withinCandidateResultDeadline(operation, deadlineAtMs, label) {
529
+ const remainingMs = deadlineAtMs - Date.now();
530
+ if (remainingMs <= 0) throw new CandidateResultTimeoutError(label);
531
+ const controller = new AbortController();
532
+ const timeoutError = new CandidateResultTimeoutError(label);
533
+ const pending = Promise.resolve().then(() => operation(controller.signal));
534
+ void pending.catch(() => void 0);
535
+ let timer;
536
+ try {
537
+ const result = await Promise.race([
538
+ pending,
539
+ new Promise((_resolve, reject) => {
540
+ timer = setTimeout(() => {
541
+ controller.abort(timeoutError);
542
+ reject(timeoutError);
543
+ }, remainingMs);
544
+ })
545
+ ]);
546
+ if (Date.now() >= deadlineAtMs) {
547
+ controller.abort(timeoutError);
548
+ throw timeoutError;
549
+ }
550
+ return result;
551
+ } finally {
552
+ if (timer) clearTimeout(timer);
553
+ }
554
+ }
555
+ var CandidateCleanupTimeoutError = class extends Error {
556
+ constructor(label) {
557
+ super(`${label} did not complete before the evaluator cleanup deadline`);
558
+ this.name = "CandidateCleanupTimeoutError";
559
+ }
560
+ };
561
+ var CandidateResultTimeoutError = class extends Error {
562
+ constructor(label) {
563
+ super(`${label} did not complete before the evaluator result deadline`);
564
+ this.name = "CandidateResultTimeoutError";
565
+ }
566
+ };
567
+
568
+ // src/candidate-execution/claim.ts
569
+ function attemptRecord(claim, phase, staged, terminal) {
570
+ return Object.freeze({
571
+ claim,
572
+ phase,
573
+ ...staged ? { staged } : {},
574
+ ...terminal ? { terminal } : {}
575
+ });
576
+ }
577
+ var InMemoryAgentCandidateExecutionClaimStore = class {
578
+ claims = /* @__PURE__ */ new Map();
579
+ now;
580
+ constructor(options = {}) {
581
+ this.now = options.now ?? Date.now;
582
+ }
583
+ async tryClaim(requested) {
584
+ const claim = sealClaim(requested);
585
+ const slot = claimSlot(claim);
586
+ const existing = this.claims.get(slot);
587
+ if (existing) return rejectedExistingClaim(existing.claim, claim);
588
+ assertUnexpiredLease(claim.leaseExpiresAtMs, this.now());
589
+ const retryRejection2 = retryRejectionFromMemory(this.claims, claim);
590
+ if (retryRejection2) return rejectedRetry(claim, retryRejection2);
591
+ const lease = newLease(claim);
592
+ this.claims.set(slot, {
593
+ claim,
594
+ leaseDigest: leaseDigest(lease),
595
+ phase: "claimed"
596
+ });
597
+ return Object.freeze({ acquired: true, claim, lease });
598
+ }
599
+ async getAttempt(requestedAttempt) {
600
+ const attempt = sealAttemptRef(requestedAttempt);
601
+ const stored = this.claims.get(claimSlot(attempt));
602
+ return stored ? attemptRecord(stored.claim, stored.phase, stored.staged, stored.terminal) : void 0;
603
+ }
604
+ async markCandidateMayRun(requestedLease) {
605
+ const lease = sealLease(requestedLease);
606
+ const stored = this.requireClaim(lease);
607
+ assertLease(stored.leaseDigest, stored.claim.leaseExpiresAtMs, lease);
608
+ if (stored.phase === "candidate-may-run") {
609
+ return Object.freeze({ marked: false, phase: "candidate-may-run" });
610
+ }
611
+ if (stored.staged || stored.terminal) {
612
+ throw new Error("candidate execution terminal was staged before candidate-may-run phase");
613
+ }
614
+ assertUnexpiredLease(stored.claim.leaseExpiresAtMs, this.now());
615
+ stored.phase = "candidate-may-run";
616
+ return Object.freeze({ marked: true, phase: "candidate-may-run" });
617
+ }
618
+ async stageTerminal(requestedLease, result) {
619
+ const lease = sealLease(requestedLease);
620
+ const stored = this.requireClaim(lease);
621
+ assertLease(stored.leaseDigest, stored.claim.leaseExpiresAtMs, lease);
622
+ const terminal = terminalRecord(stored.claim, result);
623
+ if (stored.staged) return rejectedStage(stored.staged, terminal);
624
+ assertTerminalAllowedInPhase(stored.phase, terminal);
625
+ assertUnexpiredLease(stored.claim.leaseExpiresAtMs, this.now());
626
+ stored.staged = terminal;
627
+ return Object.freeze({ staged: true, terminal });
628
+ }
629
+ async finish(requestedLease, requestedTerminalDigest) {
630
+ const lease = sealLease(requestedLease);
631
+ const terminalDigest = sealTerminalDigest(requestedTerminalDigest);
632
+ const stored = this.requireClaim(lease);
633
+ assertLease(stored.leaseDigest, stored.claim.leaseExpiresAtMs, lease);
634
+ const staged = requireStagedTerminal(stored.staged, terminalDigest);
635
+ if (stored.terminal) return rejectedFinish(stored.terminal, terminalDigest);
636
+ assertUnexpiredLease(stored.claim.leaseExpiresAtMs, this.now());
637
+ stored.terminal = staged;
638
+ return Object.freeze({ finished: true, terminal: staged });
639
+ }
640
+ async recoverExpired(requestedAttempt, evidence) {
641
+ const attempt = sealAttemptRef(requestedAttempt);
642
+ const stored = this.requireClaim(attempt, "candidate execution recovery");
643
+ const recovered = recoveredTerminalRecord(stored.claim, stored.phase, evidence);
644
+ if (stored.staged) assertRecoveryMatchesStaged(stored.staged, recovered);
645
+ const requestedDigest = stored.staged?.terminalDigest ?? recovered.terminalDigest;
646
+ if (stored.terminal) return rejectedFinish(stored.terminal, requestedDigest);
647
+ assertExpiredLease(stored.claim.leaseExpiresAtMs, this.now());
648
+ const terminal = stored.staged ?? recovered;
649
+ assertRecoveryMatchesStaged(terminal, recovered);
650
+ stored.staged ??= terminal;
651
+ stored.terminal = terminal;
652
+ return Object.freeze({ finished: true, terminal });
653
+ }
654
+ requireClaim(attempt, operation = "candidate execution lease") {
655
+ const stored = this.claims.get(claimSlot(attempt));
656
+ if (!stored) throw new Error(`${operation} does not name an acquired attempt`);
657
+ return stored;
658
+ }
659
+ };
660
+ var SHA256_PATTERN2 = /^sha256:[a-f0-9]{64}$/;
661
+ var LEASE_TOKEN_PATTERN = /^candidate-execution-lease-v1\.[A-Za-z0-9_-]{43}$/;
662
+ var PREPARATION_ID_PATTERN = /^candidate-preparation-v1\.[A-Za-z0-9_-]{43}$/;
663
+ function sealClaim(claim) {
664
+ assertExactObjectKeys(
665
+ claim,
666
+ [
667
+ "executionId",
668
+ "attempt",
669
+ "maxAttempts",
670
+ "retryPolicy",
671
+ "bundleDigest",
672
+ "executionPlanDigest",
673
+ "retryLineageDigest",
674
+ "leaseExpiresAtMs",
675
+ "resultTimeoutMs",
676
+ "cleanup"
677
+ ],
678
+ "candidate execution claim"
679
+ );
680
+ assertExecutionId2(claim.executionId);
681
+ if (!Number.isSafeInteger(claim.attempt) || claim.attempt < 1) {
682
+ throw new Error("candidate execution claim attempt must be a positive safe integer");
683
+ }
684
+ if (!Number.isSafeInteger(claim.maxAttempts) || claim.maxAttempts < 1) {
685
+ throw new Error("candidate execution claim maxAttempts must be a positive safe integer");
686
+ }
687
+ if (claim.attempt > claim.maxAttempts) {
688
+ throw new Error("candidate execution claim attempt exceeds maxAttempts");
689
+ }
690
+ if (!["none", "pre-model-infrastructure-only"].includes(claim.retryPolicy)) {
691
+ throw new Error("candidate execution claim retryPolicy is invalid");
692
+ }
693
+ if (claim.retryPolicy === "none" && claim.maxAttempts !== 1) {
694
+ throw new Error("candidate execution claim retryPolicy none requires maxAttempts 1");
695
+ }
696
+ assertSha256Digest2(claim.bundleDigest, "bundleDigest");
697
+ assertSha256Digest2(claim.executionPlanDigest, "executionPlanDigest");
698
+ assertSha256Digest2(claim.retryLineageDigest, "retryLineageDigest");
699
+ assertPositiveTimestamp(claim.leaseExpiresAtMs, "leaseExpiresAtMs");
700
+ candidateResultTimeout(claim.resultTimeoutMs, claim.resultTimeoutMs);
701
+ const cleanup = sealCleanupHandles(claim.cleanup);
702
+ return Object.freeze({
703
+ executionId: claim.executionId,
704
+ attempt: claim.attempt,
705
+ maxAttempts: claim.maxAttempts,
706
+ retryPolicy: claim.retryPolicy,
707
+ bundleDigest: claim.bundleDigest,
708
+ executionPlanDigest: claim.executionPlanDigest,
709
+ retryLineageDigest: claim.retryLineageDigest,
710
+ leaseExpiresAtMs: claim.leaseExpiresAtMs,
711
+ resultTimeoutMs: claim.resultTimeoutMs,
712
+ cleanup
713
+ });
714
+ }
715
+ function sealCleanupHandles(cleanup) {
716
+ assertExactObjectKeys(
717
+ cleanup,
718
+ cleanup.memory ? [
719
+ "preparationId",
720
+ "modelGrantDigest",
721
+ "resolvedModel",
722
+ "traceRunId",
723
+ "cleanupTimeoutMs",
724
+ "memory"
725
+ ] : ["preparationId", "modelGrantDigest", "resolvedModel", "traceRunId", "cleanupTimeoutMs"],
726
+ "candidate execution cleanup handles"
727
+ );
728
+ if (!PREPARATION_ID_PATTERN.test(cleanup.preparationId)) {
729
+ throw new Error("candidate execution cleanup preparationId is invalid");
730
+ }
731
+ assertSha256Digest2(cleanup.modelGrantDigest, "cleanup modelGrantDigest");
732
+ const resolvedModel = immutableCandidateValue(
733
+ agentCandidateResolvedModelSchema.parse(cleanup.resolvedModel)
734
+ );
735
+ assertBoundedIdentifier(cleanup.traceRunId, "cleanup traceRunId", 512);
736
+ const cleanupTimeoutMs = candidateCleanupTimeout(cleanup.cleanupTimeoutMs);
737
+ const memory = cleanup.memory ? sealMemoryCleanupHandle(cleanup.memory) : void 0;
738
+ return Object.freeze({
739
+ preparationId: cleanup.preparationId,
740
+ modelGrantDigest: cleanup.modelGrantDigest,
741
+ resolvedModel,
742
+ traceRunId: cleanup.traceRunId,
743
+ cleanupTimeoutMs,
744
+ ...memory ? { memory } : {}
745
+ });
746
+ }
747
+ function sealMemoryCleanupHandle(memory) {
748
+ assertExactObjectKeys(
749
+ memory,
750
+ ["accessDigest", "effectiveNamespace"],
751
+ "candidate execution memory cleanup handle"
752
+ );
753
+ assertSha256Digest2(memory.accessDigest, "memory accessDigest");
754
+ assertBoundedIdentifier(memory.effectiveNamespace, "memory effectiveNamespace", 1024);
755
+ return Object.freeze({
756
+ accessDigest: memory.accessDigest,
757
+ effectiveNamespace: memory.effectiveNamespace
758
+ });
759
+ }
760
+ function sealAttemptRef(attempt) {
761
+ assertExactObjectKeys(attempt, ["executionId", "attempt"], "candidate execution attempt reference");
762
+ assertExecutionId2(attempt.executionId);
763
+ if (!Number.isSafeInteger(attempt.attempt) || attempt.attempt < 1) {
764
+ throw new Error("candidate execution attempt reference must have a positive safe attempt");
765
+ }
766
+ return Object.freeze({ executionId: attempt.executionId, attempt: attempt.attempt });
767
+ }
768
+ function sealLease(lease) {
769
+ assertExactObjectKeys(
770
+ lease,
771
+ ["executionId", "attempt", "token", "expiresAtMs"],
772
+ "candidate execution lease"
773
+ );
774
+ if (lease.executionId.length === 0 || !Number.isSafeInteger(lease.attempt) || lease.attempt < 1) {
775
+ throw new Error("candidate execution lease identity is invalid");
776
+ }
777
+ if (!LEASE_TOKEN_PATTERN.test(lease.token)) {
778
+ throw new Error("candidate execution lease token is invalid");
779
+ }
780
+ assertPositiveTimestamp(lease.expiresAtMs, "lease expiresAtMs");
781
+ return Object.freeze({
782
+ executionId: lease.executionId,
783
+ attempt: lease.attempt,
784
+ token: lease.token,
785
+ expiresAtMs: lease.expiresAtMs
786
+ });
787
+ }
788
+ function newLease(claim) {
789
+ return Object.freeze({
790
+ executionId: claim.executionId,
791
+ attempt: claim.attempt,
792
+ token: `candidate-execution-lease-v1.${randomBytes(32).toString("base64url")}`,
793
+ expiresAtMs: claim.leaseExpiresAtMs
794
+ });
795
+ }
796
+ function leaseDigest(lease) {
797
+ return sha256(lease.token);
798
+ }
799
+ function assertLease(expectedDigest, expectedExpiresAtMs, lease) {
800
+ const expected = Buffer.from(expectedDigest);
801
+ const actual = Buffer.from(leaseDigest(lease));
802
+ if (expected.length !== actual.length || !timingSafeEqual(expected, actual) || lease.expiresAtMs !== expectedExpiresAtMs) {
803
+ throw new Error("candidate execution lease is invalid");
804
+ }
805
+ }
806
+ function claimSlot(claim) {
807
+ return createHash2("sha256").update(JSON.stringify([claim.executionId, claim.attempt]), "utf8").digest("hex");
808
+ }
809
+ function retryRejectionFromMemory(claims, claim) {
810
+ if (claim.attempt === 1) return void 0;
811
+ const prior = claims.get(
812
+ claimSlot({ executionId: claim.executionId, attempt: claim.attempt - 1 })
813
+ );
814
+ return retryRejection(claim, prior);
815
+ }
816
+ function retryRejection(claim, prior) {
817
+ if (!prior) return "prior-attempt-missing";
818
+ if (claim.retryPolicy !== "pre-model-infrastructure-only" || prior.claim.retryPolicy !== claim.retryPolicy || prior.claim.maxAttempts !== claim.maxAttempts || prior.claim.bundleDigest !== claim.bundleDigest || prior.claim.retryLineageDigest !== claim.retryLineageDigest) {
819
+ return "retry-lineage-mismatch";
820
+ }
821
+ if (!prior.terminal) return "prior-attempt-running";
822
+ if (prior.terminal.status === "succeeded") return "prior-attempt-succeeded";
823
+ if (prior.terminal.usage.modelCalls !== 0) return "prior-attempt-spent-model-calls";
824
+ if (prior.terminal.failureClass !== "pre-model-infrastructure") {
825
+ return "prior-attempt-not-pre-model-infrastructure";
826
+ }
827
+ return void 0;
828
+ }
829
+ function rejectedExistingClaim(existing, requested) {
830
+ return Object.freeze({
831
+ acquired: false,
832
+ reason: "already-claimed",
833
+ claim: existing,
834
+ exactReplay: canonicalCandidateDigest(existing) === canonicalCandidateDigest(requested)
835
+ });
836
+ }
837
+ function rejectedRetry(claim, detail) {
838
+ return Object.freeze({ acquired: false, reason: "retry-not-eligible", claim, detail });
839
+ }
840
+ async function readClaim(path) {
841
+ const parsed = await readJsonObject(path, "claim");
842
+ const record = parsed;
843
+ if (record.version !== CLAIM_FORMAT_VERSION) {
844
+ throw new Error(`candidate execution claim at ${path} has unsupported version`);
845
+ }
846
+ assertExactObjectKeys(
847
+ parsed,
848
+ [
849
+ "version",
850
+ "executionId",
851
+ "attempt",
852
+ "maxAttempts",
853
+ "retryPolicy",
854
+ "bundleDigest",
855
+ "executionPlanDigest",
856
+ "retryLineageDigest",
857
+ "leaseExpiresAtMs",
858
+ "resultTimeoutMs",
859
+ "cleanup",
860
+ "phase",
861
+ "leaseDigest"
862
+ ],
863
+ `candidate execution claim at ${path}`
864
+ );
865
+ const claim = sealClaim({
866
+ executionId: requireString2(record.executionId, path, "executionId"),
867
+ attempt: requireNumber2(record.attempt, path, "attempt"),
868
+ maxAttempts: requireNumber2(record.maxAttempts, path, "maxAttempts"),
869
+ retryPolicy: requireRetryPolicy(record.retryPolicy, path),
870
+ bundleDigest: requireString2(record.bundleDigest, path, "bundleDigest"),
871
+ executionPlanDigest: requireString2(
872
+ record.executionPlanDigest,
873
+ path,
874
+ "executionPlanDigest"
875
+ ),
876
+ retryLineageDigest: requireString2(
877
+ record.retryLineageDigest,
878
+ path,
879
+ "retryLineageDigest"
880
+ ),
881
+ leaseExpiresAtMs: requireNumber2(record.leaseExpiresAtMs, path, "leaseExpiresAtMs"),
882
+ resultTimeoutMs: requireNumber2(record.resultTimeoutMs, path, "resultTimeoutMs"),
883
+ cleanup: requireObject2(
884
+ record.cleanup,
885
+ path,
886
+ "cleanup"
887
+ )
888
+ });
889
+ const persistedLeaseDigest = requireString2(
890
+ record.leaseDigest,
891
+ path,
892
+ "leaseDigest"
893
+ );
894
+ assertSha256Digest2(persistedLeaseDigest, "leaseDigest");
895
+ if (record.phase !== "claimed") {
896
+ throw new Error(`candidate execution claim at ${path} has invalid initial phase`);
897
+ }
898
+ return { claim, leaseDigest: persistedLeaseDigest, phase: "claimed" };
899
+ }
900
+ async function readClaimIfPresent(path) {
901
+ try {
902
+ return await readClaim(path);
903
+ } catch (error) {
904
+ if (isMissingError(error)) return void 0;
905
+ throw error;
906
+ }
907
+ }
908
+ async function readTerminal(path) {
909
+ const parsed = await readJsonObject(path, "terminal record");
910
+ const record = parsed;
911
+ if (record.version !== TERMINAL_FORMAT_VERSION) {
912
+ throw new Error(`candidate execution terminal record at ${path} has unsupported version`);
913
+ }
914
+ assertExactObjectKeys(parsed, ["version", "terminal"], `candidate execution terminal record at ${path}`);
915
+ return sealTerminalRecordValue(
916
+ requireObject2(record.terminal, path, "terminal"),
917
+ `candidate execution terminal record at ${path}`
918
+ );
919
+ }
920
+ async function readTerminalIfPresent(path) {
921
+ try {
922
+ return await readTerminal(path);
923
+ } catch (error) {
924
+ if (isMissingError(error)) return void 0;
925
+ throw error;
926
+ }
927
+ }
928
+ async function readTransitionIfPresent(path, claim) {
929
+ let parsed;
930
+ try {
931
+ parsed = await readJsonObject(path, "transition record");
932
+ } catch (error) {
933
+ if (isMissingError(error)) return void 0;
934
+ throw error;
935
+ }
936
+ if (parsed.kind === "candidate-execution-phase") {
937
+ const record = parsed;
938
+ if (record.version !== PHASE_FORMAT_VERSION) {
939
+ throw new Error(`candidate execution phase record at ${path} has unsupported version`);
940
+ }
941
+ assertExactObjectKeys(
942
+ parsed,
943
+ ["version", "kind", "executionId", "attempt", "executionPlanDigest", "phase"],
944
+ `candidate execution phase record at ${path}`
945
+ );
946
+ if (record.executionId !== claim.executionId || record.attempt !== claim.attempt || record.executionPlanDigest !== claim.executionPlanDigest || record.phase !== "candidate-may-run") {
947
+ throw new Error(`candidate execution phase record at ${path} does not match its claim`);
948
+ }
949
+ return { kind: "phase" };
950
+ }
951
+ if (parsed.kind === "candidate-execution-pending-terminal") {
952
+ const record = parsed;
953
+ if (record.version !== PENDING_FORMAT_VERSION) {
954
+ throw new Error(`candidate execution pending record at ${path} has unsupported version`);
955
+ }
956
+ assertExactObjectKeys(
957
+ parsed,
958
+ ["version", "kind", "terminal"],
959
+ `candidate execution pending record at ${path}`
960
+ );
961
+ const terminal = sealTerminalRecordValue(
962
+ requireObject2(record.terminal, path, "terminal"),
963
+ `candidate execution pending record at ${path}`
964
+ );
965
+ assertTerminalMatchesClaim(terminal, claim, path);
966
+ return { kind: "pending", terminal };
967
+ }
968
+ throw new Error(`candidate execution transition record at ${path} has invalid kind`);
969
+ }
970
+ async function readJsonObject(path, kind) {
971
+ let parsed;
972
+ try {
973
+ parsed = JSON.parse(await readFile(path, "utf8"));
974
+ } catch (error) {
975
+ if (isMissingError(error)) throw error;
976
+ throw new Error(`candidate execution ${kind} at ${path} is unreadable`, { cause: error });
977
+ }
978
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
979
+ throw new Error(`candidate execution ${kind} at ${path} is not an object`);
980
+ }
981
+ return parsed;
982
+ }
983
+ function assertSameSlot(existing, requested, path) {
984
+ if (existing.executionId !== requested.executionId || existing.attempt !== requested.attempt) {
985
+ throw new Error(`candidate execution record at ${path} does not match its claim slot`);
986
+ }
987
+ }
988
+ function assertSha256Digest2(value, field) {
989
+ if (!SHA256_PATTERN2.test(value)) {
990
+ throw new Error(`candidate execution claim ${field} must be a lowercase sha256 digest`);
991
+ }
992
+ }
993
+ function requireString2(value, path, field) {
994
+ if (typeof value !== "string") {
995
+ throw new Error(`candidate execution record at ${path} has invalid ${field}`);
996
+ }
997
+ return value;
998
+ }
999
+ function requireNumber2(value, path, field) {
1000
+ if (typeof value !== "number") {
1001
+ throw new Error(`candidate execution record at ${path} has invalid ${field}`);
1002
+ }
1003
+ return value;
1004
+ }
1005
+ function requireObject2(value, path, field) {
1006
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
1007
+ throw new Error(`candidate execution record at ${path} has invalid ${field}`);
1008
+ }
1009
+ return value;
1010
+ }
1011
+ function requireRetryPolicy(value, path) {
1012
+ if (value !== "none" && value !== "pre-model-infrastructure-only") {
1013
+ throw new Error(`candidate execution record at ${path} has invalid retryPolicy`);
1014
+ }
1015
+ return value;
1016
+ }
1017
+ function assertExecutionId2(value) {
1018
+ if (typeof value !== "string" || !/^[A-Za-z0-9._:-]{1,200}$/.test(value)) {
1019
+ throw new Error("candidate execution claim executionId is invalid");
1020
+ }
1021
+ }
1022
+ function assertBoundedIdentifier(value, label, maxLength) {
1023
+ if (typeof value !== "string" || value.length === 0 || value.length > maxLength || hasControlCharacter(value)) {
1024
+ throw new Error(`candidate execution ${label} is invalid`);
1025
+ }
1026
+ }
1027
+ function hasControlCharacter(value) {
1028
+ for (let index = 0; index < value.length; index++) {
1029
+ const code = value.charCodeAt(index);
1030
+ if (code < 32 || code === 127) return true;
1031
+ }
1032
+ return false;
1033
+ }
1034
+ function assertPositiveTimestamp(value, label) {
1035
+ if (!Number.isSafeInteger(value) || value <= 0) {
1036
+ throw new Error(`candidate execution ${label} must be a positive safe timestamp`);
1037
+ }
1038
+ }
1039
+ function assertClock(value) {
1040
+ if (!Number.isSafeInteger(value) || value < 0) {
1041
+ throw new Error("candidate execution claim-store clock returned an invalid timestamp");
1042
+ }
1043
+ }
1044
+ function assertUnexpiredLease(expiresAtMs, nowMs) {
1045
+ assertClock(nowMs);
1046
+ if (nowMs >= expiresAtMs) throw new Error("candidate execution lease has expired");
1047
+ }
1048
+ function assertExpiredLease(expiresAtMs, nowMs) {
1049
+ assertClock(nowMs);
1050
+ if (nowMs < expiresAtMs) throw new Error("candidate execution lease has not expired");
1051
+ }
1052
+ function sha256(value) {
1053
+ return `sha256:${createHash2("sha256").update(value, "utf8").digest("hex")}`;
1054
+ }
1055
+ function isMissingError(error) {
1056
+ return isNodeError(error, "ENOENT");
1057
+ }
1058
+ function isNodeError(error, code) {
1059
+ return error !== null && typeof error === "object" && "code" in error && error.code === code;
1060
+ }
1061
+ var candidateClaimFileInternals = Object.freeze({
1062
+ assertExpiredLease,
1063
+ assertLease,
1064
+ assertSameSlot,
1065
+ assertUnexpiredLease,
1066
+ attemptRecord,
1067
+ claimSlot,
1068
+ leaseDigest,
1069
+ newLease,
1070
+ readClaim,
1071
+ readClaimIfPresent,
1072
+ readTerminal,
1073
+ readTerminalIfPresent,
1074
+ readTransitionIfPresent,
1075
+ rejectedExistingClaim,
1076
+ rejectedRetry,
1077
+ retryRejection,
1078
+ sealAttemptRef,
1079
+ sealClaim,
1080
+ sealLease
1081
+ });
1082
+
1083
+ // src/candidate-execution/execution-window.ts
1084
+ var CANDIDATE_TERMINAL_PERSISTENCE_MARGIN_MS = 1e4;
1085
+ var CANDIDATE_POST_RUN_CLEANUP_PHASES = 4;
1086
+ function candidatePostRunWindowMs(cleanupTimeoutMs, resultTimeoutMs) {
1087
+ const windowMs = cleanupTimeoutMs * CANDIDATE_POST_RUN_CLEANUP_PHASES + resultTimeoutMs + CANDIDATE_TERMINAL_PERSISTENCE_MARGIN_MS;
1088
+ if (!Number.isSafeInteger(windowMs) || windowMs > MAX_CANDIDATE_TIMER_INTERVAL_MS) {
1089
+ throw new Error("candidate post-run window exceeds the supported timer range");
1090
+ }
1091
+ return windowMs;
1092
+ }
1093
+ function candidateExecutionOwnerWindowMs(timeoutMs, cleanupTimeoutMs, resultTimeoutMs) {
1094
+ const windowMs = timeoutMs + candidatePostRunWindowMs(cleanupTimeoutMs, resultTimeoutMs);
1095
+ if (!Number.isSafeInteger(windowMs) || windowMs > MAX_CANDIDATE_TIMER_INTERVAL_MS) {
1096
+ throw new Error("candidate execution and cleanup window exceeds the supported timer range");
1097
+ }
1098
+ return windowMs;
1099
+ }
1100
+ function candidateTerminalWindowMs(cleanupTimeoutMs) {
1101
+ const windowMs = cleanupTimeoutMs + CANDIDATE_TERMINAL_PERSISTENCE_MARGIN_MS;
1102
+ if (!Number.isSafeInteger(windowMs) || windowMs > MAX_CANDIDATE_TIMER_INTERVAL_MS) {
1103
+ throw new Error("candidate terminal window exceeds the supported timer range");
1104
+ }
1105
+ return windowMs;
1106
+ }
1107
+
1108
+ // src/candidate-execution/prepared-state.ts
1109
+ import {
1110
+ agentCandidateExecutionPlanEvidenceSchema,
1111
+ agentCandidateMaterializationReceiptSchema,
1112
+ agentCandidateProfilePlanEvidenceSchema
1113
+ } from "@tangle-network/agent-interface";
1114
+
1115
+ // src/candidate-execution/artifacts.ts
1116
+ import { constants as fsConstants } from "fs";
1117
+ import { lstat, open, readdir, realpath } from "fs/promises";
1118
+ import { relative, resolve, sep } from "path";
1119
+ function artifactCacheKey(artifact) {
1120
+ return `${artifact.sha256}:${artifact.byteLength}`;
1121
+ }
1122
+ async function readVerifiedArtifact(artifact, port) {
1123
+ const bytes = "content" in artifact ? Buffer.from(artifact.content, "base64") : await port.read(artifact);
1124
+ verifyBytes(bytes, artifact.sha256, artifact.byteLength, "candidate artifact");
1125
+ return Uint8Array.from(bytes);
1126
+ }
1127
+ function verifyBytes(bytes, digest, byteLength, label) {
1128
+ if (bytes.byteLength !== byteLength) {
1129
+ throw new Error(`${label} byte length ${bytes.byteLength} does not match ${byteLength}`);
1130
+ }
1131
+ const actual = sha256Bytes(bytes);
1132
+ if (actual !== digest) {
1133
+ throw new Error(`${label} digest ${actual} does not match ${digest}`);
1134
+ }
1135
+ }
1136
+ async function verifyWorkspaceSnapshotArtifacts(snapshot, port) {
1137
+ const [manifest, archive] = await Promise.all([
1138
+ readVerifiedArtifact(snapshot.manifest, port),
1139
+ readVerifiedArtifact(snapshot.archive, port)
1140
+ ]);
1141
+ const canonicalManifest = canonicalCandidateBytes(snapshot.material);
1142
+ if (!Buffer.from(manifest).equals(Buffer.from(canonicalManifest))) {
1143
+ throw new Error("workspace manifest artifact is not the exact canonical manifest material");
1144
+ }
1145
+ if (sha256Bytes(canonicalManifest) !== snapshot.digest) {
1146
+ throw new Error("workspace snapshot digest does not match its canonical manifest material");
1147
+ }
1148
+ return { manifest, archive };
1149
+ }
1150
+ async function verifyMaterializedWorkspace(root, expected, options = {}) {
1151
+ const observed = await scanWorkspace(root, new Set(options.ignoredProtectedRootEntries ?? []));
1152
+ assertWorkspaceManifest(observed.manifest, expected);
1153
+ }
1154
+ async function readMaterializedWorkspaceFiles(root, expected, options = {}) {
1155
+ const observed = await scanWorkspace(root, new Set(options.ignoredProtectedRootEntries ?? []));
1156
+ assertWorkspaceManifest(observed.manifest, expected);
1157
+ return observed.files.map(
1158
+ (file) => Object.freeze({ path: file.path, mode: file.mode, bytes: Uint8Array.from(file.bytes) })
1159
+ );
1160
+ }
1161
+ function assertWorkspaceManifest(observed, expected) {
1162
+ if (!Buffer.from(canonicalCandidateBytes(observed)).equals(canonicalCandidateBytes(expected))) {
1163
+ throw new Error(
1164
+ "materialized workspace files, modes, or bytes do not match the signed manifest"
1165
+ );
1166
+ }
1167
+ }
1168
+ async function verifyMaterializedProfileWorkspace(root, expected) {
1169
+ const observed = await scanWorkspace(root, /* @__PURE__ */ new Set());
1170
+ const observedProfile = observed.manifest.files.map(({ path, mode, sha256: sha2562 }) => ({
1171
+ relPath: path,
1172
+ mode,
1173
+ contentSha256: sha2562
1174
+ }));
1175
+ if (!Buffer.from(canonicalCandidateBytes(observedProfile)).equals(
1176
+ canonicalCandidateBytes(expected.files)
1177
+ )) {
1178
+ throw new Error("profile staging files, modes, or bytes do not match the signed profile plan");
1179
+ }
1180
+ }
1181
+ async function scanWorkspace(root, ignoredProtectedRootEntries) {
1182
+ const absoluteRoot = resolve(root);
1183
+ const rootStats = await lstat(absoluteRoot);
1184
+ if (!rootStats.isDirectory() || rootStats.isSymbolicLink()) {
1185
+ throw new Error("workspace root must be a real directory");
1186
+ }
1187
+ if (await realpath(absoluteRoot) !== absoluteRoot) {
1188
+ throw new Error("workspace root has a symlinked path component");
1189
+ }
1190
+ const files = [];
1191
+ const capturedFiles = [];
1192
+ async function visit(directory) {
1193
+ const entries = await readdir(directory, { withFileTypes: true });
1194
+ entries.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
1195
+ for (const entry of entries) {
1196
+ if (directory === absoluteRoot && ignoredProtectedRootEntries.has(entry.name)) {
1197
+ continue;
1198
+ }
1199
+ const absolute = resolve(directory, entry.name);
1200
+ const relPath = relative(absoluteRoot, absolute).split(sep).join("/");
1201
+ if (!relPath || relPath.startsWith("../") || relPath.includes("/../")) {
1202
+ throw new Error(`workspace entry escapes root: ${relPath}`);
1203
+ }
1204
+ const stats = await lstat(absolute);
1205
+ if (stats.isSymbolicLink()) {
1206
+ throw new Error(`workspace contains a symlink: ${relPath}`);
1207
+ }
1208
+ if (stats.isDirectory()) {
1209
+ await visit(absolute);
1210
+ continue;
1211
+ }
1212
+ if (!stats.isFile()) {
1213
+ throw new Error(`workspace contains a non-regular entry: ${relPath}`);
1214
+ }
1215
+ const descriptor = await open(
1216
+ absolute,
1217
+ fsConstants.O_RDONLY | (typeof fsConstants.O_NOFOLLOW === "number" ? fsConstants.O_NOFOLLOW : 0)
1218
+ );
1219
+ try {
1220
+ const openedStats = await descriptor.stat();
1221
+ if (!openedStats.isFile()) {
1222
+ throw new Error(`workspace contains a non-regular entry: ${relPath}`);
1223
+ }
1224
+ if (openedStats.nlink !== 1) {
1225
+ throw new Error(`workspace contains a hard-linked file: ${relPath}`);
1226
+ }
1227
+ const mode = openedStats.mode & 511;
1228
+ if (mode !== 420 && mode !== 493) {
1229
+ throw new Error(`workspace file has unsupported mode ${mode.toString(8)}: ${relPath}`);
1230
+ }
1231
+ const bytes = await descriptor.readFile();
1232
+ const supportedMode = mode;
1233
+ files.push({
1234
+ path: relPath,
1235
+ mode: supportedMode,
1236
+ sha256: sha256Bytes(bytes),
1237
+ byteLength: bytes.byteLength
1238
+ });
1239
+ capturedFiles.push({ path: relPath, mode: supportedMode, bytes: Uint8Array.from(bytes) });
1240
+ } finally {
1241
+ await descriptor.close();
1242
+ }
1243
+ }
1244
+ }
1245
+ await visit(absoluteRoot);
1246
+ files.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
1247
+ capturedFiles.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
1248
+ return {
1249
+ manifest: {
1250
+ schemaVersion: 1,
1251
+ kind: "agent-candidate-workspace-manifest",
1252
+ files
1253
+ },
1254
+ files: capturedFiles
1255
+ };
1256
+ }
1257
+
1258
+ // src/candidate-execution/git-materialize.ts
1259
+ import { spawn } from "child_process";
1260
+ import { mkdir, mkdtemp, readFile as readFile2, realpath as realpath2, rm, stat } from "fs/promises";
1261
+ import { tmpdir } from "os";
1262
+ import { join, resolve as resolve2 } from "path";
1263
+ async function verifyCandidateCode(code, repositories, patchBytes) {
1264
+ if (code.kind === "disabled") return void 0;
1265
+ const repositoryRoot = await verifiedRepositoryRoot(code.repository, repositories);
1266
+ await assertCommitAndBaseTree(repositoryRoot, code.baseCommit, code.baseTree);
1267
+ if (code.kind === "no-op") {
1268
+ await assertSafeTree(repositoryRoot, code.baseTree);
1269
+ return code.baseTree;
1270
+ }
1271
+ if (!patchBytes) throw new Error("git-patch candidate is missing verified patch bytes");
1272
+ const temporary = await mkdtemp(join(tmpdir(), "agent-candidate-git-"));
1273
+ try {
1274
+ const indexFile = join(temporary, "index");
1275
+ await git(repositoryRoot, ["read-tree", code.baseTree], void 0, {
1276
+ GIT_INDEX_FILE: indexFile
1277
+ });
1278
+ await git(
1279
+ repositoryRoot,
1280
+ ["apply", "--cached", "--binary", "--whitespace=nowarn", "-"],
1281
+ patchBytes,
1282
+ { GIT_INDEX_FILE: indexFile }
1283
+ );
1284
+ const candidateTree = (await git(repositoryRoot, ["write-tree"], void 0, { GIT_INDEX_FILE: indexFile })).stdout.toString("utf8").trim();
1285
+ if (candidateTree !== code.candidateTree) {
1286
+ throw new Error(
1287
+ `git patch materialized tree ${candidateTree} does not match ${code.candidateTree}`
1288
+ );
1289
+ }
1290
+ await assertSafeTree(repositoryRoot, candidateTree);
1291
+ return candidateTree;
1292
+ } finally {
1293
+ await rm(temporary, { recursive: true, force: true });
1294
+ }
1295
+ }
1296
+ async function readCandidateGitHubResource(resource, repositories) {
1297
+ const repositoryRoot = await verifiedRepositoryRoot(resource.repository, repositories);
1298
+ const commitType = (await git(repositoryRoot, ["cat-file", "-t", resource.commit])).stdout.toString("utf8").trim();
1299
+ if (commitType !== "commit") {
1300
+ throw new Error(`GitHub resource commit is not a commit object: ${resource.commit}`);
1301
+ }
1302
+ const listing = (await git(repositoryRoot, ["ls-tree", "-z", resource.commit, "--", resource.path])).stdout;
1303
+ const entries = parseTreeEntries(listing);
1304
+ if (entries.length !== 1 || entries[0]?.path !== resource.path) {
1305
+ throw new Error(`GitHub resource path is not one exact file: ${resource.path}`);
1306
+ }
1307
+ const entry = entries[0];
1308
+ if (!entry || entry.type !== "blob" || entry.mode !== "100644" && entry.mode !== "100755") {
1309
+ throw new Error(`GitHub resource path is not a regular Git blob: ${resource.path}`);
1310
+ }
1311
+ const bytes = (await git(repositoryRoot, ["cat-file", "blob", entry.object])).stdout;
1312
+ verifyBytes(bytes, resource.sha256, resource.byteLength, `GitHub resource ${resource.path}`);
1313
+ return Uint8Array.from(bytes);
1314
+ }
1315
+ async function verifyTaskCheckout(taskRoot, expected) {
1316
+ const root = resolve2(taskRoot);
1317
+ const head = (await git(root, ["rev-parse", "HEAD"])).stdout.toString("utf8").trim();
1318
+ if (head !== expected.baseCommit) {
1319
+ throw new Error(`task checkout HEAD ${head} does not match ${expected.baseCommit}`);
1320
+ }
1321
+ const tree = (await git(root, ["rev-parse", "HEAD^{tree}"])).stdout.toString("utf8").trim();
1322
+ if (tree !== expected.baseTree) {
1323
+ throw new Error(`task checkout base tree ${tree} does not match ${expected.baseTree}`);
1324
+ }
1325
+ }
1326
+ async function verifyTaskOutcomePatch(input) {
1327
+ const repositoryRoot = resolve2(input.repositoryRoot);
1328
+ await verifyTaskCheckout(repositoryRoot, input);
1329
+ const gitDir = resolve2(
1330
+ (await git(repositoryRoot, ["rev-parse", "--absolute-git-dir"])).stdout.toString("utf8").trim()
1331
+ );
1332
+ if (await realpath2(gitDir) !== gitDir || gitDir.includes(":")) {
1333
+ throw new Error("task Git object store has an unsupported path");
1334
+ }
1335
+ await assertNoGitIndirection(repositoryRoot, gitDir, "task repository");
1336
+ const temporary = await mkdtemp(join(tmpdir(), "agent-candidate-task-outcome-"));
1337
+ try {
1338
+ const objectDirectory = join(temporary, "objects");
1339
+ const indexFile = join(temporary, "index");
1340
+ await mkdir(objectDirectory);
1341
+ const gitEnvironment = {
1342
+ GIT_INDEX_FILE: indexFile,
1343
+ GIT_OBJECT_DIRECTORY: objectDirectory,
1344
+ GIT_ALTERNATE_OBJECT_DIRECTORIES: join(gitDir, "objects")
1345
+ };
1346
+ await git(repositoryRoot, ["read-tree", input.baseTree], void 0, gitEnvironment);
1347
+ if (input.patch.byteLength > 0) {
1348
+ await git(
1349
+ repositoryRoot,
1350
+ ["apply", "--cached", "--binary", "--whitespace=nowarn", "-"],
1351
+ input.patch,
1352
+ gitEnvironment
1353
+ );
1354
+ }
1355
+ const resultTree = (await git(repositoryRoot, ["write-tree"], void 0, gitEnvironment)).stdout.toString("utf8").trim();
1356
+ if (resultTree !== input.resultTree) {
1357
+ throw new Error(
1358
+ `task outcome patch materialized tree ${resultTree} does not match ${input.resultTree}`
1359
+ );
1360
+ }
1361
+ await assertSafeTree(repositoryRoot, resultTree, gitEnvironment);
1362
+ const observed = await workspaceManifestFromGitTree(repositoryRoot, resultTree, gitEnvironment);
1363
+ if (!Buffer.from(canonicalCandidateBytes(observed)).equals(
1364
+ Buffer.from(canonicalCandidateBytes(input.afterState))
1365
+ )) {
1366
+ throw new Error("task outcome after-state does not match the materialized result tree");
1367
+ }
1368
+ const resultCommit = (await git(
1369
+ repositoryRoot,
1370
+ ["commit-tree", resultTree, "-p", input.baseCommit],
1371
+ Buffer.from("candidate task outcome\n", "utf8"),
1372
+ {
1373
+ ...gitEnvironment,
1374
+ GIT_AUTHOR_NAME: "Tangle Evaluator",
1375
+ GIT_AUTHOR_EMAIL: "evaluator@tangle.tools",
1376
+ GIT_AUTHOR_DATE: "2000-01-01T00:00:00Z",
1377
+ GIT_COMMITTER_NAME: "Tangle Evaluator",
1378
+ GIT_COMMITTER_EMAIL: "evaluator@tangle.tools",
1379
+ GIT_COMMITTER_DATE: "2000-01-01T00:00:00Z"
1380
+ }
1381
+ )).stdout.toString("utf8").trim();
1382
+ const committedTree = (await git(repositoryRoot, ["rev-parse", `${resultCommit}^{tree}`], void 0, gitEnvironment)).stdout.toString("utf8").trim();
1383
+ if (committedTree !== resultTree) {
1384
+ throw new Error("task outcome evaluator commit does not bind the verified result tree");
1385
+ }
1386
+ return { resultTree, resultCommit };
1387
+ } finally {
1388
+ await rm(temporary, { recursive: true, force: true });
1389
+ }
1390
+ }
1391
+ async function verifiedRepositoryRoot(repository, repositories) {
1392
+ const repositoryRoot = resolve2(await repositories.resolve(repository));
1393
+ const rootStats = await stat(repositoryRoot);
1394
+ if (!rootStats.isDirectory()) throw new Error("candidate repository path is not a directory");
1395
+ const origin = (await git(repositoryRoot, ["remote", "get-url", "origin"])).stdout.toString("utf8").trim();
1396
+ const actual = parseGitHubRemote(origin);
1397
+ if (!actual || actual.owner !== repository.owner || actual.repo !== repository.repo) {
1398
+ throw new Error(
1399
+ `local repository origin ${origin || "<missing>"} does not match github.com/${repository.owner}/${repository.repo}`
1400
+ );
1401
+ }
1402
+ const gitDirText = (await git(repositoryRoot, ["rev-parse", "--absolute-git-dir"])).stdout.toString("utf8").trim();
1403
+ const gitDir = resolve2(gitDirText);
1404
+ await assertNoGitIndirection(repositoryRoot, gitDir, "candidate repository");
1405
+ return repositoryRoot;
1406
+ }
1407
+ async function assertNoGitIndirection(repositoryRoot, gitDir, label) {
1408
+ const replacements = (await git(repositoryRoot, ["for-each-ref", "--format=%(refname)", "refs/replace"])).stdout.toString("utf8").trim();
1409
+ if (replacements) throw new Error(`${label} contains Git replace refs`);
1410
+ for (const name of ["alternates", "http-alternates"]) {
1411
+ const path = join(gitDir, "objects", "info", name);
1412
+ try {
1413
+ const contents = await readFile2(path, "utf8");
1414
+ if (contents.trim()) throw new Error(`${label} uses forbidden Git ${name}`);
1415
+ } catch (error) {
1416
+ if (!isNoEntry(error)) throw error;
1417
+ }
1418
+ }
1419
+ }
1420
+ async function assertCommitAndBaseTree(repositoryRoot, commit, expectedTree) {
1421
+ const type = (await git(repositoryRoot, ["cat-file", "-t", commit])).stdout.toString("utf8").trim();
1422
+ if (type !== "commit") throw new Error(`candidate base object is not a commit: ${commit}`);
1423
+ const actualTree = (await git(repositoryRoot, ["rev-parse", `${commit}^{tree}`])).stdout.toString("utf8").trim();
1424
+ if (actualTree !== expectedTree) {
1425
+ throw new Error(`candidate base commit tree ${actualTree} does not match ${expectedTree}`);
1426
+ }
1427
+ }
1428
+ async function assertSafeTree(repositoryRoot, tree, environment = {}) {
1429
+ const listing = (await git(repositoryRoot, ["ls-tree", "-rz", "--full-tree", tree], void 0, environment)).stdout;
1430
+ const entries = parseTreeEntries(listing);
1431
+ if (entries.length === 0) throw new Error("candidate Git tree cannot be empty");
1432
+ for (const entry of entries) {
1433
+ if (entry.type !== "blob" || entry.mode !== "100644" && entry.mode !== "100755") {
1434
+ throw new Error(
1435
+ `candidate Git tree contains a symlink, submodule, or non-blob: ${entry.path}`
1436
+ );
1437
+ }
1438
+ assertSafeGitPath(entry.path);
1439
+ }
1440
+ }
1441
+ async function workspaceManifestFromGitTree(repositoryRoot, tree, environment) {
1442
+ const listing = (await git(repositoryRoot, ["ls-tree", "-rz", "--full-tree", tree], void 0, environment)).stdout;
1443
+ const entries = parseTreeEntries(listing);
1444
+ const files = await Promise.all(
1445
+ entries.map(async (entry) => {
1446
+ if (entry.type !== "blob" || entry.mode !== "100644" && entry.mode !== "100755") {
1447
+ throw new Error(`task outcome tree contains a non-regular file: ${entry.path}`);
1448
+ }
1449
+ const bytes = (await git(repositoryRoot, ["cat-file", "blob", entry.object], void 0, environment)).stdout;
1450
+ return {
1451
+ path: entry.path,
1452
+ mode: entry.mode === "100755" ? 493 : 420,
1453
+ sha256: sha256Bytes(bytes),
1454
+ byteLength: bytes.byteLength
1455
+ };
1456
+ })
1457
+ );
1458
+ files.sort((left, right) => left.path.localeCompare(right.path));
1459
+ return {
1460
+ schemaVersion: 1,
1461
+ kind: "agent-candidate-workspace-manifest",
1462
+ files
1463
+ };
1464
+ }
1465
+ function parseTreeEntries(bytes) {
1466
+ const raw = Buffer.from(bytes);
1467
+ const decoded = raw.toString("utf8");
1468
+ if (!Buffer.from(decoded, "utf8").equals(raw)) {
1469
+ throw new Error("candidate Git tree contains a non-UTF-8 path");
1470
+ }
1471
+ const rows = decoded.split("\0").filter(Boolean);
1472
+ return rows.map((row) => {
1473
+ const tab = row.indexOf(" ");
1474
+ const header = row.slice(0, tab).split(" ");
1475
+ const path = row.slice(tab + 1);
1476
+ const [mode, type, object] = header;
1477
+ if (tab < 1 || !mode || !type || !object || !path) {
1478
+ throw new Error("malformed Git tree entry");
1479
+ }
1480
+ return { mode, type, object, path };
1481
+ });
1482
+ }
1483
+ function assertSafeGitPath(path) {
1484
+ if (!path || path.startsWith("/") || path.includes("\\") || path.includes("\0") || hasControlCharacter2(path) || path.split("/").some((part) => !part || part === "." || part === "..") || path.split("/")[0]?.toLowerCase() === ".git") {
1485
+ throw new Error(`candidate Git tree contains an unsafe path: ${path}`);
1486
+ }
1487
+ }
1488
+ function hasControlCharacter2(value) {
1489
+ for (let index = 0; index < value.length; index++) {
1490
+ const code = value.charCodeAt(index);
1491
+ if (code < 32 || code === 127) return true;
1492
+ }
1493
+ return false;
1494
+ }
1495
+ function parseGitHubRemote(value) {
1496
+ const match = value.match(
1497
+ /^(?:https?:\/\/github\.com\/|ssh:\/\/git@github\.com\/|git@github\.com:)([^/]+)\/([^/]+?)(?:\.git)?$/
1498
+ );
1499
+ if (!match?.[1] || !match[2]) return void 0;
1500
+ return { owner: match[1], repo: match[2] };
1501
+ }
1502
+ async function git(repositoryRoot, args, input, extraEnv = {}) {
1503
+ const env = Object.fromEntries(
1504
+ Object.entries(process.env).filter(([name]) => !name.startsWith("GIT_"))
1505
+ );
1506
+ Object.assign(env, {
1507
+ GIT_CONFIG_NOSYSTEM: "1",
1508
+ GIT_CONFIG_GLOBAL: "/dev/null",
1509
+ GIT_CONFIG_SYSTEM: "/dev/null",
1510
+ GIT_TERMINAL_PROMPT: "0",
1511
+ GIT_NO_REPLACE_OBJECTS: "1",
1512
+ LC_ALL: "C",
1513
+ ...extraEnv
1514
+ });
1515
+ const fullArgs = [
1516
+ "-c",
1517
+ "core.hooksPath=/dev/null",
1518
+ "-c",
1519
+ "protocol.file.allow=never",
1520
+ "-C",
1521
+ repositoryRoot,
1522
+ ...args
1523
+ ];
1524
+ return await new Promise((resolveResult, reject) => {
1525
+ const child = spawn("git", fullArgs, { env, stdio: ["pipe", "pipe", "pipe"] });
1526
+ const stdout = [];
1527
+ const stderr = [];
1528
+ child.stdout.on("data", (chunk) => stdout.push(chunk));
1529
+ child.stderr.on("data", (chunk) => stderr.push(chunk));
1530
+ child.on("error", reject);
1531
+ child.on("close", (code, signal) => {
1532
+ const out = Buffer.concat(stdout);
1533
+ const err = Buffer.concat(stderr);
1534
+ if (code !== 0) {
1535
+ reject(
1536
+ new Error(
1537
+ `git ${args[0] ?? "<command>"} failed (${signal ?? code}): ${err.toString("utf8").trim()}`
1538
+ )
1539
+ );
1540
+ return;
1541
+ }
1542
+ resolveResult({ stdout: out, stderr: err });
1543
+ });
1544
+ if (input) child.stdin.end(input);
1545
+ else child.stdin.end();
1546
+ });
1547
+ }
1548
+ function isNoEntry(error) {
1549
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
1550
+ }
1551
+
1552
+ // src/candidate-execution/prepared-state.ts
1553
+ var stateByExecution = /* @__PURE__ */ new WeakMap();
1554
+ var lifecycleByExecution = /* @__PURE__ */ new WeakMap();
1555
+ function createPreparedCandidateExecution(input) {
1556
+ const state = detachPreparedCandidateState(input);
1557
+ assertPrivateCandidateIntegrity(state);
1558
+ const prepared = Object.freeze({
1559
+ bundle: state.bundle,
1560
+ executionId: state.executionId,
1561
+ roots: state.roots,
1562
+ profilePlan: evidenceView(state.profilePlan),
1563
+ executionPlan: evidenceView(state.executionPlan),
1564
+ materializationReceipt: state.materializationReceipt,
1565
+ launch: state.launch,
1566
+ instruction: bytesView(state.instruction, "bytes"),
1567
+ resolvedModel: state.resolvedModel,
1568
+ ...state.knowledge ? { knowledge: knowledgeView(state.knowledge) } : {},
1569
+ trace: state.trace,
1570
+ memory: state.memory,
1571
+ [preparedCandidateBrand]: true
1572
+ });
1573
+ stateByExecution.set(prepared, state);
1574
+ lifecycleByExecution.set(prepared, { status: "prepared" });
1575
+ return prepared;
1576
+ }
1577
+ function getPreparedCandidateState(prepared) {
1578
+ const state = stateByExecution.get(prepared);
1579
+ if (!state || prepared[preparedCandidateBrand] !== true) {
1580
+ throw new Error("execution must come from prepareAgentCandidateExecution");
1581
+ }
1582
+ return state;
1583
+ }
1584
+ function assertPreparedCandidateIntegrity(prepared) {
1585
+ const state = getPreparedCandidateState(prepared);
1586
+ assertPrivateCandidateIntegrity(state);
1587
+ return state;
1588
+ }
1589
+ function beginPreparedCandidateClaim(prepared) {
1590
+ const state = assertPreparedCandidateIntegrity(prepared);
1591
+ transitionLifecycle(prepared, ["prepared"], "claiming");
1592
+ return state;
1593
+ }
1594
+ function beginPreparedCandidateDisposal(prepared) {
1595
+ const state = assertPreparedCandidateIntegrity(prepared);
1596
+ transitionLifecycle(prepared, ["prepared", "disposal-failed", "cleanup-failed"], "disposing");
1597
+ return state;
1598
+ }
1599
+ function markPreparedCandidateClaimed(prepared) {
1600
+ transitionLifecycle(prepared, ["claiming"], "claimed");
1601
+ }
1602
+ function beginPreparedCandidateRun(prepared, modelAccess, memoryAccess) {
1603
+ const state = assertPreparedCandidateIntegrity(prepared);
1604
+ assertProtectedEnvironment(state, modelAccess.env, memoryAccess?.env);
1605
+ transitionLifecycle(prepared, ["claimed"], "running");
1606
+ const completeEnvironment = immutableCandidateValue({
1607
+ ...state.launch.env,
1608
+ ...modelAccess.env,
1609
+ ...memoryAccess?.env ?? {},
1610
+ ...state.trace.env
1611
+ });
1612
+ const material = state.executionPlan.value.material;
1613
+ const request = Object.freeze({
1614
+ executionId: state.executionId,
1615
+ inputs: Object.freeze({
1616
+ task: workspaceInputView(material.task.workspace, state.executorInputs.taskFiles),
1617
+ ...material.candidateWorkspace && state.executorInputs.candidateFiles ? {
1618
+ candidate: workspaceInputView(
1619
+ material.candidateWorkspace,
1620
+ state.executorInputs.candidateFiles
1621
+ )
1622
+ } : {},
1623
+ profile: Object.freeze({
1624
+ files: Object.freeze(
1625
+ state.executorInputs.profileFiles.map((file) => profileFileView(file))
1626
+ )
1627
+ })
1628
+ }),
1629
+ roots: state.roots.execution,
1630
+ profilePlan: evidenceView(state.profilePlan),
1631
+ executionPlan: evidenceView(state.executionPlan),
1632
+ materializationReceipt: state.materializationReceipt,
1633
+ launch: immutableCandidateValue({ ...state.launch, env: completeEnvironment }),
1634
+ instruction: bytesView(state.instruction, "bytes"),
1635
+ resolvedModel: state.resolvedModel,
1636
+ hardLimits: Object.freeze({ timeoutMs: state.executionPlan.value.material.limits.timeoutMs }),
1637
+ observedLimits: Object.freeze({ maxSteps: state.executionPlan.value.material.limits.maxSteps }),
1638
+ ...state.knowledge ? { knowledge: knowledgeView(state.knowledge) } : {},
1639
+ trace: state.trace,
1640
+ memory: state.memory
1641
+ });
1642
+ return { state, request };
1643
+ }
1644
+ function consumePreparedCandidateExecution(prepared, outcome) {
1645
+ transitionLifecycle(
1646
+ prepared,
1647
+ outcome === "disposed" || outcome === "disposal-failed" ? ["disposing"] : ["settling"],
1648
+ outcome
1649
+ );
1650
+ }
1651
+ function beginPreparedCandidateSettlement(prepared) {
1652
+ transitionLifecycle(prepared, ["claiming", "claimed", "running"], "settling");
1653
+ }
1654
+ async function assertPreparedCandidateWorkspaces(state) {
1655
+ const plan = state.executionPlan.value.material;
1656
+ await verifyMaterializedWorkspace(state.roots.staging.taskRoot, plan.task.workspace.material, {
1657
+ ignoredProtectedRootEntries: [".git", ".sidecar"]
1658
+ });
1659
+ await verifyTaskCheckout(state.roots.staging.taskRoot, plan.task.repository);
1660
+ await verifyMaterializedProfileWorkspace(
1661
+ state.roots.staging.profileRoot,
1662
+ state.profilePlan.value.material
1663
+ );
1664
+ if (plan.candidateWorkspace) {
1665
+ const candidateRoot = state.roots.staging.candidateRoot;
1666
+ if (!candidateRoot) throw new Error("prepared candidate staging root is missing");
1667
+ await verifyMaterializedWorkspace(candidateRoot, plan.candidateWorkspace.material);
1668
+ } else if (state.roots.staging.candidateRoot !== void 0) {
1669
+ throw new Error("disabled candidate unexpectedly has a staging root");
1670
+ }
1671
+ }
1672
+ function detachPreparedCandidateState(input) {
1673
+ const profilePlan = immutableCandidateValue(
1674
+ agentCandidateProfilePlanEvidenceSchema.parse(input.profilePlan.value)
1675
+ );
1676
+ const executionPlan = immutableCandidateValue(
1677
+ agentCandidateExecutionPlanEvidenceSchema.parse(input.executionPlan.value)
1678
+ );
1679
+ const receiptValue = immutableCandidateValue(
1680
+ agentCandidateMaterializationReceiptSchema.parse(input.materializationReceipt.value)
1681
+ );
1682
+ const materializationReceipt = canonicalCandidateDocument(
1683
+ omitTopLevelDigest(receiptValue)
1684
+ );
1685
+ if (materializationReceipt.digest !== input.materializationReceipt.digest) {
1686
+ throw new Error("materialization receipt digest changed while sealing prepared execution");
1687
+ }
1688
+ return Object.freeze({
1689
+ ports: input.ports,
1690
+ bundle: input.bundle,
1691
+ executionId: input.executionId,
1692
+ roots: immutableCandidateValue(input.roots),
1693
+ profilePlan: Object.freeze({
1694
+ value: profilePlan,
1695
+ bytes: Uint8Array.from(input.profilePlan.bytes),
1696
+ written: Object.freeze([...input.profilePlan.written])
1697
+ }),
1698
+ executionPlan: Object.freeze({
1699
+ value: executionPlan,
1700
+ bytes: Uint8Array.from(input.executionPlan.bytes)
1701
+ }),
1702
+ materializationReceipt,
1703
+ launch: immutableCandidateValue(input.launch),
1704
+ instruction: Object.freeze({
1705
+ bytes: Uint8Array.from(input.instruction.bytes),
1706
+ delivery: immutableCandidateValue(input.instruction.delivery)
1707
+ }),
1708
+ resolvedModel: immutableCandidateValue(input.resolvedModel),
1709
+ preparationId: input.preparationId,
1710
+ reservationExpiresAtMs: input.reservationExpiresAtMs,
1711
+ cleanupTimeoutMs: input.cleanupTimeoutMs,
1712
+ resultTimeoutMs: input.resultTimeoutMs,
1713
+ modelReservation: immutableCandidateValue(input.modelReservation),
1714
+ executorInputs: Object.freeze({
1715
+ taskFiles: immutableExecutorFiles(input.executorInputs.taskFiles),
1716
+ ...input.executorInputs.candidateFiles ? { candidateFiles: immutableExecutorFiles(input.executorInputs.candidateFiles) } : {},
1717
+ profileFiles: Object.freeze(
1718
+ input.executorInputs.profileFiles.map(
1719
+ (file) => Object.freeze({ ...file, bytes: Uint8Array.from(file.bytes) })
1720
+ )
1721
+ )
1722
+ }),
1723
+ ...input.memoryReservation ? { memoryReservation: immutableCandidateValue(input.memoryReservation) } : {},
1724
+ ...input.knowledge ? {
1725
+ knowledge: Object.freeze({
1726
+ snapshotId: input.knowledge.snapshotId,
1727
+ manifestDigest: input.knowledge.manifestDigest,
1728
+ manifest: Uint8Array.from(input.knowledge.manifest)
1729
+ })
1730
+ } : {},
1731
+ trace: immutableCandidateValue(input.trace),
1732
+ memory: immutableCandidateValue(input.memory)
1733
+ });
1734
+ }
1735
+ function assertPrivateCandidateIntegrity(state) {
1736
+ const bundleMaterial = omitTopLevelDigest(state.bundle);
1737
+ if (canonicalCandidateDigest(bundleMaterial) !== state.bundle.digest) {
1738
+ throw new Error("prepared candidate bundle no longer matches its digest");
1739
+ }
1740
+ assertPlanEvidence(state.profilePlan.value, state.profilePlan.bytes, "profile plan");
1741
+ assertPlanEvidence(state.executionPlan.value, state.executionPlan.bytes, "execution plan");
1742
+ agentCandidateExecutionPlanEvidenceSchema.parse(state.executionPlan.value);
1743
+ const receipt = agentCandidateMaterializationReceiptSchema.parse(
1744
+ state.materializationReceipt.value
1745
+ );
1746
+ const receiptBytes = canonicalCandidateBytes(omitTopLevelDigest(receipt));
1747
+ if (canonicalCandidateDigest(omitTopLevelDigest(receipt)) !== state.materializationReceipt.digest || !Buffer.from(receiptBytes).equals(Buffer.from(state.materializationReceipt.bytes))) {
1748
+ throw new Error("prepared materialization receipt no longer matches its canonical bytes");
1749
+ }
1750
+ const instruction = state.executionPlan.value.material.task.instruction;
1751
+ if (sha256Bytes(state.instruction.bytes) !== instruction.sha256 || state.instruction.bytes.byteLength !== instruction.byteLength || JSON.stringify(state.instruction.delivery) !== JSON.stringify(instruction.delivery)) {
1752
+ throw new Error("prepared instruction no longer matches the signed execution plan");
1753
+ }
1754
+ if (!/^candidate-preparation-v1\.[A-Za-z0-9_-]{43}$/.test(state.preparationId) || !Number.isSafeInteger(state.reservationExpiresAtMs) || state.reservationExpiresAtMs <= 0 || !Number.isSafeInteger(state.cleanupTimeoutMs) || state.cleanupTimeoutMs <= 0 || !Number.isSafeInteger(state.resultTimeoutMs) || state.resultTimeoutMs <= 0 || JSON.stringify(state.resolvedModel) !== JSON.stringify(state.executionPlan.value.material.model.resolved) || state.modelReservation.digest !== state.executionPlan.value.material.model.access.grantDigest || state.modelReservation.preparationId !== state.preparationId || state.modelReservation.expiresAtMs !== state.reservationExpiresAtMs || canonicalCandidateDigest(state.modelReservation.network) !== canonicalCandidateDigest(state.executionPlan.value.material.model.access.network) || canonicalCandidateDigest(state.modelReservation.enforcedLimits) !== canonicalCandidateDigest(modelLimits(state.executionPlan.value.material.limits))) {
1755
+ throw new Error("prepared model access no longer matches the signed execution plan");
1756
+ }
1757
+ assertExecutorInputs(state);
1758
+ if (state.memory.mode === "isolated" && !state.memoryReservation || state.memory.mode === "disabled" && state.memoryReservation) {
1759
+ throw new Error("prepared memory reservation does not match the signed execution plan");
1760
+ }
1761
+ if (state.memory.mode === "isolated" && state.memoryReservation && (state.memoryReservation.preparationId !== state.preparationId || state.memoryReservation.expiresAtMs !== state.reservationExpiresAtMs || state.memoryReservation.effectiveNamespace !== state.memory.effectiveNamespace)) {
1762
+ throw new Error("prepared memory reservation identity no longer matches the execution");
1763
+ }
1764
+ if (JSON.stringify(state.memory) !== JSON.stringify(state.executionPlan.value.material.memory)) {
1765
+ throw new Error("prepared memory no longer matches the signed execution plan");
1766
+ }
1767
+ const expectedTags = {
1768
+ [CANDIDATE_TRACE_TAGS.executionId]: state.executionId,
1769
+ [CANDIDATE_TRACE_TAGS.bundleDigest]: state.bundle.digest,
1770
+ [CANDIDATE_TRACE_TAGS.executionPlanDigest]: state.executionPlan.value.digest,
1771
+ [CANDIDATE_TRACE_TAGS.materializationReceiptDigest]: state.materializationReceipt.digest
1772
+ };
1773
+ const expectedTraceEnvironment = {
1774
+ [CANDIDATE_TRACE_ENV.executionId]: state.executionId,
1775
+ [CANDIDATE_TRACE_ENV.bundleDigest]: state.bundle.digest,
1776
+ [CANDIDATE_TRACE_ENV.executionPlanDigest]: state.executionPlan.value.digest,
1777
+ [CANDIDATE_TRACE_ENV.materializationReceiptDigest]: state.materializationReceipt.digest,
1778
+ [CANDIDATE_TRACE_ENV.traceRunId]: state.trace.runId
1779
+ };
1780
+ if (!state.trace.runId.startsWith(
1781
+ `${state.executionId}:attempt-${state.executionPlan.value.material.attempt.number}:`
1782
+ ) || canonicalCandidateDigest(state.trace.tags) !== canonicalCandidateDigest(expectedTags) || canonicalCandidateDigest(state.trace.env) !== canonicalCandidateDigest(expectedTraceEnvironment)) {
1783
+ throw new Error("prepared trace identity no longer matches the signed execution");
1784
+ }
1785
+ }
1786
+ function assertPlanEvidence(evidence, bytes, label) {
1787
+ const expected = canonicalCandidateBytes(evidence.material);
1788
+ if (sha256Bytes(expected) !== evidence.digest || !Buffer.from(expected).equals(Buffer.from(bytes)) || evidence.artifact.sha256 !== evidence.digest || evidence.artifact.byteLength !== bytes.byteLength || !("content" in evidence.artifact) || !Buffer.from(evidence.artifact.content, "base64").equals(Buffer.from(bytes))) {
1789
+ throw new Error(`prepared ${label} no longer matches its canonical bytes`);
1790
+ }
1791
+ }
1792
+ function evidenceView(evidence) {
1793
+ const bytes = Uint8Array.from(evidence.bytes);
1794
+ return Object.freeze({
1795
+ ...evidence,
1796
+ get bytes() {
1797
+ return Uint8Array.from(bytes);
1798
+ }
1799
+ });
1800
+ }
1801
+ function bytesView(value, key) {
1802
+ const bytes = Uint8Array.from(value.bytes);
1803
+ return Object.freeze({
1804
+ ...value,
1805
+ get [key]() {
1806
+ return Uint8Array.from(bytes);
1807
+ }
1808
+ });
1809
+ }
1810
+ function knowledgeView(knowledge) {
1811
+ const manifest = Uint8Array.from(knowledge.manifest);
1812
+ return Object.freeze({
1813
+ snapshotId: knowledge.snapshotId,
1814
+ manifestDigest: knowledge.manifestDigest,
1815
+ get manifest() {
1816
+ return Uint8Array.from(manifest);
1817
+ }
1818
+ });
1819
+ }
1820
+ function workspaceInputView(snapshot, sourceFiles) {
1821
+ return Object.freeze({
1822
+ snapshot,
1823
+ files: Object.freeze(sourceFiles.map((file) => profileFileView(file)))
1824
+ });
1825
+ }
1826
+ function profileFileView(source) {
1827
+ const bytes = Uint8Array.from(source.bytes);
1828
+ return Object.freeze({
1829
+ path: source.path,
1830
+ mode: source.mode,
1831
+ get bytes() {
1832
+ return Uint8Array.from(bytes);
1833
+ }
1834
+ });
1835
+ }
1836
+ function assertExecutorInputs(state) {
1837
+ const material = state.executionPlan.value.material;
1838
+ assertWorkspaceExecutorFiles(state.executorInputs.taskFiles, material.task.workspace.material);
1839
+ if (material.candidateWorkspace) {
1840
+ if (!state.executorInputs.candidateFiles) {
1841
+ throw new Error("prepared candidate executor files are missing");
1842
+ }
1843
+ assertWorkspaceExecutorFiles(
1844
+ state.executorInputs.candidateFiles,
1845
+ material.candidateWorkspace.material
1846
+ );
1847
+ } else if (state.executorInputs.candidateFiles) {
1848
+ throw new Error("disabled candidate has executor files");
1849
+ }
1850
+ const expectedFiles = state.profilePlan.value.material.files;
1851
+ if (state.executorInputs.profileFiles.length !== expectedFiles.length) {
1852
+ throw new Error("prepared profile executor files do not match the signed profile plan");
1853
+ }
1854
+ for (let index = 0; index < expectedFiles.length; index++) {
1855
+ const expected = expectedFiles[index];
1856
+ const actual = state.executorInputs.profileFiles[index];
1857
+ if (!expected || !actual || actual.path !== expected.relPath || actual.mode !== expected.mode || sha256Bytes(actual.bytes) !== expected.contentSha256) {
1858
+ throw new Error("prepared profile executor files do not match the signed profile plan");
1859
+ }
1860
+ }
1861
+ }
1862
+ function assertWorkspaceExecutorFiles(actualFiles, expected) {
1863
+ if (actualFiles.length !== expected.files.length) {
1864
+ throw new Error("prepared workspace executor files do not match the signed manifest");
1865
+ }
1866
+ for (let index = 0; index < expected.files.length; index++) {
1867
+ const actual = actualFiles[index];
1868
+ const planned = expected.files[index];
1869
+ if (!actual || !planned || actual.path !== planned.path || actual.mode !== planned.mode || actual.bytes.byteLength !== planned.byteLength || sha256Bytes(actual.bytes) !== planned.sha256) {
1870
+ throw new Error("prepared workspace executor files do not match the signed manifest");
1871
+ }
1872
+ }
1873
+ }
1874
+ function immutableExecutorFiles(files) {
1875
+ return Object.freeze(
1876
+ files.map((file) => Object.freeze({ ...file, bytes: Uint8Array.from(file.bytes) }))
1877
+ );
1878
+ }
1879
+ function modelLimits(limits) {
1880
+ return {
1881
+ maxModelCalls: limits.maxModelCalls,
1882
+ maxInputTokens: limits.maxInputTokens,
1883
+ maxOutputTokens: limits.maxOutputTokens,
1884
+ maxCostUsd: limits.maxCostUsd
1885
+ };
1886
+ }
1887
+ function transitionLifecycle(prepared, expected, next) {
1888
+ const lifecycle = lifecycleByExecution.get(prepared);
1889
+ if (!lifecycle || !expected.includes(lifecycle.status)) {
1890
+ throw new Error(`prepared candidate execution is already ${lifecycle?.status ?? "unknown"}`);
1891
+ }
1892
+ lifecycle.status = next;
1893
+ }
1894
+ function assertProtectedEnvironment(state, modelEnvironment, memoryEnvironment) {
1895
+ const seen = /* @__PURE__ */ new Set([...Object.keys(state.launch.env), ...Object.keys(state.trace.env)]);
1896
+ for (const [name, value] of [
1897
+ ...Object.entries(modelEnvironment),
1898
+ ...Object.entries(memoryEnvironment ?? {})
1899
+ ]) {
1900
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name) || typeof value !== "string" || value.length < 8) {
1901
+ throw new Error("protected model activation contains an invalid environment binding");
1902
+ }
1903
+ if (seen.has(name)) {
1904
+ throw new Error(`protected model activation collides with environment binding ${name}`);
1905
+ }
1906
+ seen.add(name);
1907
+ }
1908
+ }
1909
+
1910
+ // src/candidate-execution/claim-plan.ts
1911
+ function candidateExecutionClaim(prepared) {
1912
+ const state = assertPreparedCandidateIntegrity(prepared);
1913
+ const material = prepared.executionPlan.value.material;
1914
+ const attempt = material.attempt;
1915
+ const nowMs = Date.now();
1916
+ if (!Number.isSafeInteger(nowMs) || nowMs < 0) {
1917
+ throw new Error("candidate execution claim-store clock returned an invalid timestamp");
1918
+ }
1919
+ const leaseExpiresAtMs = nowMs + candidateExecutionOwnerWindowMs(
1920
+ material.limits.timeoutMs,
1921
+ state.cleanupTimeoutMs,
1922
+ state.resultTimeoutMs
1923
+ );
1924
+ if (!Number.isSafeInteger(leaseExpiresAtMs) || leaseExpiresAtMs <= 0) {
1925
+ throw new Error("candidate execution leaseExpiresAtMs must be a positive safe timestamp");
1926
+ }
1927
+ if (leaseExpiresAtMs > state.reservationExpiresAtMs) {
1928
+ throw new Error(
1929
+ "candidate preparation expires before its full execution and cleanup owner window"
1930
+ );
1931
+ }
1932
+ return candidateClaimFileInternals.sealClaim({
1933
+ executionId: prepared.executionId,
1934
+ attempt: attempt.number,
1935
+ maxAttempts: attempt.maxAttempts,
1936
+ retryPolicy: attempt.retryPolicy,
1937
+ bundleDigest: prepared.bundle.digest,
1938
+ executionPlanDigest: prepared.executionPlan.value.digest,
1939
+ retryLineageDigest: retryLineageDigest(prepared, state.resultTimeoutMs),
1940
+ leaseExpiresAtMs,
1941
+ resultTimeoutMs: state.resultTimeoutMs,
1942
+ cleanup: {
1943
+ preparationId: state.preparationId,
1944
+ modelGrantDigest: state.modelReservation.digest,
1945
+ resolvedModel: state.resolvedModel,
1946
+ traceRunId: state.trace.runId,
1947
+ cleanupTimeoutMs: state.cleanupTimeoutMs,
1948
+ ...state.memoryReservation ? {
1949
+ memory: {
1950
+ accessDigest: state.memoryReservation.accessDigest,
1951
+ effectiveNamespace: state.memoryReservation.effectiveNamespace
1952
+ }
1953
+ } : {}
1954
+ }
1955
+ });
1956
+ }
1957
+ function retryLineageDigest(prepared, resultTimeoutMs) {
1958
+ const material = prepared.executionPlan.value.material;
1959
+ return canonicalCandidateDigest({
1960
+ resultTimeoutMs,
1961
+ executionPlan: {
1962
+ ...material,
1963
+ attempt: { ...material.attempt, number: 0 },
1964
+ model: {
1965
+ ...material.model,
1966
+ access: {
1967
+ ...material.model.access,
1968
+ grantDigest: `sha256:${"0".repeat(64)}`
1969
+ }
1970
+ },
1971
+ memory: material.memory.mode === "disabled" ? material.memory : {
1972
+ mode: "isolated",
1973
+ scope: "task",
1974
+ effectiveNamespace: "candidate/retry-lineage-normalized",
1975
+ reset: {
1976
+ kind: "fresh",
1977
+ emptyStateDigest: material.memory.reset.emptyStateDigest
1978
+ },
1979
+ beforeState: {
1980
+ digest: material.memory.beforeState.digest,
1981
+ material: material.memory.beforeState.material,
1982
+ manifest: {
1983
+ sha256: material.memory.beforeState.manifest.sha256,
1984
+ byteLength: material.memory.beforeState.manifest.byteLength
1985
+ },
1986
+ archive: {
1987
+ sha256: material.memory.beforeState.archive.sha256,
1988
+ byteLength: material.memory.beforeState.archive.byteLength
1989
+ }
1990
+ },
1991
+ ...material.memory.seedDigest ? { seedDigest: material.memory.seedDigest } : {}
1992
+ }
1993
+ }
1994
+ });
1995
+ }
1996
+
1997
+ // src/candidate-execution/output-artifacts.ts
1998
+ import {
1999
+ agentCandidateArtifactRefSchema as agentCandidateArtifactRefSchema2
2000
+ } from "@tangle-network/agent-interface";
2001
+ async function persistCandidateOutputArtifact(port, input) {
2002
+ input.signal?.throwIfAborted();
2003
+ const bytes = Uint8Array.from(input.bytes);
2004
+ const expectedDigest = sha256Bytes(bytes);
2005
+ const ref = agentCandidateArtifactRefSchema2.parse(
2006
+ await port.put({
2007
+ executionId: input.executionId,
2008
+ purpose: input.purpose,
2009
+ bytes: Uint8Array.from(bytes),
2010
+ ...input.signal ? { signal: input.signal } : {}
2011
+ })
2012
+ );
2013
+ input.signal?.throwIfAborted();
2014
+ if (ref.sha256 !== expectedDigest || ref.byteLength !== bytes.byteLength) {
2015
+ throw new Error("candidate output locator does not identify the submitted bytes");
2016
+ }
2017
+ const stored = await port.read(ref);
2018
+ input.signal?.throwIfAborted();
2019
+ verifyBytes(stored, expectedDigest, bytes.byteLength, "persisted candidate output");
2020
+ return immutableCandidateValue(ref);
2021
+ }
2022
+
2023
+ // src/candidate-execution/executor-capture.ts
2024
+ import {
2025
+ agentCandidateTerminationSchema,
2026
+ agentCandidateWorkspaceManifestMaterialSchema
2027
+ } from "@tangle-network/agent-interface";
2028
+ function sealAgentCandidateProtectedRunCapture(value) {
2029
+ const capture = requireRecord(value, "candidate execution capture");
2030
+ assertExactObjectKeys(capture, ["executionId", "termination"], "candidate execution capture");
2031
+ if (typeof capture.executionId !== "string" || capture.executionId.length === 0) {
2032
+ throw new Error("candidate execution capture has an invalid executionId");
2033
+ }
2034
+ return Object.freeze({
2035
+ executionId: capture.executionId,
2036
+ termination: Object.freeze(agentCandidateTerminationSchema.parse(capture.termination))
2037
+ });
2038
+ }
2039
+ function sealAgentCandidateExecutorFinalCapture(value) {
2040
+ const capture = requireRecord(value, "candidate final capture");
2041
+ assertExactObjectKeys(capture, ["stopped"], "candidate final capture", ["taskOutcome", "memoryAfter"]);
2042
+ if (capture.stopped !== true) {
2043
+ throw new Error("candidate final capture does not prove process death");
2044
+ }
2045
+ const taskOutcome = capture.taskOutcome ? sealTaskOutcomeCapture(capture.taskOutcome) : void 0;
2046
+ const memoryAfter = capture.memoryAfter ? sealMemoryCapture(capture.memoryAfter) : void 0;
2047
+ return Object.freeze({
2048
+ stopped: true,
2049
+ ...taskOutcome ? { taskOutcome } : {},
2050
+ ...memoryAfter ? { memoryAfter: Object.freeze(memoryAfter) } : {}
2051
+ });
2052
+ }
2053
+ function sealMemoryCapture(value) {
2054
+ const capture = requireRecord(value, "candidate memory capture");
2055
+ assertExactObjectKeys(capture, ["afterState", "archive"], "candidate memory capture");
2056
+ if (!(capture.archive instanceof Uint8Array)) {
2057
+ throw new Error("candidate memory capture archive must be a byte array");
2058
+ }
2059
+ return Object.freeze({
2060
+ afterState: Object.freeze(
2061
+ agentCandidateWorkspaceManifestMaterialSchema.parse(capture.afterState)
2062
+ ),
2063
+ archive: Uint8Array.from(capture.archive)
2064
+ });
2065
+ }
2066
+ function sealTaskOutcomeCapture(value) {
2067
+ const capture = requireRecord(value, "candidate task capture");
2068
+ assertExactObjectKeys(
2069
+ capture,
2070
+ ["resultTree", "afterState", "archive", "gitDiff"],
2071
+ "candidate task capture"
2072
+ );
2073
+ if (typeof capture.resultTree !== "string" || !/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(capture.resultTree)) {
2074
+ throw new Error("candidate task capture resultTree is not a Git object id");
2075
+ }
2076
+ if (!(capture.archive instanceof Uint8Array) || !(capture.gitDiff instanceof Uint8Array)) {
2077
+ throw new Error("candidate task capture archive and gitDiff must be byte arrays");
2078
+ }
2079
+ const afterState = agentCandidateWorkspaceManifestMaterialSchema.parse(capture.afterState);
2080
+ return Object.freeze({
2081
+ resultTree: capture.resultTree,
2082
+ afterState: Object.freeze(afterState),
2083
+ archive: Uint8Array.from(capture.archive),
2084
+ gitDiff: Uint8Array.from(capture.gitDiff)
2085
+ });
2086
+ }
2087
+ function requireRecord(value, label) {
2088
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
2089
+ throw new Error(`${label} must be an object`);
2090
+ }
2091
+ return value;
2092
+ }
2093
+
2094
+ // src/candidate-execution/finalize.ts
2095
+ import { mkdtemp as mkdtemp2, rm as rm2 } from "fs/promises";
2096
+ import { tmpdir as tmpdir2 } from "os";
2097
+ import { join as join2 } from "path";
2098
+ import { isLlmSpan as isLlmSpan2, REDACTION_VERSION as REDACTION_VERSION2 } from "@tangle-network/agent-eval";
2099
+ import {
2100
+ agentCandidateRunReceiptV2Schema,
2101
+ agentCandidateWorkspaceSnapshotEvidenceSchema
2102
+ } from "@tangle-network/agent-interface";
2103
+
2104
+ // src/candidate-execution/model-settlement.ts
2105
+ import { isLlmSpan } from "@tangle-network/agent-eval";
2106
+ var USD_NANOS = 1e9;
2107
+ function sealAgentCandidateModelSettlement(settlement, expected) {
2108
+ assertExactObjectKeys(
2109
+ settlement,
2110
+ ["preparationId", "grantDigest", "closed", "calls"],
2111
+ "model settlement"
2112
+ );
2113
+ if (settlement.closed !== true) throw new Error("protected model grant is not closed");
2114
+ if (settlement.grantDigest !== expected.grantDigest) {
2115
+ throw new Error("protected model settlement grant digest does not match the reservation");
2116
+ }
2117
+ if (settlement.preparationId !== expected.preparationId) {
2118
+ throw new Error("protected model settlement preparation does not match the reservation");
2119
+ }
2120
+ if (!Array.isArray(settlement.calls)) {
2121
+ throw new Error("protected model settlement calls must be an array");
2122
+ }
2123
+ const callIds = /* @__PURE__ */ new Set();
2124
+ const spanIds = /* @__PURE__ */ new Set();
2125
+ let inputTokens = 0;
2126
+ let outputTokens = 0;
2127
+ let cachedInputTokens = 0;
2128
+ let reasoningTokens = 0;
2129
+ let hasCachedInput = false;
2130
+ let costUsdNanos = 0;
2131
+ const calls = settlement.calls.map((source, index) => {
2132
+ assertExactObjectKeys(
2133
+ source,
2134
+ [
2135
+ "callId",
2136
+ "generationId",
2137
+ "traceSpanId",
2138
+ "status",
2139
+ "model",
2140
+ "startedAtMs",
2141
+ "endedAtMs",
2142
+ "inputTokens",
2143
+ "outputTokens",
2144
+ "cachedInputTokens",
2145
+ "reasoningTokens",
2146
+ "costUsdNanos"
2147
+ ],
2148
+ `model settlement call ${index}`
2149
+ );
2150
+ assertIdentifier(source.callId, `model settlement call ${index} callId`);
2151
+ assertIdentifier(source.generationId, `model settlement call ${index} generationId`);
2152
+ assertIdentifier(source.traceSpanId, `model settlement call ${index} traceSpanId`);
2153
+ if (source.traceSpanId !== source.generationId) {
2154
+ throw new Error(`model settlement call ${index} traceSpanId is not its router generationId`);
2155
+ }
2156
+ if (source.status !== "succeeded" && source.status !== "failed") {
2157
+ throw new Error(`model settlement call ${index} has an invalid status`);
2158
+ }
2159
+ if (callIds.has(source.callId))
2160
+ throw new Error("protected model settlement has duplicate call ids");
2161
+ if (spanIds.has(source.traceSpanId)) {
2162
+ throw new Error("protected model settlement has duplicate trace span ids");
2163
+ }
2164
+ callIds.add(source.callId);
2165
+ spanIds.add(source.traceSpanId);
2166
+ if (source.model !== expected.model) {
2167
+ throw new Error(`protected model settlement call ${index} has an unexpected model`);
2168
+ }
2169
+ assertTimestamp(source.startedAtMs, `model settlement call ${index} startedAtMs`);
2170
+ assertTimestamp(source.endedAtMs, `model settlement call ${index} endedAtMs`);
2171
+ if (source.endedAtMs < source.startedAtMs) {
2172
+ throw new Error(`model settlement call ${index} ended before it started`);
2173
+ }
2174
+ assertCount2(source.inputTokens, `model settlement call ${index} inputTokens`);
2175
+ assertCount2(source.outputTokens, `model settlement call ${index} outputTokens`);
2176
+ assertCount2(source.cachedInputTokens, `model settlement call ${index} cachedInputTokens`);
2177
+ cachedInputTokens = safeAdd(
2178
+ cachedInputTokens,
2179
+ source.cachedInputTokens,
2180
+ "cached input token total"
2181
+ );
2182
+ hasCachedInput = true;
2183
+ assertCount2(source.reasoningTokens, `model settlement call ${index} reasoningTokens`);
2184
+ reasoningTokens = safeAdd(reasoningTokens, source.reasoningTokens, "reasoning token total");
2185
+ assertCount2(source.costUsdNanos, `model settlement call ${index} costUsdNanos`);
2186
+ inputTokens = safeAdd(inputTokens, source.inputTokens, "input token total");
2187
+ outputTokens = safeAdd(outputTokens, source.outputTokens, "output token total");
2188
+ costUsdNanos = safeAdd(costUsdNanos, source.costUsdNanos, "cost total");
2189
+ return Object.freeze({ ...source });
2190
+ });
2191
+ const usage = Object.freeze({
2192
+ costUsd: costUsdNanos / USD_NANOS,
2193
+ inputTokens,
2194
+ outputTokens,
2195
+ ...hasCachedInput ? { cachedInputTokens } : {},
2196
+ modelCalls: calls.length
2197
+ });
2198
+ const fixedUsage = Object.freeze({
2199
+ costUsdNanos,
2200
+ inputTokens,
2201
+ outputTokens,
2202
+ cachedInputTokens,
2203
+ reasoningTokens,
2204
+ modelCalls: calls.length
2205
+ });
2206
+ return Object.freeze({
2207
+ value: Object.freeze({
2208
+ preparationId: settlement.preparationId,
2209
+ grantDigest: settlement.grantDigest,
2210
+ closed: true,
2211
+ calls: Object.freeze(calls)
2212
+ }),
2213
+ usage,
2214
+ fixedUsage,
2215
+ costUsdNanos
2216
+ });
2217
+ }
2218
+ async function appendAuthoritativeModelSettlementSpans(traceStore, runId, settlement) {
2219
+ const run = await traceStore.getRun(runId);
2220
+ if (!run) throw new Error(`protected trace run is missing before model settlement: ${runId}`);
2221
+ if (run.status === "running" || run.endedAt === void 0) {
2222
+ throw new Error("protected trace run must be terminal before model spans are appended");
2223
+ }
2224
+ const existing = await traceStore.spans({ runId });
2225
+ if (existing.some(isLlmSpan)) {
2226
+ throw new Error(
2227
+ "protected trace contains a model span not authored from the closed router ledger"
2228
+ );
2229
+ }
2230
+ const occupiedIds = new Set(existing.map((span) => span.spanId));
2231
+ for (const call of settlement.value.calls) {
2232
+ if (occupiedIds.has(call.traceSpanId)) {
2233
+ throw new Error(
2234
+ `protected trace span identity collides with router generation ${call.generationId}`
2235
+ );
2236
+ }
2237
+ await traceStore.appendSpan({
2238
+ runId,
2239
+ spanId: call.traceSpanId,
2240
+ kind: "llm",
2241
+ name: "protected model call",
2242
+ model: call.model,
2243
+ messages: [],
2244
+ startedAt: call.startedAtMs,
2245
+ endedAt: call.endedAtMs,
2246
+ status: call.status === "succeeded" ? "ok" : "error",
2247
+ inputTokens: call.inputTokens,
2248
+ outputTokens: call.outputTokens,
2249
+ cachedTokens: call.cachedInputTokens,
2250
+ reasoningTokens: call.reasoningTokens,
2251
+ costUsd: call.costUsdNanos / USD_NANOS,
2252
+ attributes: {
2253
+ "tangle.protected_model.source": "router-settlement",
2254
+ "tangle.router.call_id": call.callId,
2255
+ "tangle.router.generation_id": call.generationId
2256
+ }
2257
+ });
2258
+ }
2259
+ }
2260
+ function assertTraceMatchesModelSettlement(spans, settlement) {
2261
+ if (spans.length !== settlement.value.calls.length) {
2262
+ throw new Error(
2263
+ `protected trace model calls ${spans.length} do not match model ledger ${settlement.value.calls.length}`
2264
+ );
2265
+ }
2266
+ const byId = new Map(spans.map((span) => [span.spanId, span]));
2267
+ if (byId.size !== spans.length) throw new Error("protected trace has duplicate model span ids");
2268
+ for (const call of settlement.value.calls) {
2269
+ const span = byId.get(call.traceSpanId);
2270
+ if (!span) {
2271
+ throw new Error(`protected trace is missing model ledger span ${call.traceSpanId}`);
2272
+ }
2273
+ assertTraceCall(span, call);
2274
+ }
2275
+ }
2276
+ function usdToNanos(value, label) {
2277
+ if (!Number.isFinite(value) || value < 0) throw new Error(`${label} must be nonnegative`);
2278
+ const nanos = Math.round(value * USD_NANOS);
2279
+ if (!Number.isSafeInteger(nanos)) throw new Error(`${label} exceeds fixed-point range`);
2280
+ return nanos;
2281
+ }
2282
+ function assertTraceCall(span, call) {
2283
+ if (span.model !== call.model) {
2284
+ throw new Error(`protected trace span ${span.spanId} model does not match model ledger`);
2285
+ }
2286
+ if (span.startedAt !== call.startedAtMs || span.endedAt !== call.endedAtMs || span.status !== (call.status === "succeeded" ? "ok" : "error")) {
2287
+ throw new Error(
2288
+ `protected trace span ${span.spanId} timing or status does not match model ledger`
2289
+ );
2290
+ }
2291
+ if (span.attributes?.["tangle.protected_model.source"] !== "router-settlement" || span.attributes?.["tangle.router.call_id"] !== call.callId || span.attributes?.["tangle.router.generation_id"] !== call.generationId) {
2292
+ throw new Error(`protected trace span ${span.spanId} lacks router settlement provenance`);
2293
+ }
2294
+ for (const [name, traced, settled] of [
2295
+ ["inputTokens", span.inputTokens, call.inputTokens],
2296
+ ["outputTokens", span.outputTokens, call.outputTokens],
2297
+ ["cachedInputTokens", span.cachedTokens ?? 0, call.cachedInputTokens],
2298
+ ["reasoningTokens", span.reasoningTokens ?? 0, call.reasoningTokens]
2299
+ ]) {
2300
+ if (traced === void 0 || traced !== settled) {
2301
+ throw new Error(
2302
+ `protected trace span ${span.spanId} ${name} ${traced} does not match model ledger ${settled}`
2303
+ );
2304
+ }
2305
+ }
2306
+ if (span.costUsd === void 0) {
2307
+ throw new Error(`protected trace span ${span.spanId} is missing costUsd`);
2308
+ }
2309
+ const tracedCost = usdToNanos(span.costUsd, `protected trace span ${span.spanId} costUsd`);
2310
+ if (tracedCost !== call.costUsdNanos) {
2311
+ throw new Error(
2312
+ `protected trace span ${span.spanId} costUsdNanos ${tracedCost} does not match model ledger ${call.costUsdNanos}`
2313
+ );
2314
+ }
2315
+ }
2316
+ function assertIdentifier(value, label) {
2317
+ if (typeof value !== "string" || value.length === 0 || value.length > 256) {
2318
+ throw new Error(`${label} must be a non-empty bounded string`);
2319
+ }
2320
+ }
2321
+ function assertCount2(value, label) {
2322
+ if (!Number.isSafeInteger(value) || value < 0) {
2323
+ throw new Error(`${label} must be a nonnegative safe integer`);
2324
+ }
2325
+ }
2326
+ function assertTimestamp(value, label) {
2327
+ if (!Number.isSafeInteger(value) || value <= 0) {
2328
+ throw new Error(`${label} must be a positive safe integer`);
2329
+ }
2330
+ }
2331
+ function safeAdd(left, right, label) {
2332
+ const total = left + right;
2333
+ if (!Number.isSafeInteger(total)) throw new Error(`${label} exceeds safe integer range`);
2334
+ return total;
2335
+ }
2336
+
2337
+ // src/candidate-execution/protected-redaction.ts
2338
+ import {
2339
+ DEFAULT_REDACTION_RULES,
2340
+ REDACTION_VERSION,
2341
+ redactString
2342
+ } from "@tangle-network/agent-eval";
2343
+ function redactProtectedValue(value, protectedValues) {
2344
+ const report = {
2345
+ version: REDACTION_VERSION,
2346
+ redactionCount: 0,
2347
+ byRule: {}
2348
+ };
2349
+ const rules = protectedRedactionRules(protectedValues);
2350
+ const redacted = redactNode(value, protectedValues, rules, report);
2351
+ assertNoProtectedEvidence(redacted, protectedValues);
2352
+ return { value: redacted, report };
2353
+ }
2354
+ function redactProtectedReason(reason, protectedValues) {
2355
+ try {
2356
+ return redactProtectedValue(reason, protectedValues).value;
2357
+ } catch {
2358
+ return "candidate execution failed with a protected error";
2359
+ }
2360
+ }
2361
+ function assertNoProtectedEvidence(value, protectedValues) {
2362
+ if (value instanceof Uint8Array) {
2363
+ assertNoProtectedBytes(value, protectedValues);
2364
+ return;
2365
+ }
2366
+ if (typeof value === "string") {
2367
+ for (const protectedValue of protectedValueVariants(protectedValues)) {
2368
+ if (value.includes(protectedValue)) {
2369
+ throw new Error("protected value survived candidate evidence redaction");
2370
+ }
2371
+ }
2372
+ if (decodedBase64ContainsProtectedValue(value, protectedValues)) {
2373
+ throw new Error("base64 protected value survived candidate evidence redaction");
2374
+ }
2375
+ return;
2376
+ }
2377
+ if (Array.isArray(value)) {
2378
+ for (const entry of value) assertNoProtectedEvidence(entry, protectedValues);
2379
+ return;
2380
+ }
2381
+ if (value && typeof value === "object") {
2382
+ for (const [key, entry] of Object.entries(value)) {
2383
+ assertNoProtectedEvidence(key, protectedValues);
2384
+ assertNoProtectedEvidence(entry, protectedValues);
2385
+ }
2386
+ }
2387
+ }
2388
+ function assertNoProtectedBytes(bytes, protectedValues) {
2389
+ if (containsProtectedBytes(bytes, protectedValues)) {
2390
+ throw new Error("protected value survived candidate evidence byte redaction");
2391
+ }
2392
+ }
2393
+ function redactNode(value, protectedValues, rules, report) {
2394
+ if (value instanceof Uint8Array) {
2395
+ if (containsProtectedBytes(value, protectedValues)) {
2396
+ recordRedaction(report, "candidate-access-binary", 1);
2397
+ return Uint8Array.from(Buffer.from("[redacted:candidate-access-binary]", "utf8"));
2398
+ }
2399
+ return Uint8Array.from(value);
2400
+ }
2401
+ if (typeof value === "string") {
2402
+ if (decodedBase64ContainsProtectedValue(value, protectedValues)) {
2403
+ recordRedaction(report, "candidate-access-binary", 1);
2404
+ return "[redacted:candidate-access-binary]";
2405
+ }
2406
+ const redacted = redactString(value, [...rules]);
2407
+ for (const [rule, count] of Object.entries(redacted.report.byRule)) {
2408
+ recordRedaction(report, rule, count);
2409
+ }
2410
+ return redacted.output;
2411
+ }
2412
+ if (Array.isArray(value)) {
2413
+ return value.map((entry) => redactNode(entry, protectedValues, rules, report));
2414
+ }
2415
+ if (value && typeof value === "object") {
2416
+ const entries = [];
2417
+ const seenKeys = /* @__PURE__ */ new Set();
2418
+ for (const [key, entry] of Object.entries(value)) {
2419
+ const redactedKey = redactNode(key, protectedValues, rules, report);
2420
+ if (typeof redactedKey !== "string" || seenKeys.has(redactedKey)) {
2421
+ throw new Error("protected evidence redaction produced an ambiguous object key");
2422
+ }
2423
+ seenKeys.add(redactedKey);
2424
+ entries.push([redactedKey, redactNode(entry, protectedValues, rules, report)]);
2425
+ }
2426
+ return Object.fromEntries(entries);
2427
+ }
2428
+ return value;
2429
+ }
2430
+ function protectedRedactionRules(protectedValues) {
2431
+ const exactRules = protectedValueVariants(protectedValues).sort((left, right) => right.length - left.length || left.localeCompare(right)).map((value, index) => ({
2432
+ id: `candidate-access-${index}`,
2433
+ pattern: new RegExp(escapeRegularExpression(value), "g"),
2434
+ replacement: "[redacted:candidate-access]"
2435
+ }));
2436
+ return [...exactRules, ...DEFAULT_REDACTION_RULES];
2437
+ }
2438
+ function recordRedaction(report, rule, count) {
2439
+ if (count <= 0) return;
2440
+ report.redactionCount += count;
2441
+ report.byRule[rule] = (report.byRule[rule] ?? 0) + count;
2442
+ }
2443
+ function containsProtectedBytes(bytes, protectedValues) {
2444
+ const source = Buffer.from(bytes);
2445
+ return protectedValueVariants(protectedValues).some(
2446
+ (value) => source.includes(Buffer.from(value, "utf8"))
2447
+ );
2448
+ }
2449
+ function decodedBase64ContainsProtectedValue(value, protectedValues) {
2450
+ if (value.length < 4 || value.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(value)) {
2451
+ return false;
2452
+ }
2453
+ try {
2454
+ return containsProtectedBytes(Buffer.from(value, "base64"), protectedValues);
2455
+ } catch {
2456
+ return false;
2457
+ }
2458
+ }
2459
+ function protectedValueVariants(protectedValues) {
2460
+ const variants = /* @__PURE__ */ new Set();
2461
+ for (const value of normalizedProtectedValues(protectedValues)) {
2462
+ variants.add(value);
2463
+ variants.add(Buffer.from(value, "utf8").toString("base64"));
2464
+ variants.add(Buffer.from(value, "utf8").toString("base64url"));
2465
+ variants.add(encodeURIComponent(value));
2466
+ }
2467
+ return [...variants];
2468
+ }
2469
+ function normalizedProtectedValues(values) {
2470
+ return [...new Set(values.filter((value) => value.length > 0))];
2471
+ }
2472
+ function escapeRegularExpression(value) {
2473
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2474
+ }
2475
+
2476
+ // src/candidate-execution/finalize.ts
2477
+ async function finalizeAgentCandidateRun(state, capture, traceStore, settlement, evidence, protectedValues, writeRedactionReport, signal) {
2478
+ let termination;
2479
+ try {
2480
+ signal?.throwIfAborted();
2481
+ const protectedCapture = sealAgentCandidateProtectedRunCapture(capture);
2482
+ if (protectedCapture.executionId !== state.executionId) {
2483
+ throw new Error("protected capture execution id does not match the prepared execution");
2484
+ }
2485
+ termination = protectedCapture.termination;
2486
+ if (termination.kind === "timeout" && termination.timeoutMs !== state.executionPlan.value.material.limits.timeoutMs) {
2487
+ throw new Error("timeout termination does not match the frozen execution limit");
2488
+ }
2489
+ const run = await traceStore.getRun(state.trace.runId);
2490
+ if (!run) throw new Error(`protected trace run is missing: ${state.trace.runId}`);
2491
+ if (run.status === "running" || run.endedAt === void 0) {
2492
+ throw new Error("protected trace run is not terminal");
2493
+ }
2494
+ assertTraceBindings(run.tags, state);
2495
+ const [spans, events, budget, artifacts] = await Promise.all([
2496
+ traceStore.spans({ runId: run.runId }),
2497
+ traceStore.events({ runId: run.runId }),
2498
+ traceStore.budget(run.runId),
2499
+ traceStore.artifacts(run.runId)
2500
+ ]);
2501
+ const orderedSpans = [...spans].sort(
2502
+ (a, b) => a.startedAt - b.startedAt || compareStrings(a.spanId, b.spanId)
2503
+ );
2504
+ const orderedEvents = [...events].sort(
2505
+ (a, b) => a.timestamp - b.timestamp || compareStrings(a.eventId, b.eventId)
2506
+ );
2507
+ const orderedBudget = [...budget].sort(
2508
+ (a, b) => a.timestamp - b.timestamp || compareStrings(a.dimension, b.dimension)
2509
+ );
2510
+ const orderedArtifacts = [...artifacts].sort(
2511
+ (a, b) => compareStrings(a.artifactId, b.artifactId)
2512
+ );
2513
+ const modelSpans = orderedSpans.filter(isLlmSpan2);
2514
+ assertTraceMatchesModelSettlement(modelSpans, settlement);
2515
+ const usage = settlement.usage;
2516
+ enforceLimits(state, run.startedAt, run.endedAt, orderedSpans, settlement);
2517
+ const finalCapture = sealAgentCandidateExecutorFinalCapture(evidence.finalCapture);
2518
+ const memory = await memoryReceipt(
2519
+ state,
2520
+ finalCapture,
2521
+ evidence.outputArtifacts,
2522
+ protectedValues,
2523
+ signal
2524
+ );
2525
+ const redacted = redactProtectedValue(
2526
+ {
2527
+ schemaVersion: 1,
2528
+ run: { ...run, redactionVersion: REDACTION_VERSION2 },
2529
+ spans: orderedSpans,
2530
+ events: orderedEvents,
2531
+ budget: orderedBudget,
2532
+ artifacts: orderedArtifacts
2533
+ },
2534
+ protectedValues
2535
+ );
2536
+ const combinedByRule = { ...writeRedactionReport?.byRule ?? {} };
2537
+ for (const [rule, count] of Object.entries(redacted.report.byRule)) {
2538
+ combinedByRule[rule] = (combinedByRule[rule] ?? 0) + count;
2539
+ }
2540
+ const traceMaterial = {
2541
+ ...redacted.value,
2542
+ evaluatorLimits: { resultTimeoutMs: state.resultTimeoutMs },
2543
+ redaction: {
2544
+ version: REDACTION_VERSION2,
2545
+ redactionCount: (writeRedactionReport?.redactionCount ?? 0) + redacted.report.redactionCount,
2546
+ byRule: combinedByRule
2547
+ }
2548
+ };
2549
+ const traceBytes = canonicalCandidateBytes(traceMaterial);
2550
+ assertNoProtectedBytes(traceBytes, protectedValues);
2551
+ const traceArtifact = await persistCandidateOutputArtifact(evidence.outputArtifacts, {
2552
+ executionId: state.executionId,
2553
+ purpose: "trace",
2554
+ bytes: traceBytes,
2555
+ signal
2556
+ });
2557
+ const trace = {
2558
+ schemaVersion: 1,
2559
+ artifact: traceArtifact,
2560
+ eventCount: 1 + orderedSpans.length + orderedEvents.length + orderedBudget.length + orderedArtifacts.length,
2561
+ modelCallCount: modelSpans.length
2562
+ };
2563
+ const document = canonicalCandidateDocument({
2564
+ schemaVersion: 2,
2565
+ kind: "agent-candidate-run",
2566
+ digestAlgorithm: "rfc8785-sha256",
2567
+ bundleDigest: state.bundle.digest,
2568
+ materializationReceiptDigest: state.materializationReceipt.digest,
2569
+ executionPlanDigest: state.executionPlan.value.digest,
2570
+ memory,
2571
+ usage,
2572
+ modelUsage: { resolved: state.resolvedModel, usage },
2573
+ trace,
2574
+ termination,
2575
+ fixedUsage: settlement.fixedUsage,
2576
+ modelSettlement: evidence.modelSettlement,
2577
+ taskOutcome: evidence.taskOutcome.evidence,
2578
+ benchmarkResult: evidence.benchmarkResult
2579
+ });
2580
+ agentCandidateRunReceiptV2Schema.parse(document.value);
2581
+ const runReceipt = await persistCandidateOutputArtifact(evidence.outputArtifacts, {
2582
+ executionId: state.executionId,
2583
+ purpose: "run-receipt",
2584
+ bytes: document.bytes,
2585
+ signal
2586
+ });
2587
+ return {
2588
+ succeeded: true,
2589
+ receipt: document,
2590
+ artifacts: {
2591
+ modelSettlement: evidence.modelSettlement.artifact,
2592
+ taskOutcome: evidence.taskOutcome.evidence.artifact,
2593
+ benchmarkResult: evidence.benchmarkResult.artifact,
2594
+ runReceipt
2595
+ }
2596
+ };
2597
+ } catch (error) {
2598
+ return {
2599
+ ...failedAgentCandidateRun(
2600
+ state,
2601
+ redactProtectedReason(
2602
+ error instanceof Error ? error.message : String(error),
2603
+ protectedValues
2604
+ ),
2605
+ termination,
2606
+ settlement.usage
2607
+ )
2608
+ };
2609
+ }
2610
+ }
2611
+ function assertTraceBindings(tags, state) {
2612
+ const expected = state.trace.tags;
2613
+ for (const name of Object.values(CANDIDATE_TRACE_TAGS)) {
2614
+ if (tags?.[name] !== expected[name]) {
2615
+ throw new Error(`protected trace is not bound to prepared execution tag ${name}`);
2616
+ }
2617
+ }
2618
+ }
2619
+ function enforceLimits(state, startedAt, endedAt, spans, settlement) {
2620
+ const limits = state.executionPlan.value.material.limits;
2621
+ const usage = settlement.usage;
2622
+ const wallMs = endedAt - startedAt;
2623
+ if (!Number.isFinite(wallMs) || wallMs < 0 || wallMs > limits.timeoutMs) {
2624
+ throw new Error(`protected trace wall time ${wallMs} exceeds ${limits.timeoutMs}`);
2625
+ }
2626
+ const steps = spans.filter((span) => span.kind === "tool").length;
2627
+ const checks = [
2628
+ [steps, limits.maxSteps, "tool steps"],
2629
+ [usage.modelCalls, limits.maxModelCalls, "model calls"],
2630
+ [usage.inputTokens, limits.maxInputTokens, "input tokens"],
2631
+ [usage.outputTokens, limits.maxOutputTokens, "output tokens"]
2632
+ ];
2633
+ for (const [actual, limit, label] of checks) {
2634
+ if (actual > limit) throw new Error(`protected ${label} ${actual} exceeds ${limit}`);
2635
+ }
2636
+ if (settlement.costUsdNanos > usdToNanos(limits.maxCostUsd, "frozen maxCostUsd")) {
2637
+ throw new Error(`protected cost USD ${usage.costUsd} exceeds ${limits.maxCostUsd}`);
2638
+ }
2639
+ }
2640
+ async function memoryReceipt(state, capture, outputArtifacts, protectedValues, signal) {
2641
+ signal?.throwIfAborted();
2642
+ if (state.memory.mode === "disabled") {
2643
+ if (capture.memoryAfter !== void 0) {
2644
+ throw new Error("disabled memory cannot return an after-state");
2645
+ }
2646
+ return { mode: "disabled" };
2647
+ }
2648
+ if (!capture.memoryAfter) throw new Error("isolated memory is missing its protected after-state");
2649
+ const afterState = capture.memoryAfter.afterState;
2650
+ const archive = Uint8Array.from(capture.memoryAfter.archive);
2651
+ if (archive.byteLength === 0) throw new Error("isolated memory archive cannot be empty");
2652
+ const manifestBytes = canonicalCandidateBytes(afterState);
2653
+ assertNoProtectedBytes(manifestBytes, protectedValues);
2654
+ assertNoProtectedBytes(archive, protectedValues);
2655
+ const provisionalSnapshot = agentCandidateWorkspaceSnapshotEvidenceSchema.parse({
2656
+ schemaVersion: 1,
2657
+ kind: "agent-candidate-workspace-snapshot",
2658
+ digest: sha256Bytes(manifestBytes),
2659
+ material: afterState,
2660
+ manifest: embeddedCandidateArtifact(manifestBytes),
2661
+ archive: embeddedCandidateArtifact(archive)
2662
+ });
2663
+ const root = await mkdtemp2(join2(tmpdir2(), "agent-candidate-memory-after-"));
2664
+ try {
2665
+ await state.ports.workspaces.materialize({
2666
+ role: "memory",
2667
+ snapshot: provisionalSnapshot,
2668
+ archive: Uint8Array.from(archive),
2669
+ destination: root
2670
+ });
2671
+ const files = await readMaterializedWorkspaceFiles(root, afterState);
2672
+ for (const file of files) assertNoProtectedBytes(file.bytes, protectedValues);
2673
+ signal?.throwIfAborted();
2674
+ } finally {
2675
+ await rm2(root, { recursive: true, force: true });
2676
+ }
2677
+ const [manifest, archiveRef] = await Promise.all([
2678
+ persistCandidateOutputArtifact(outputArtifacts, {
2679
+ executionId: state.executionId,
2680
+ purpose: "memory-after-manifest",
2681
+ bytes: manifestBytes,
2682
+ signal
2683
+ }),
2684
+ persistCandidateOutputArtifact(outputArtifacts, {
2685
+ executionId: state.executionId,
2686
+ purpose: "memory-after-archive",
2687
+ bytes: archive,
2688
+ signal
2689
+ })
2690
+ ]);
2691
+ const snapshot = agentCandidateWorkspaceSnapshotEvidenceSchema.parse({
2692
+ schemaVersion: 1,
2693
+ kind: "agent-candidate-workspace-snapshot",
2694
+ digest: sha256Bytes(manifestBytes),
2695
+ material: afterState,
2696
+ manifest,
2697
+ archive: archiveRef
2698
+ });
2699
+ return {
2700
+ mode: "isolated",
2701
+ scope: "task",
2702
+ effectiveNamespace: state.memory.effectiveNamespace,
2703
+ resetEvidenceDigest: state.memory.reset.evidence.sha256,
2704
+ beforeStateDigest: state.memory.beforeState.digest,
2705
+ afterState: snapshot
2706
+ };
2707
+ }
2708
+ function failedAgentCandidateRun(state, reason, termination, usage = null) {
2709
+ return {
2710
+ succeeded: false,
2711
+ reason,
2712
+ partial: {
2713
+ executionId: state.executionId,
2714
+ bundleDigest: state.bundle.digest,
2715
+ executionPlanDigest: state.executionPlan.value.digest,
2716
+ materializationReceiptDigest: state.materializationReceipt.digest,
2717
+ ...termination ? { termination } : {}
2718
+ },
2719
+ usage
2720
+ };
2721
+ }
2722
+ function compareStrings(a, b) {
2723
+ return a < b ? -1 : a > b ? 1 : 0;
2724
+ }
2725
+
2726
+ // src/candidate-execution/outcome-evidence.ts
2727
+ import { mkdtemp as mkdtemp3, rm as rm3 } from "fs/promises";
2728
+ import { tmpdir as tmpdir3 } from "os";
2729
+ import { join as join3 } from "path";
2730
+ import {
2731
+ agentCandidateBenchmarkResultEvidenceSchema,
2732
+ agentCandidateModelSettlementEvidenceSchema,
2733
+ agentCandidateTaskOutcomeEvidenceSchema,
2734
+ agentCandidateWorkspaceSnapshotEvidenceSchema as agentCandidateWorkspaceSnapshotEvidenceSchema2
2735
+ } from "@tangle-network/agent-interface";
2736
+
2737
+ // src/candidate-execution/benchmark-grader.ts
2738
+ async function runBoundCandidateBenchmarkGrader(input) {
2739
+ input.signal?.throwIfAborted();
2740
+ const descriptor = snapshotGraderDescriptor(input.grader);
2741
+ const implementationBytes = await readVerifiedArtifact(descriptor.artifact, input.artifacts);
2742
+ if (implementationBytes.byteLength === 0) {
2743
+ throw new Error("candidate benchmark grader implementation cannot be empty");
2744
+ }
2745
+ const expectedImplementationDigest = sha256Bytes(implementationBytes);
2746
+ const termination = immutableCandidateValue(input.termination);
2747
+ const run = input.grader.run;
2748
+ const result = await run(
2749
+ Object.freeze({
2750
+ executionId: input.executionId,
2751
+ termination,
2752
+ outcome: input.outcome,
2753
+ implementation: detachedImplementation(implementationBytes),
2754
+ signal: input.signal ?? new AbortController().signal
2755
+ })
2756
+ );
2757
+ input.signal?.throwIfAborted();
2758
+ assertExactRunnerResult(result);
2759
+ const evidence = Uint8Array.from(result.evidence);
2760
+ const outputDigest = sha256Bytes(evidence);
2761
+ if (result.binding.implementationDigest !== expectedImplementationDigest) {
2762
+ throw new Error(
2763
+ "candidate benchmark grader executed implementation digest does not match its verified artifact"
2764
+ );
2765
+ }
2766
+ if (result.binding.taskOutcomeDigest !== input.outcome.evidence.digest) {
2767
+ throw new Error(
2768
+ "candidate benchmark grader task outcome digest does not match verified outcome"
2769
+ );
2770
+ }
2771
+ if (result.binding.outputDigest !== outputDigest) {
2772
+ throw new Error("candidate benchmark grader raw output digest does not match returned evidence");
2773
+ }
2774
+ return Object.freeze({
2775
+ grader: descriptor,
2776
+ evaluation: result.evaluation,
2777
+ evidence
2778
+ });
2779
+ }
2780
+ function snapshotGraderDescriptor(grader) {
2781
+ if (!grader.name || !grader.version) {
2782
+ throw new Error("candidate benchmark grader name and version must be non-empty");
2783
+ }
2784
+ return immutableCandidateValue({
2785
+ name: grader.name,
2786
+ version: grader.version,
2787
+ artifact: grader.artifact
2788
+ });
2789
+ }
2790
+ function detachedImplementation(bytes) {
2791
+ const stored = Uint8Array.from(bytes);
2792
+ return Object.freeze({
2793
+ byteLength: stored.byteLength,
2794
+ get bytes() {
2795
+ return Uint8Array.from(stored);
2796
+ }
2797
+ });
2798
+ }
2799
+ function assertExactRunnerResult(value) {
2800
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
2801
+ throw new Error("candidate benchmark grader result must be an object");
2802
+ }
2803
+ const result = value;
2804
+ const keys = Object.keys(result).sort();
2805
+ if (keys.length !== 3 || keys[0] !== "binding" || keys[1] !== "evaluation" || keys[2] !== "evidence") {
2806
+ throw new Error("candidate benchmark grader returned unknown or missing fields");
2807
+ }
2808
+ if (!(result.evidence instanceof Uint8Array)) {
2809
+ throw new Error("candidate benchmark grader evidence must be bytes");
2810
+ }
2811
+ if (result.binding === null || typeof result.binding !== "object" || Array.isArray(result.binding)) {
2812
+ throw new Error("candidate benchmark grader binding must be an object");
2813
+ }
2814
+ const bindingKeys = Object.keys(result.binding).sort();
2815
+ if (bindingKeys.length !== 3 || bindingKeys[0] !== "implementationDigest" || bindingKeys[1] !== "outputDigest" || bindingKeys[2] !== "taskOutcomeDigest") {
2816
+ throw new Error("candidate benchmark grader binding returned unknown or missing fields");
2817
+ }
2818
+ }
2819
+
2820
+ // src/candidate-execution/outcome-evidence.ts
2821
+ async function persistCandidateModelSettlement(state, settlement, outputArtifacts) {
2822
+ return await persistCandidateModelSettlementEvidence(
2823
+ {
2824
+ executionId: state.executionId,
2825
+ executionPlanDigest: state.executionPlan.value.digest,
2826
+ resolvedModel: state.resolvedModel
2827
+ },
2828
+ settlement,
2829
+ outputArtifacts
2830
+ );
2831
+ }
2832
+ async function persistCandidateModelSettlementEvidence(identity, settlement, outputArtifacts) {
2833
+ const material = {
2834
+ schemaVersion: 2,
2835
+ kind: "agent-candidate-model-settlement-material",
2836
+ executionPlanDigest: identity.executionPlanDigest,
2837
+ preparationId: settlement.value.preparationId,
2838
+ grantDigest: settlement.value.grantDigest,
2839
+ closed: true,
2840
+ resolved: identity.resolvedModel,
2841
+ calls: settlement.value.calls.map((call) => ({
2842
+ callId: call.callId,
2843
+ generationId: call.generationId,
2844
+ traceSpanId: call.traceSpanId,
2845
+ status: call.status,
2846
+ model: call.model,
2847
+ startedAtMs: call.startedAtMs,
2848
+ endedAtMs: call.endedAtMs,
2849
+ inputTokens: call.inputTokens,
2850
+ outputTokens: call.outputTokens,
2851
+ cachedInputTokens: call.cachedInputTokens ?? 0,
2852
+ reasoningTokens: call.reasoningTokens ?? 0,
2853
+ costUsdNanos: call.costUsdNanos
2854
+ })),
2855
+ usage: settlement.fixedUsage
2856
+ };
2857
+ const bytes = canonicalCandidateBytes(material);
2858
+ const digest = sha256Bytes(bytes);
2859
+ const artifact = await persistCandidateOutputArtifact(outputArtifacts, {
2860
+ executionId: identity.executionId,
2861
+ purpose: "model-settlement",
2862
+ bytes
2863
+ });
2864
+ return immutableCandidateValue(
2865
+ agentCandidateModelSettlementEvidenceSchema.parse({
2866
+ schemaVersion: 1,
2867
+ kind: "agent-candidate-model-settlement",
2868
+ digest,
2869
+ material,
2870
+ artifact
2871
+ })
2872
+ );
2873
+ }
2874
+ async function persistVerifiedCandidateTaskOutcome(state, capture, outputArtifacts, protectedValues, signal) {
2875
+ signal?.throwIfAborted();
2876
+ const patch = Uint8Array.from(capture.gitDiff);
2877
+ const archive = Uint8Array.from(capture.archive);
2878
+ if (archive.byteLength === 0) throw new Error("candidate task archive cannot be empty");
2879
+ assertNoProtectedBytes(patch, protectedValues);
2880
+ assertNoProtectedBytes(archive, protectedValues);
2881
+ const afterState = immutableCandidateValue(capture.afterState);
2882
+ const repository = state.executionPlan.value.material.task.repository;
2883
+ const verified = await verifyTaskOutcomePatch({
2884
+ repositoryRoot: state.roots.staging.taskRoot,
2885
+ baseCommit: repository.baseCommit,
2886
+ baseTree: repository.baseTree,
2887
+ resultTree: capture.resultTree,
2888
+ patch,
2889
+ afterState
2890
+ });
2891
+ signal?.throwIfAborted();
2892
+ const manifestBytes = canonicalCandidateBytes(afterState);
2893
+ assertNoProtectedBytes(manifestBytes, protectedValues);
2894
+ const provisionalSnapshot = agentCandidateWorkspaceSnapshotEvidenceSchema2.parse({
2895
+ schemaVersion: 1,
2896
+ kind: "agent-candidate-workspace-snapshot",
2897
+ digest: sha256Bytes(manifestBytes),
2898
+ material: afterState,
2899
+ manifest: embeddedCandidateArtifact(manifestBytes),
2900
+ archive: embeddedCandidateArtifact(archive)
2901
+ });
2902
+ await verifyTaskOutcomeArchive(state, provisionalSnapshot, archive, protectedValues);
2903
+ signal?.throwIfAborted();
2904
+ const [manifest, archiveRef, gitDiff] = await Promise.all([
2905
+ persistCandidateOutputArtifact(outputArtifacts, {
2906
+ executionId: state.executionId,
2907
+ purpose: "task-manifest",
2908
+ bytes: manifestBytes,
2909
+ signal
2910
+ }),
2911
+ persistCandidateOutputArtifact(outputArtifacts, {
2912
+ executionId: state.executionId,
2913
+ purpose: "task-archive",
2914
+ bytes: archive,
2915
+ signal
2916
+ }),
2917
+ persistCandidateOutputArtifact(outputArtifacts, {
2918
+ executionId: state.executionId,
2919
+ purpose: "task-patch",
2920
+ bytes: patch,
2921
+ signal
2922
+ })
2923
+ ]);
2924
+ const snapshot = agentCandidateWorkspaceSnapshotEvidenceSchema2.parse({
2925
+ schemaVersion: 1,
2926
+ kind: "agent-candidate-workspace-snapshot",
2927
+ digest: sha256Bytes(manifestBytes),
2928
+ material: afterState,
2929
+ manifest,
2930
+ archive: archiveRef
2931
+ });
2932
+ const material = {
2933
+ schemaVersion: 1,
2934
+ kind: "agent-candidate-task-outcome-material",
2935
+ executionPlanDigest: state.executionPlan.value.digest,
2936
+ baseRepository: {
2937
+ identity: repository.identity,
2938
+ rootIdentity: repository.rootIdentity,
2939
+ commit: repository.baseCommit,
2940
+ tree: repository.baseTree
2941
+ },
2942
+ resultRepository: {
2943
+ identity: repository.identity,
2944
+ rootIdentity: repository.rootIdentity,
2945
+ commit: verified.resultCommit,
2946
+ tree: verified.resultTree
2947
+ },
2948
+ afterState: snapshot,
2949
+ gitDiff: {
2950
+ format: "git-diff-binary",
2951
+ artifact: gitDiff
2952
+ }
2953
+ };
2954
+ const bytes = canonicalCandidateBytes(material);
2955
+ const digest = sha256Bytes(bytes);
2956
+ const artifact = await persistCandidateOutputArtifact(outputArtifacts, {
2957
+ executionId: state.executionId,
2958
+ purpose: "task-outcome",
2959
+ bytes,
2960
+ signal
2961
+ });
2962
+ const evidence = immutableCandidateValue(
2963
+ agentCandidateTaskOutcomeEvidenceSchema.parse({
2964
+ schemaVersion: 1,
2965
+ kind: "agent-candidate-task-outcome",
2966
+ digest,
2967
+ material,
2968
+ artifact
2969
+ })
2970
+ );
2971
+ const storedPatch = Uint8Array.from(patch);
2972
+ return Object.freeze({
2973
+ evidence,
2974
+ get patch() {
2975
+ return Uint8Array.from(storedPatch);
2976
+ },
2977
+ [verifiedTaskOutcomeBrand]: true
2978
+ });
2979
+ }
2980
+ async function persistCandidateBenchmarkResult(state, termination, outcome, grader, outputArtifacts, protectedValues, signal) {
2981
+ signal?.throwIfAborted();
2982
+ const frozenTermination = immutableCandidateValue(termination);
2983
+ const graded = await runBoundCandidateBenchmarkGrader({
2984
+ executionId: state.executionId,
2985
+ termination: frozenTermination,
2986
+ outcome,
2987
+ grader,
2988
+ artifacts: outputArtifacts,
2989
+ signal
2990
+ });
2991
+ signal?.throwIfAborted();
2992
+ const evaluation = normalizeEvaluation(graded.evaluation, frozenTermination);
2993
+ const rawEvidence = Uint8Array.from(graded.evidence);
2994
+ if (rawEvidence.byteLength === 0) throw new Error("candidate benchmark evidence cannot be empty");
2995
+ assertNoProtectedBytes(rawEvidence, protectedValues);
2996
+ const evidenceRef = await persistCandidateOutputArtifact(outputArtifacts, {
2997
+ executionId: state.executionId,
2998
+ purpose: "grader-evidence",
2999
+ bytes: rawEvidence,
3000
+ signal
3001
+ });
3002
+ const task = state.executionPlan.value.material.task;
3003
+ const material = {
3004
+ schemaVersion: 1,
3005
+ kind: "agent-candidate-benchmark-result-material",
3006
+ executionPlanDigest: state.executionPlan.value.digest,
3007
+ taskOutcomeDigest: outcome.evidence.digest,
3008
+ benchmark: {
3009
+ name: task.benchmark,
3010
+ version: task.benchmarkVersion,
3011
+ taskId: task.taskId,
3012
+ splitDigest: task.splitDigest
3013
+ },
3014
+ grader: {
3015
+ name: graded.grader.name,
3016
+ version: graded.grader.version,
3017
+ artifact: graded.grader.artifact
3018
+ },
3019
+ evidence: evidenceRef,
3020
+ score: evaluation.score,
3021
+ passed: evaluation.passed,
3022
+ dimensions: evaluation.dimensions
3023
+ };
3024
+ const bytes = canonicalCandidateBytes(material);
3025
+ const digest = sha256Bytes(bytes);
3026
+ const artifact = await persistCandidateOutputArtifact(outputArtifacts, {
3027
+ executionId: state.executionId,
3028
+ purpose: "benchmark-result",
3029
+ bytes,
3030
+ signal
3031
+ });
3032
+ return immutableCandidateValue(
3033
+ agentCandidateBenchmarkResultEvidenceSchema.parse({
3034
+ schemaVersion: 1,
3035
+ kind: "agent-candidate-benchmark-result",
3036
+ digest,
3037
+ material,
3038
+ artifact
3039
+ })
3040
+ );
3041
+ }
3042
+ async function verifyTaskOutcomeArchive(state, snapshot, archive, protectedValues) {
3043
+ const root = await mkdtemp3(join3(tmpdir3(), "agent-candidate-task-archive-"));
3044
+ try {
3045
+ await state.ports.workspaces.materialize({
3046
+ role: "task",
3047
+ snapshot,
3048
+ archive: Uint8Array.from(archive),
3049
+ destination: root
3050
+ });
3051
+ const files = await readMaterializedWorkspaceFiles(root, snapshot.material);
3052
+ for (const file of files) assertNoProtectedBytes(file.bytes, protectedValues);
3053
+ } finally {
3054
+ await rm3(root, { recursive: true, force: true });
3055
+ }
3056
+ }
3057
+ function normalizeEvaluation(evaluation, termination) {
3058
+ if (!evaluation || typeof evaluation !== "object" || Array.isArray(evaluation)) {
3059
+ throw new Error("candidate benchmark evaluation must be an object");
3060
+ }
3061
+ assertUnitScore(evaluation.score, "candidate benchmark score");
3062
+ if (evaluation.passed !== void 0 && typeof evaluation.passed !== "boolean") {
3063
+ throw new Error("candidate benchmark passed must be boolean");
3064
+ }
3065
+ const cleanExit = termination.kind === "exit" && termination.exitCode === 0;
3066
+ const dimensions = Object.entries(evaluation.dimensions ?? {}).map(([name, score]) => {
3067
+ if (!/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/.test(name)) {
3068
+ throw new Error(`candidate benchmark dimension is not normalized: ${name}`);
3069
+ }
3070
+ assertUnitScore(score, `candidate benchmark dimension ${name}`);
3071
+ return { name, score: cleanExit ? score : 0 };
3072
+ }).sort((left, right) => left.name.localeCompare(right.name));
3073
+ return {
3074
+ score: cleanExit ? evaluation.score : 0,
3075
+ passed: cleanExit && (evaluation.passed ?? evaluation.score > 0),
3076
+ dimensions
3077
+ };
3078
+ }
3079
+ function assertUnitScore(value, label) {
3080
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 1) {
3081
+ throw new Error(`${label} must be finite and within [0, 1]`);
3082
+ }
3083
+ }
3084
+
3085
+ // src/candidate-execution/protected-trace-store.ts
3086
+ import { REDACTION_VERSION as REDACTION_VERSION3 } from "@tangle-network/agent-eval";
3087
+ var ProtectedAgentCandidateTraceStore = class {
3088
+ constructor(inner, protectedValues) {
3089
+ this.inner = inner;
3090
+ this.protectedValues = protectedValues;
3091
+ }
3092
+ inner;
3093
+ protectedValues;
3094
+ aggregate = {
3095
+ version: REDACTION_VERSION3,
3096
+ redactionCount: 0,
3097
+ byRule: {}
3098
+ };
3099
+ report() {
3100
+ return {
3101
+ version: this.aggregate.version,
3102
+ redactionCount: this.aggregate.redactionCount,
3103
+ byRule: { ...this.aggregate.byRule }
3104
+ };
3105
+ }
3106
+ async appendRun(run) {
3107
+ await this.inner.appendRun(this.redact(run));
3108
+ }
3109
+ async updateRun(runId, patch) {
3110
+ await this.inner.updateRun(this.redact(runId), this.redact(patch));
3111
+ }
3112
+ async appendSpan(span) {
3113
+ if (span.kind === "llm") {
3114
+ throw new Error("candidate executors cannot author protected model spans");
3115
+ }
3116
+ await this.inner.appendSpan(this.redact(span));
3117
+ }
3118
+ async updateSpan(spanId, patch) {
3119
+ if (patch.kind === "llm") {
3120
+ throw new Error("candidate executors cannot author protected model spans");
3121
+ }
3122
+ await this.inner.updateSpan(this.redact(spanId), this.redact(patch));
3123
+ }
3124
+ async appendEvent(event) {
3125
+ await this.inner.appendEvent(this.redact(event));
3126
+ }
3127
+ async appendArtifact(artifact) {
3128
+ await this.inner.appendArtifact(this.redact(artifact));
3129
+ }
3130
+ async appendBudgetEntry(entry) {
3131
+ await this.inner.appendBudgetEntry(this.redact(entry));
3132
+ }
3133
+ getRun(...args) {
3134
+ return this.inner.getRun(...args);
3135
+ }
3136
+ listRuns(...args) {
3137
+ return this.inner.listRuns(...args);
3138
+ }
3139
+ spans(...args) {
3140
+ return this.inner.spans(...args);
3141
+ }
3142
+ events(...args) {
3143
+ return this.inner.events(...args);
3144
+ }
3145
+ budget(...args) {
3146
+ return this.inner.budget(...args);
3147
+ }
3148
+ artifacts(...args) {
3149
+ return this.inner.artifacts(...args);
3150
+ }
3151
+ redact(value) {
3152
+ const redacted = redactProtectedValue(value, this.protectedValues);
3153
+ this.aggregate.version = redacted.report.version;
3154
+ this.aggregate.redactionCount += redacted.report.redactionCount;
3155
+ for (const [rule, count] of Object.entries(redacted.report.byRule)) {
3156
+ this.aggregate.byRule[rule] = (this.aggregate.byRule[rule] ?? 0) + count;
3157
+ }
3158
+ return redacted.value;
3159
+ }
3160
+ };
3161
+ var RecoveryAgentCandidateTraceStore = class {
3162
+ constructor(inner) {
3163
+ this.inner = inner;
3164
+ }
3165
+ inner;
3166
+ appendRun() {
3167
+ return this.rejectWrite();
3168
+ }
3169
+ updateRun() {
3170
+ return this.rejectWrite();
3171
+ }
3172
+ appendSpan() {
3173
+ return this.rejectWrite();
3174
+ }
3175
+ updateSpan() {
3176
+ return this.rejectWrite();
3177
+ }
3178
+ appendEvent() {
3179
+ return this.rejectWrite();
3180
+ }
3181
+ appendArtifact() {
3182
+ return this.rejectWrite();
3183
+ }
3184
+ appendBudgetEntry() {
3185
+ return this.rejectWrite();
3186
+ }
3187
+ getRun(...args) {
3188
+ return this.inner.getRun(...args);
3189
+ }
3190
+ listRuns(...args) {
3191
+ return this.inner.listRuns(...args);
3192
+ }
3193
+ spans(...args) {
3194
+ return this.inner.spans(...args);
3195
+ }
3196
+ events(...args) {
3197
+ return this.inner.events(...args);
3198
+ }
3199
+ budget(...args) {
3200
+ return this.inner.budget(...args);
3201
+ }
3202
+ artifacts(...args) {
3203
+ return this.inner.artifacts(...args);
3204
+ }
3205
+ rejectWrite() {
3206
+ return Promise.reject(new Error("expired candidate recovery cannot append trace evidence"));
3207
+ }
3208
+ };
3209
+
3210
+ // src/candidate-execution/execute.ts
3211
+ async function executePreparedAgentCandidate(prepared, options) {
3212
+ const initialState = assertPreparedCandidateIntegrity(prepared);
3213
+ const cleanupTimeoutMs = candidateCleanupTimeout(
3214
+ options.cleanupTimeoutMs ?? initialState.cleanupTimeoutMs
3215
+ );
3216
+ if (cleanupTimeoutMs > initialState.cleanupTimeoutMs) {
3217
+ throw new Error("execution cleanup timeout exceeds the frozen preparation bound");
3218
+ }
3219
+ const resultTimeoutMs = candidateResultTimeout(
3220
+ options.resultTimeoutMs ?? initialState.resultTimeoutMs,
3221
+ initialState.resultTimeoutMs
3222
+ );
3223
+ if (resultTimeoutMs > initialState.resultTimeoutMs) {
3224
+ throw new Error("execution result timeout exceeds the frozen preparation bound");
3225
+ }
3226
+ let state;
3227
+ try {
3228
+ state = beginPreparedCandidateClaim(prepared);
3229
+ } catch (error) {
3230
+ return failedAgentCandidateRun(initialState, errorMessage(error));
3231
+ }
3232
+ try {
3233
+ await assertPreparedCandidateWorkspaces(state);
3234
+ } catch (error) {
3235
+ return await failBeforeActivation(prepared, state, error, "failed", cleanupTimeoutMs);
3236
+ }
3237
+ let acquired;
3238
+ try {
3239
+ acquired = await options.claimStore.tryClaim(candidateExecutionClaim(prepared));
3240
+ } catch (error) {
3241
+ return await failBeforeActivation(prepared, state, error, "failed", cleanupTimeoutMs);
3242
+ }
3243
+ if (!acquired.acquired) {
3244
+ return await failBeforeActivation(
3245
+ prepared,
3246
+ state,
3247
+ new Error(
3248
+ acquired.reason === "retry-not-eligible" ? `candidate execution retry is not eligible: ${acquired.detail}` : "candidate execution attempt is already claimed"
3249
+ ),
3250
+ "replayed",
3251
+ cleanupTimeoutMs
3252
+ );
3253
+ }
3254
+ markPreparedCandidateClaimed(prepared);
3255
+ const postRunWindowMs = candidatePostRunWindowMs(cleanupTimeoutMs, resultTimeoutMs);
3256
+ const deadlineAtMs = acquired.claim.leaseExpiresAtMs - candidatePostRunWindowMs(state.cleanupTimeoutMs, state.resultTimeoutMs);
3257
+ const requiredLeaseExpiry = deadlineAtMs + postRunWindowMs;
3258
+ if (Date.now() >= deadlineAtMs || deadlineAtMs > state.reservationExpiresAtMs || requiredLeaseExpiry > acquired.lease.expiresAtMs) {
3259
+ return await failClaimedExecution(
3260
+ prepared,
3261
+ state,
3262
+ acquired.lease,
3263
+ options.claimStore,
3264
+ options.outputArtifacts,
3265
+ new Error("candidate claim no longer covers its full execution and cleanup window"),
3266
+ "failed",
3267
+ cleanupTimeoutMs,
3268
+ "pre-model-infrastructure"
3269
+ );
3270
+ }
3271
+ let activation;
3272
+ try {
3273
+ const activated = await withinCandidateCleanupDeadline(
3274
+ () => state.ports.models.activateGrant({
3275
+ executionId: state.executionId,
3276
+ preparationId: state.preparationId,
3277
+ grantDigest: state.modelReservation.digest,
3278
+ resolved: state.resolvedModel,
3279
+ deadlineAtMs
3280
+ }),
3281
+ Math.min(deadlineAtMs, candidateCleanupDeadline(cleanupTimeoutMs)),
3282
+ "protected model activation"
3283
+ );
3284
+ activation = Object.freeze({ env: Object.freeze({ ...activated.env }) });
3285
+ } catch (error) {
3286
+ return await failClaimedExecution(
3287
+ prepared,
3288
+ state,
3289
+ acquired.lease,
3290
+ options.claimStore,
3291
+ options.outputArtifacts,
3292
+ new Error("protected model activation failed", { cause: error }),
3293
+ "failed",
3294
+ cleanupTimeoutMs,
3295
+ "pre-model-infrastructure"
3296
+ );
3297
+ }
3298
+ let memoryActivation;
3299
+ if (state.memory.mode === "isolated") {
3300
+ try {
3301
+ const reservation = state.memoryReservation;
3302
+ if (!reservation) throw new Error("isolated memory reservation is missing");
3303
+ const activated = await withinCandidateCleanupDeadline(
3304
+ () => state.ports.memory.activate({
3305
+ executionId: state.executionId,
3306
+ preparationId: reservation.preparationId,
3307
+ accessDigest: reservation.accessDigest,
3308
+ effectiveNamespace: reservation.effectiveNamespace,
3309
+ deadlineAtMs
3310
+ }),
3311
+ Math.min(deadlineAtMs, candidateCleanupDeadline(cleanupTimeoutMs)),
3312
+ "isolated memory activation"
3313
+ );
3314
+ memoryActivation = Object.freeze({ env: Object.freeze({ ...activated.env }) });
3315
+ } catch (error) {
3316
+ return await failClaimedExecution(
3317
+ prepared,
3318
+ state,
3319
+ acquired.lease,
3320
+ options.claimStore,
3321
+ options.outputArtifacts,
3322
+ new Error("isolated memory activation failed", { cause: error }),
3323
+ "failed",
3324
+ cleanupTimeoutMs,
3325
+ "pre-model-infrastructure",
3326
+ activation
3327
+ );
3328
+ }
3329
+ }
3330
+ let request;
3331
+ try {
3332
+ request = beginPreparedCandidateRun(prepared, activation, memoryActivation).request;
3333
+ } catch (error) {
3334
+ return await failClaimedExecution(
3335
+ prepared,
3336
+ state,
3337
+ acquired.lease,
3338
+ options.claimStore,
3339
+ options.outputArtifacts,
3340
+ error,
3341
+ "failed",
3342
+ cleanupTimeoutMs,
3343
+ "pre-model-infrastructure",
3344
+ activation,
3345
+ memoryActivation
3346
+ );
3347
+ }
3348
+ try {
3349
+ const phase = await options.claimStore.markCandidateMayRun(acquired.lease);
3350
+ if (phase.phase !== "candidate-may-run") {
3351
+ throw new Error("candidate claim did not persist the candidate-may-run phase");
3352
+ }
3353
+ } catch (error) {
3354
+ return await failClaimedExecution(
3355
+ prepared,
3356
+ state,
3357
+ acquired.lease,
3358
+ options.claimStore,
3359
+ options.outputArtifacts,
3360
+ new Error("candidate execution phase persistence failed", { cause: error }),
3361
+ "failed",
3362
+ cleanupTimeoutMs,
3363
+ "pre-model-infrastructure",
3364
+ activation,
3365
+ memoryActivation
3366
+ );
3367
+ }
3368
+ if (Date.now() >= deadlineAtMs) {
3369
+ return await failClaimedExecution(
3370
+ prepared,
3371
+ state,
3372
+ acquired.lease,
3373
+ options.claimStore,
3374
+ options.outputArtifacts,
3375
+ new Error("candidate execution deadline elapsed while persisting its launch phase"),
3376
+ "failed",
3377
+ cleanupTimeoutMs,
3378
+ "unknown",
3379
+ activation,
3380
+ memoryActivation
3381
+ );
3382
+ }
3383
+ const protectedValues = protectedEnvironmentValues(activation, memoryActivation);
3384
+ const protectedTraceStore = new ProtectedAgentCandidateTraceStore(
3385
+ options.traceStore,
3386
+ protectedValues
3387
+ );
3388
+ const execution = await runAndStopExecutor(
3389
+ options.executor,
3390
+ request,
3391
+ protectedTraceStore,
3392
+ deadlineAtMs,
3393
+ cleanupTimeoutMs
3394
+ );
3395
+ beginPreparedCandidateSettlement(prepared);
3396
+ const cleanupDeadlineAtMs = candidateCleanupDeadline(cleanupTimeoutMs);
3397
+ const accessReason = execution.kind === "timeout" || execution.termination?.kind === "timeout" ? "timeout" : execution.kind === "capture" ? "completed" : "failed";
3398
+ const [memoryClose, settlementResult] = await Promise.all([
3399
+ closeMemoryAccess(state, accessReason, cleanupDeadlineAtMs),
3400
+ settleModelGrant(state, accessReason, cleanupDeadlineAtMs)
3401
+ ]);
3402
+ if (!execution.processStopped || !settlementResult.settlement || !memoryClose.closed) {
3403
+ consumePreparedCandidateExecution(prepared, "failed");
3404
+ return failedAgentCandidateRun(
3405
+ state,
3406
+ redactProtectedReason(
3407
+ joinErrors(
3408
+ execution.error,
3409
+ !execution.processStopped ? new Error("candidate process termination is not proven") : void 0,
3410
+ memoryClose.error,
3411
+ settlementResult.error ?? (!settlementResult.settlement ? new Error("model settlement failed") : void 0),
3412
+ new Error("candidate claim remains recoverable until protected cleanup is proven")
3413
+ ),
3414
+ protectedValues
3415
+ ),
3416
+ execution.termination,
3417
+ settlementResult.settlement?.usage ?? null
3418
+ );
3419
+ }
3420
+ let modelSettlement;
3421
+ try {
3422
+ modelSettlement = await withinCandidateCleanupDeadline(
3423
+ () => persistCandidateModelSettlement(
3424
+ state,
3425
+ settlementResult.settlement,
3426
+ options.outputArtifacts
3427
+ ),
3428
+ candidateCleanupDeadline(cleanupTimeoutMs),
3429
+ "candidate model settlement persistence"
3430
+ );
3431
+ } catch (error) {
3432
+ consumePreparedCandidateExecution(prepared, "failed");
3433
+ return failedAgentCandidateRun(
3434
+ state,
3435
+ redactProtectedReason(
3436
+ joinErrors(
3437
+ error,
3438
+ new Error("candidate claim remains recoverable until settlement evidence is durable")
3439
+ ),
3440
+ protectedValues
3441
+ ),
3442
+ execution.termination,
3443
+ settlementResult.settlement.usage
3444
+ );
3445
+ }
3446
+ let result;
3447
+ const failureClass = execution.kind === "error" ? "execution" : "post-model-infrastructure";
3448
+ if (execution.kind === "error") {
3449
+ result = failedAgentCandidateRun(
3450
+ state,
3451
+ redactProtectedReason(errorMessage(execution.error), protectedValues),
3452
+ execution.termination,
3453
+ settlementResult.settlement.usage
3454
+ );
3455
+ } else if (!execution.finalCapture.taskOutcome) {
3456
+ result = failedAgentCandidateRun(
3457
+ state,
3458
+ "candidate executor stopped without a captured task outcome",
3459
+ execution.termination,
3460
+ settlementResult.settlement.usage
3461
+ );
3462
+ } else {
3463
+ const capture = execution.kind === "capture" ? execution.capture : {
3464
+ executionId: state.executionId,
3465
+ termination: execution.termination
3466
+ };
3467
+ try {
3468
+ const resultDeadlineAtMs = Math.min(
3469
+ Date.now() + resultTimeoutMs,
3470
+ acquired.lease.expiresAtMs - candidateTerminalWindowMs(cleanupTimeoutMs)
3471
+ );
3472
+ result = await withinCandidateResultDeadline(
3473
+ async (signal) => {
3474
+ await appendAuthoritativeModelSettlementSpans(
3475
+ options.traceStore,
3476
+ state.trace.runId,
3477
+ settlementResult.settlement
3478
+ );
3479
+ const taskOutcome = await persistVerifiedCandidateTaskOutcome(
3480
+ state,
3481
+ execution.finalCapture.taskOutcome,
3482
+ options.outputArtifacts,
3483
+ protectedValues,
3484
+ signal
3485
+ );
3486
+ const benchmarkResult = await persistCandidateBenchmarkResult(
3487
+ state,
3488
+ capture.termination,
3489
+ taskOutcome,
3490
+ options.grader,
3491
+ options.outputArtifacts,
3492
+ protectedValues,
3493
+ signal
3494
+ );
3495
+ return await finalizeAgentCandidateRun(
3496
+ state,
3497
+ capture,
3498
+ options.traceStore,
3499
+ settlementResult.settlement,
3500
+ {
3501
+ finalCapture: execution.finalCapture,
3502
+ modelSettlement,
3503
+ taskOutcome,
3504
+ benchmarkResult,
3505
+ outputArtifacts: options.outputArtifacts
3506
+ },
3507
+ protectedValues,
3508
+ protectedTraceStore.report(),
3509
+ signal
3510
+ );
3511
+ },
3512
+ resultDeadlineAtMs,
3513
+ "candidate evidence finalization"
3514
+ );
3515
+ } catch (error) {
3516
+ result = failedAgentCandidateRun(
3517
+ state,
3518
+ redactProtectedReason(errorMessage(error), protectedValues),
3519
+ execution.termination,
3520
+ settlementResult.settlement.usage
3521
+ );
3522
+ }
3523
+ }
3524
+ let terminal;
3525
+ try {
3526
+ terminal = result.succeeded ? {
3527
+ schemaVersion: 1,
3528
+ status: "succeeded",
3529
+ usage: settlementResult.settlement.fixedUsage,
3530
+ modelSettlement: result.artifacts.modelSettlement,
3531
+ taskOutcome: result.artifacts.taskOutcome,
3532
+ benchmarkResult: result.artifacts.benchmarkResult,
3533
+ runReceipt: result.artifacts.runReceipt
3534
+ } : {
3535
+ schemaVersion: 1,
3536
+ status: "failed",
3537
+ failureClass,
3538
+ usage: settlementResult.settlement.fixedUsage,
3539
+ modelSettlement: modelSettlement.artifact,
3540
+ failureEvidence: await withinCandidateCleanupDeadline(
3541
+ () => persistFailureEvidence(
3542
+ state,
3543
+ result.reason,
3544
+ failureClass,
3545
+ execution.termination,
3546
+ options.outputArtifacts
3547
+ ),
3548
+ acquired.lease.expiresAtMs,
3549
+ "candidate failure-evidence persistence"
3550
+ )
3551
+ };
3552
+ } catch (error) {
3553
+ consumePreparedCandidateExecution(prepared, "failed");
3554
+ return failedAgentCandidateRun(
3555
+ state,
3556
+ redactProtectedReason(
3557
+ joinErrors(
3558
+ error,
3559
+ new Error("candidate claim remains recoverable until terminal evidence is durable")
3560
+ ),
3561
+ protectedValues
3562
+ ),
3563
+ execution.termination,
3564
+ settlementResult.settlement.usage
3565
+ );
3566
+ }
3567
+ const finished = await finishClaim(
3568
+ options.claimStore,
3569
+ acquired.lease,
3570
+ terminal,
3571
+ acquired.lease.expiresAtMs
3572
+ );
3573
+ if (finished) {
3574
+ consumePreparedCandidateExecution(prepared, result.succeeded ? "succeeded" : "failed");
3575
+ return result;
3576
+ }
3577
+ consumePreparedCandidateExecution(prepared, "failed");
3578
+ return failedAgentCandidateRun(
3579
+ state,
3580
+ "candidate execution terminal record could not be persisted",
3581
+ execution.termination,
3582
+ settlementResult.settlement.usage
3583
+ );
3584
+ }
3585
+ async function runAndStopExecutor(executor, request, traceStore, deadlineAtMs, cleanupTimeoutMs) {
3586
+ const timeoutMs = request.hardLimits.timeoutMs;
3587
+ const timeoutError = new CandidateExecutionDeadlineError(timeoutMs);
3588
+ if (Date.now() >= deadlineAtMs) {
3589
+ return {
3590
+ kind: "error",
3591
+ error: timeoutError,
3592
+ termination: { kind: "timeout", timeoutMs },
3593
+ processStopped: true
3594
+ };
3595
+ }
3596
+ const controller = new AbortController();
3597
+ let timer;
3598
+ let timedOut = false;
3599
+ let capture;
3600
+ let executionError;
3601
+ const executionPromise = Promise.resolve().then(
3602
+ () => executor.execute(request, {
3603
+ traceStore,
3604
+ signal: controller.signal,
3605
+ deadlineAtMs
3606
+ })
3607
+ );
3608
+ void executionPromise.catch(() => void 0);
3609
+ const deadlinePromise = new Promise((_resolve, reject) => {
3610
+ timer = setTimeout(
3611
+ () => {
3612
+ timedOut = true;
3613
+ controller.abort(timeoutError);
3614
+ reject(timeoutError);
3615
+ },
3616
+ Math.max(0, deadlineAtMs - Date.now())
3617
+ );
3618
+ });
3619
+ void deadlinePromise.catch(() => void 0);
3620
+ try {
3621
+ capture = sealAgentCandidateProtectedRunCapture(
3622
+ await Promise.race([executionPromise, deadlinePromise])
3623
+ );
3624
+ } catch (error) {
3625
+ executionError = error;
3626
+ }
3627
+ if (!timedOut && capture && capture.executionId !== request.executionId) {
3628
+ executionError = new Error("candidate execution capture id does not match the request");
3629
+ capture = void 0;
3630
+ } else if (!timedOut && capture && Date.now() >= deadlineAtMs) {
3631
+ timedOut = true;
3632
+ executionError = timeoutError;
3633
+ capture = void 0;
3634
+ } else if (!timedOut && capture?.termination.kind === "timeout") {
3635
+ executionError = new Error("candidate executor cannot declare the runtime-owned timeout");
3636
+ capture = void 0;
3637
+ }
3638
+ if (!capture || timedOut) controller.abort(executionError);
3639
+ const stopReason = timedOut ? "timeout" : capture ? "completed" : "failed";
3640
+ let stopped;
3641
+ try {
3642
+ stopped = await withinCandidateCleanupDeadline(
3643
+ () => executor.stopAndCapture(
3644
+ {
3645
+ executionId: request.executionId,
3646
+ executionPlanDigest: request.executionPlan.value.digest
3647
+ },
3648
+ {
3649
+ traceStore,
3650
+ reason: stopReason,
3651
+ signal: controller.signal,
3652
+ deadlineAtMs
3653
+ }
3654
+ ),
3655
+ Date.now() + cleanupTimeoutMs,
3656
+ "candidate process termination"
3657
+ );
3658
+ if (!stopped || typeof stopped !== "object" || stopped.stopped !== true) {
3659
+ throw new Error("candidate executor did not acknowledge exact process termination");
3660
+ }
3661
+ } catch (stopError) {
3662
+ if (timer) clearTimeout(timer);
3663
+ controller.abort(stopError);
3664
+ return {
3665
+ kind: "error",
3666
+ error: new Error(joinErrors(executionError, stopError)),
3667
+ ...timedOut ? { termination: { kind: "timeout", timeoutMs } } : {},
3668
+ processStopped: false
3669
+ };
3670
+ }
3671
+ let finalCapture;
3672
+ try {
3673
+ finalCapture = sealAgentCandidateExecutorFinalCapture(stopped);
3674
+ } catch (captureError) {
3675
+ if (timer) clearTimeout(timer);
3676
+ controller.abort(captureError);
3677
+ return {
3678
+ kind: "error",
3679
+ error: new Error(joinErrors(executionError, captureError)),
3680
+ ...timedOut ? { termination: { kind: "timeout", timeoutMs } } : {},
3681
+ processStopped: true
3682
+ };
3683
+ }
3684
+ if (Date.now() >= deadlineAtMs) {
3685
+ timedOut = true;
3686
+ executionError = timeoutError;
3687
+ capture = void 0;
3688
+ controller.abort(timeoutError);
3689
+ }
3690
+ if (timer) clearTimeout(timer);
3691
+ if (timedOut) {
3692
+ return {
3693
+ kind: "timeout",
3694
+ termination: { kind: "timeout", timeoutMs },
3695
+ finalCapture,
3696
+ processStopped: true
3697
+ };
3698
+ }
3699
+ if (executionError || !capture) {
3700
+ return {
3701
+ kind: "error",
3702
+ error: executionError ?? new Error("candidate executor returned no capture"),
3703
+ finalCapture,
3704
+ processStopped: true
3705
+ };
3706
+ }
3707
+ return {
3708
+ kind: "capture",
3709
+ capture,
3710
+ termination: capture.termination,
3711
+ finalCapture,
3712
+ processStopped: true
3713
+ };
3714
+ }
3715
+ async function failBeforeActivation(prepared, state, error, reason, cleanupTimeoutMs) {
3716
+ beginPreparedCandidateSettlement(prepared);
3717
+ const cleanupDeadlineAtMs = candidateCleanupDeadline(cleanupTimeoutMs);
3718
+ const [memoryClose, settled] = await Promise.all([
3719
+ closeMemoryAccess(state, reason, cleanupDeadlineAtMs),
3720
+ settleModelGrant(state, reason, cleanupDeadlineAtMs)
3721
+ ]);
3722
+ const cleanupProven = memoryClose.closed && settled.settlement !== void 0;
3723
+ consumePreparedCandidateExecution(prepared, cleanupProven ? "failed" : "cleanup-failed");
3724
+ return failedAgentCandidateRun(
3725
+ state,
3726
+ redactProtectedReason(
3727
+ joinErrors(
3728
+ error,
3729
+ memoryClose.error,
3730
+ settled.error,
3731
+ !cleanupProven ? new Error("prepared access cleanup remains incomplete and may be retried by disposal") : void 0
3732
+ ),
3733
+ []
3734
+ ),
3735
+ void 0,
3736
+ settled.settlement?.usage ?? null
3737
+ );
3738
+ }
3739
+ async function failClaimedExecution(prepared, state, lease, claimStore, outputArtifacts, error, reason, cleanupTimeoutMs, failureClass, activation, memoryActivation) {
3740
+ beginPreparedCandidateSettlement(prepared);
3741
+ const cleanupDeadlineAtMs = candidateCleanupDeadline(cleanupTimeoutMs);
3742
+ const [memoryClose, settled] = await Promise.all([
3743
+ closeMemoryAccess(state, reason, cleanupDeadlineAtMs),
3744
+ settleModelGrant(state, reason, cleanupDeadlineAtMs)
3745
+ ]);
3746
+ const protectedValues = protectedEnvironmentValues(activation, memoryActivation);
3747
+ const safeReason = redactProtectedReason(
3748
+ joinErrors(error, memoryClose.error, settled.error),
3749
+ protectedValues
3750
+ );
3751
+ let finishFailed = false;
3752
+ let persistenceFailure;
3753
+ if (settled.settlement && memoryClose.closed) {
3754
+ try {
3755
+ const modelSettlement = await withinCandidateCleanupDeadline(
3756
+ () => persistCandidateModelSettlement(state, settled.settlement, outputArtifacts),
3757
+ lease.expiresAtMs,
3758
+ "candidate pre-run model-settlement persistence"
3759
+ );
3760
+ const failureEvidence = await withinCandidateCleanupDeadline(
3761
+ () => persistFailureEvidence(state, safeReason, failureClass, void 0, outputArtifacts),
3762
+ lease.expiresAtMs,
3763
+ "candidate pre-run failure-evidence persistence"
3764
+ );
3765
+ finishFailed = !await finishClaim(
3766
+ claimStore,
3767
+ lease,
3768
+ {
3769
+ schemaVersion: 1,
3770
+ status: "failed",
3771
+ failureClass,
3772
+ usage: settled.settlement.fixedUsage,
3773
+ modelSettlement: modelSettlement.artifact,
3774
+ failureEvidence
3775
+ },
3776
+ lease.expiresAtMs
3777
+ );
3778
+ } catch (persistenceError) {
3779
+ finishFailed = true;
3780
+ persistenceFailure = persistenceError;
3781
+ }
3782
+ }
3783
+ consumePreparedCandidateExecution(prepared, "failed");
3784
+ return failedAgentCandidateRun(
3785
+ state,
3786
+ redactProtectedReason(
3787
+ joinErrors(
3788
+ safeReason,
3789
+ persistenceFailure,
3790
+ memoryClose.error,
3791
+ settled.error,
3792
+ !memoryClose.closed || !settled.settlement ? new Error("candidate claim remains recoverable until protected cleanup is proven") : void 0,
3793
+ finishFailed ? new Error("candidate execution terminal record could not be persisted") : void 0
3794
+ ),
3795
+ protectedValues
3796
+ ),
3797
+ void 0,
3798
+ settled.settlement?.usage ?? null
3799
+ );
3800
+ }
3801
+ async function closeMemoryAccess(state, reason, cleanupDeadlineAtMs) {
3802
+ if (state.memory.mode === "disabled") return { closed: true };
3803
+ try {
3804
+ const reservation = state.memoryReservation;
3805
+ if (!reservation) throw new Error("isolated memory reservation is missing");
3806
+ const closed = await withinCandidateCleanupDeadline(
3807
+ () => state.ports.memory.close({
3808
+ executionId: state.executionId,
3809
+ preparationId: reservation.preparationId,
3810
+ accessDigest: reservation.accessDigest,
3811
+ effectiveNamespace: reservation.effectiveNamespace,
3812
+ reason
3813
+ }),
3814
+ cleanupDeadlineAtMs,
3815
+ "isolated memory closure"
3816
+ );
3817
+ if (closed.closed !== true || Object.keys(closed).some((key) => key !== "closed")) {
3818
+ throw new Error("isolated memory access did not acknowledge closure");
3819
+ }
3820
+ return { closed: true };
3821
+ } catch (error) {
3822
+ return { closed: false, error };
3823
+ }
3824
+ }
3825
+ async function settleModelGrant(state, reason, cleanupDeadlineAtMs) {
3826
+ try {
3827
+ const value = await withinCandidateCleanupDeadline(
3828
+ () => state.ports.models.settleGrant({
3829
+ executionId: state.executionId,
3830
+ preparationId: state.preparationId,
3831
+ grantDigest: state.modelReservation.digest,
3832
+ resolved: state.resolvedModel,
3833
+ reason
3834
+ }),
3835
+ cleanupDeadlineAtMs,
3836
+ "protected model settlement"
3837
+ );
3838
+ return {
3839
+ settlement: sealAgentCandidateModelSettlement(value, {
3840
+ preparationId: state.preparationId,
3841
+ grantDigest: state.modelReservation.digest,
3842
+ model: state.resolvedModel.model
3843
+ })
3844
+ };
3845
+ } catch (error) {
3846
+ return { error: new Error("protected model settlement failed", { cause: error }) };
3847
+ }
3848
+ }
3849
+ async function finishClaim(store, lease, terminal, deadlineAtMs) {
3850
+ try {
3851
+ const staged = await withinCandidateCleanupDeadline(
3852
+ () => store.stageTerminal(lease, terminal),
3853
+ deadlineAtMs ?? lease.expiresAtMs,
3854
+ "candidate terminal staging"
3855
+ );
3856
+ if (!staged.staged && !staged.exactReplay) return false;
3857
+ const result = await withinCandidateCleanupDeadline(
3858
+ () => store.finish(lease, staged.terminal.terminalDigest),
3859
+ deadlineAtMs ?? lease.expiresAtMs,
3860
+ "candidate terminal publication"
3861
+ );
3862
+ return result.finished || result.exactReplay;
3863
+ } catch {
3864
+ return false;
3865
+ }
3866
+ }
3867
+ async function persistFailureEvidence(state, reason, failureClass, termination, outputArtifacts) {
3868
+ const bytes = canonicalCandidateBytes({
3869
+ schemaVersion: 1,
3870
+ kind: "agent-candidate-execution-failure",
3871
+ executionId: state.executionId,
3872
+ bundleDigest: state.bundle.digest,
3873
+ executionPlanDigest: state.executionPlan.value.digest,
3874
+ failureClass,
3875
+ reason,
3876
+ ...termination ? { termination } : {}
3877
+ });
3878
+ return await persistCandidateOutputArtifact(outputArtifacts, {
3879
+ executionId: state.executionId,
3880
+ purpose: "failure-evidence",
3881
+ bytes
3882
+ });
3883
+ }
3884
+ function protectedEnvironmentValues(activation, memoryActivation) {
3885
+ return [...Object.values(activation?.env ?? {}), ...Object.values(memoryActivation?.env ?? {})];
3886
+ }
3887
+ function joinErrors(...errors) {
3888
+ return errors.filter((error) => error !== void 0).map(errorMessage).join("; ");
3889
+ }
3890
+ function errorMessage(error) {
3891
+ return error instanceof Error ? error.message : String(error);
3892
+ }
3893
+ var CandidateExecutionDeadlineError = class extends Error {
3894
+ constructor(timeoutMs) {
3895
+ super(`candidate execution reached its frozen ${timeoutMs}ms deadline`);
3896
+ this.name = "CandidateExecutionDeadlineError";
3897
+ }
3898
+ };
3899
+
3900
+ // src/candidate-execution/verify.ts
3901
+ import { agentCandidateBundleSchema } from "@tangle-network/agent-interface";
3902
+ var verifiedCandidateState = /* @__PURE__ */ new WeakMap();
3903
+ async function verifyAgentCandidateBundle(input, ports) {
3904
+ const parsed = agentCandidateBundleSchema.parse(input);
3905
+ const withoutDigest = omitTopLevelDigest(parsed);
3906
+ const actualDigest = canonicalCandidateDigest(withoutDigest);
3907
+ if (actualDigest !== parsed.digest) {
3908
+ throw new Error(`candidate bundle digest ${parsed.digest} does not match ${actualDigest}`);
3909
+ }
3910
+ const canonicalBytes = canonicalCandidateBytes(withoutDigest);
3911
+ verifyBytes(canonicalBytes, parsed.digest, canonicalBytes.byteLength, "candidate bundle");
3912
+ const artifactBytes = /* @__PURE__ */ new Map();
3913
+ const readArtifact = async (artifact) => {
3914
+ const key = artifactCacheKey(artifact);
3915
+ const existing = artifactBytes.get(key);
3916
+ if (existing) return Uint8Array.from(existing);
3917
+ const bytes = await readVerifiedArtifact(artifact, ports.artifacts);
3918
+ artifactBytes.set(key, Uint8Array.from(bytes));
3919
+ return bytes;
3920
+ };
3921
+ let patchBytes;
3922
+ if (parsed.code.kind === "git-patch") {
3923
+ patchBytes = await readArtifact(parsed.code.patch.artifact);
3924
+ }
3925
+ const materializedTree = await verifyCandidateCode(parsed.code, ports.repositories, patchBytes);
3926
+ const resourceBytes = /* @__PURE__ */ new Map();
3927
+ for (const resource of candidateResources(parsed)) {
3928
+ const bytes = resource.kind === "inline" ? Buffer.from(resource.content, "utf8") : await readCandidateGitHubResource(resource, ports.repositories);
3929
+ verifyBytes(
3930
+ bytes,
3931
+ resource.sha256,
3932
+ resource.byteLength,
3933
+ `candidate resource ${resource.name ?? (resource.kind === "github" ? resource.path : "<unnamed>")}`
3934
+ );
3935
+ resourceBytes.set(resourceKey(resource), Uint8Array.from(bytes));
3936
+ resourceBytes.set(resource.sha256, Uint8Array.from(bytes));
3937
+ }
3938
+ if (parsed.execution.workspace) {
3939
+ const workspace = await verifyWorkspaceSnapshotArtifacts(
3940
+ parsed.execution.workspace,
3941
+ ports.artifacts
3942
+ );
3943
+ artifactBytes.set(artifactCacheKey(parsed.execution.workspace.manifest), workspace.manifest);
3944
+ artifactBytes.set(artifactCacheKey(parsed.execution.workspace.archive), workspace.archive);
3945
+ }
3946
+ if (parsed.knowledge) await readArtifact(parsed.knowledge.manifest);
3947
+ if (parsed.memory.mode === "isolated" && parsed.memory.seed)
3948
+ await readArtifact(parsed.memory.seed);
3949
+ deepFreezeCandidate(parsed);
3950
+ const verified = Object.freeze({
3951
+ bundle: parsed,
3952
+ ...materializedTree === void 0 ? {} : { materializedTree },
3953
+ [verifiedCandidateBrand]: true
3954
+ });
3955
+ verifiedCandidateState.set(verified, { ports, artifactBytes, resourceBytes });
3956
+ return verified;
3957
+ }
3958
+ function getVerifiedCandidateState(candidate) {
3959
+ const state = verifiedCandidateState.get(candidate);
3960
+ if (!state || candidate[verifiedCandidateBrand] !== true) {
3961
+ throw new Error("candidate must come from verifyAgentCandidateBundle");
3962
+ }
3963
+ return state;
3964
+ }
3965
+ async function verifiedArtifactBytes(candidate, artifact) {
3966
+ const state = getVerifiedCandidateState(candidate);
3967
+ const key = artifactCacheKey(artifact);
3968
+ const existing = state.artifactBytes.get(key);
3969
+ if (existing) return Uint8Array.from(existing);
3970
+ const bytes = await readVerifiedArtifact(artifact, state.ports.artifacts);
3971
+ state.artifactBytes.set(key, Uint8Array.from(bytes));
3972
+ return bytes;
3973
+ }
3974
+ function verifiedResourceTextByDigest(candidate) {
3975
+ const output = /* @__PURE__ */ new Map();
3976
+ for (const resource of candidateResources(candidate.bundle)) {
3977
+ const bytes = getVerifiedCandidateState(candidate).resourceBytes.get(resource.sha256);
3978
+ if (!bytes) throw new Error(`candidate resource digest was not verified: ${resource.sha256}`);
3979
+ output.set(resource.sha256, new TextDecoder("utf-8", { fatal: true }).decode(bytes));
3980
+ }
3981
+ return output;
3982
+ }
3983
+ function candidateResources(bundle) {
3984
+ const resources = bundle.profile.resources;
3985
+ if (!resources) return [];
3986
+ const output = [];
3987
+ for (const mount of resources.files ?? []) output.push(mount.resource);
3988
+ output.push(...resources.tools ?? []);
3989
+ output.push(...resources.skills ?? []);
3990
+ output.push(...resources.agents ?? []);
3991
+ output.push(...resources.commands ?? []);
3992
+ if (typeof resources.instructions === "object") output.push(resources.instructions);
3993
+ return output;
3994
+ }
3995
+ function resourceKey(resource) {
3996
+ return canonicalCandidateDigest(resource);
3997
+ }
3998
+
3999
+ // src/candidate-execution/prepare.ts
4000
+ import { randomBytes as randomBytes2 } from "crypto";
4001
+ import { lstat as lstat2, readdir as readdir2 } from "fs/promises";
4002
+ import { isAbsolute, posix, relative as relative2, resolve as resolveHostPath } from "path";
4003
+ import {
4004
+ agentCandidateContainerSchema,
4005
+ agentCandidateExecutionLimitsSchema,
4006
+ agentCandidateExecutionPlanEvidenceSchema as agentCandidateExecutionPlanEvidenceSchema2,
4007
+ agentCandidateExecutionPlanMaterialSchema,
4008
+ agentCandidateMaterializationReceiptSchema as agentCandidateMaterializationReceiptSchema2,
4009
+ agentCandidateModelAccessNetworkSchema,
4010
+ agentCandidateWorkspaceSnapshotEvidenceSchema as agentCandidateWorkspaceSnapshotEvidenceSchema3,
4011
+ sha256DigestSchema
4012
+ } from "@tangle-network/agent-interface";
4013
+ import {
4014
+ applyAgentCandidateWorkspacePlan,
4015
+ materializeCandidateProfile
4016
+ } from "@tangle-network/agent-profile-materialize";
4017
+ var MATERIALIZER_HARNESSES = /* @__PURE__ */ new Set([
4018
+ "claude-code",
4019
+ "claude",
4020
+ "claudish",
4021
+ "nanoclaw",
4022
+ "codex",
4023
+ "opencode",
4024
+ "kimi-code",
4025
+ "kimi",
4026
+ "pi",
4027
+ "gemini",
4028
+ "hermes",
4029
+ "openclaw"
4030
+ ]);
4031
+ var MIN_RESERVATION_TTL_MS = 15 * 6e4;
4032
+ var PREPARED_HOLD_MARGIN_MS = 5 * 6e4;
4033
+ async function prepareAgentCandidateExecution(candidate, task, ports, options = {}) {
4034
+ const cleanupTimeoutMs = candidateCleanupTimeout(options.cleanupTimeoutMs);
4035
+ const verifiedState = getVerifiedCandidateState(candidate);
4036
+ assertSameVerificationPorts(verifiedState.ports, ports);
4037
+ const bundle = candidate.bundle;
4038
+ const harness = materializerHarness(bundle.execution.harness);
4039
+ assertTaskInput(task, bundle.execution.instructionDelivery);
4040
+ const resultTimeoutMs = candidateResultTimeout(options.resultTimeoutMs, task.limits.timeoutMs);
4041
+ const ownerWindowMs = candidateExecutionOwnerWindowMs(
4042
+ task.limits.timeoutMs,
4043
+ cleanupTimeoutMs,
4044
+ resultTimeoutMs
4045
+ );
4046
+ const reservationWindowMs = ownerWindowMs + PREPARED_HOLD_MARGIN_MS;
4047
+ if (reservationWindowMs > MAX_CANDIDATE_TIMER_INTERVAL_MS) {
4048
+ throw new Error("candidate reservation window exceeds the supported timer range");
4049
+ }
4050
+ assertDisjointHostStagingRoots(task);
4051
+ const instructionBytes = Buffer.from(task.instruction, "utf8");
4052
+ const instructionDigest = sha256Bytes(instructionBytes);
4053
+ const taskArtifacts = await verifyWorkspaceSnapshotArtifacts(task.workspace, ports.artifacts);
4054
+ await ports.workspaces.materialize({
4055
+ role: "task",
4056
+ snapshot: task.workspace,
4057
+ archive: taskArtifacts.archive,
4058
+ destination: task.stagingRoots.taskRoot
4059
+ });
4060
+ await verifyMaterializedWorkspace(task.stagingRoots.taskRoot, task.workspace.material, {
4061
+ ignoredProtectedRootEntries: [".git", ".sidecar"]
4062
+ });
4063
+ await verifyTaskCheckout(task.stagingRoots.taskRoot, task.repository);
4064
+ const taskExecutorFiles = await readMaterializedWorkspaceFiles(
4065
+ task.stagingRoots.taskRoot,
4066
+ task.workspace.material,
4067
+ { ignoredProtectedRootEntries: [".git", ".sidecar"] }
4068
+ );
4069
+ let candidateArchive;
4070
+ let candidateExecutorFiles;
4071
+ if (bundle.execution.workspace) {
4072
+ if (!task.stagingRoots.candidateRoot || !task.executionRoots.candidateRoot) {
4073
+ throw new Error("active candidate execution requires host and container candidate roots");
4074
+ }
4075
+ candidateArchive = await verifiedArtifactBytes(candidate, bundle.execution.workspace.archive);
4076
+ await ports.workspaces.materialize({
4077
+ role: "candidate",
4078
+ snapshot: bundle.execution.workspace,
4079
+ archive: candidateArchive,
4080
+ destination: task.stagingRoots.candidateRoot
4081
+ });
4082
+ await verifyMaterializedWorkspace(
4083
+ task.stagingRoots.candidateRoot,
4084
+ bundle.execution.workspace.material
4085
+ );
4086
+ candidateExecutorFiles = await readMaterializedWorkspaceFiles(
4087
+ task.stagingRoots.candidateRoot,
4088
+ bundle.execution.workspace.material
4089
+ );
4090
+ } else if (task.stagingRoots.candidateRoot || task.executionRoots.candidateRoot) {
4091
+ throw new Error("disabled code cannot receive a candidate workspace root");
4092
+ }
4093
+ await assertEmptyDirectory(task.stagingRoots.profileRoot);
4094
+ const profileWorkspacePlan = materializeCandidateProfile(bundle.profile, harness, {
4095
+ resolvedResources: verifiedResourceTextByDigest(candidate)
4096
+ });
4097
+ const profileApplication = applyAgentCandidateWorkspacePlan(
4098
+ profileWorkspacePlan,
4099
+ task.stagingRoots.profileRoot,
4100
+ bundle.execution.cwd.workspace
4101
+ );
4102
+ await verifyMaterializedProfileWorkspace(
4103
+ task.stagingRoots.profileRoot,
4104
+ profileApplication.profilePlan.material
4105
+ );
4106
+ const profilePlanBytes = await readVerifiedArtifact(
4107
+ profileApplication.profilePlan.artifact,
4108
+ ports.artifacts
4109
+ );
4110
+ if (!Buffer.from(profilePlanBytes).equals(
4111
+ Buffer.from(canonicalCandidateBytes(profileApplication.profilePlan.material))
4112
+ )) {
4113
+ throw new Error("profile materializer did not capture exact canonical plan bytes");
4114
+ }
4115
+ const container = await resolveContainer(candidate, task, ports);
4116
+ const resolvedModel = await resolveModel(candidate, task, ports);
4117
+ const preparationId = `candidate-preparation-v1.${randomBytes2(32).toString("base64url")}`;
4118
+ const reservationExpiresAtMs = Date.now() + Math.max(MIN_RESERVATION_TTL_MS, reservationWindowMs);
4119
+ const modelReservation = await withinCandidateCleanupDeadline(
4120
+ () => ports.models.reserveGrant({
4121
+ executionId: task.executionId,
4122
+ preparationId,
4123
+ expiresAtMs: reservationExpiresAtMs,
4124
+ attempt: task.attempt,
4125
+ bundleDigest: bundle.digest,
4126
+ resolved: resolvedModel,
4127
+ limits: modelLimits2(task.limits)
4128
+ }),
4129
+ candidateCleanupDeadline(cleanupTimeoutMs),
4130
+ "protected model reservation"
4131
+ );
4132
+ let preparedMemory;
4133
+ try {
4134
+ validateProtectedModelReservation(
4135
+ modelReservation,
4136
+ task.limits,
4137
+ preparationId,
4138
+ reservationExpiresAtMs
4139
+ );
4140
+ preparedMemory = await prepareMemory(
4141
+ candidate,
4142
+ task,
4143
+ ports,
4144
+ preparationId,
4145
+ reservationExpiresAtMs,
4146
+ cleanupTimeoutMs
4147
+ );
4148
+ const memory = preparedMemory.value;
4149
+ const knowledge = bundle.knowledge ? {
4150
+ snapshotId: bundle.knowledge.snapshotId,
4151
+ manifestDigest: bundle.knowledge.manifest.sha256,
4152
+ manifest: await verifiedArtifactBytes(candidate, bundle.knowledge.manifest)
4153
+ } : void 0;
4154
+ const baseLaunch = buildLaunch(candidate, task, profileApplication.flags);
4155
+ const publicEnv = mergePublicEnvironment(
4156
+ bundle.execution.env ?? {},
4157
+ profileApplication.env,
4158
+ bundle.execution.instructionDelivery.kind === "utf8-file" ? {
4159
+ [bundle.execution.instructionDelivery.env]: {
4160
+ kind: "public",
4161
+ value: bundle.execution.instructionDelivery.path
4162
+ }
4163
+ } : {}
4164
+ );
4165
+ const routes = modelRoutes(bundle.profile, task.model.requested);
4166
+ const executionMaterial = {
4167
+ schemaVersion: 1,
4168
+ kind: "agent-candidate-execution-plan-material",
4169
+ bundleDigest: bundle.digest,
4170
+ executionId: task.executionId,
4171
+ attempt: task.attempt,
4172
+ task: {
4173
+ benchmark: task.benchmark,
4174
+ benchmarkVersion: task.benchmarkVersion,
4175
+ taskId: task.taskId,
4176
+ splitDigest: task.splitDigest,
4177
+ instruction: {
4178
+ encoding: "utf8",
4179
+ sha256: instructionDigest,
4180
+ byteLength: instructionBytes.byteLength,
4181
+ delivery: bundle.execution.instructionDelivery
4182
+ },
4183
+ repository: task.repository,
4184
+ workspace: task.workspace
4185
+ },
4186
+ workspaces: {
4187
+ taskRoot: task.executionRoots.taskRoot,
4188
+ ...task.executionRoots.candidateRoot ? { candidateRoot: task.executionRoots.candidateRoot } : {}
4189
+ },
4190
+ codeKind: bundle.code.kind,
4191
+ ...bundle.execution.workspace ? { candidateWorkspace: bundle.execution.workspace } : {},
4192
+ profile: profileApplication.application,
4193
+ harness: bundle.execution.harness,
4194
+ harnessVersion: bundle.execution.harnessVersion,
4195
+ container,
4196
+ model: {
4197
+ policy: "single",
4198
+ resolved: resolvedModel,
4199
+ access: {
4200
+ kind: "evaluator-mediated",
4201
+ grantDigest: modelReservation.digest,
4202
+ network: modelReservation.network
4203
+ },
4204
+ routes
4205
+ },
4206
+ grader: task.grader,
4207
+ launch: {
4208
+ executable: baseLaunch.executable,
4209
+ args: baseLaunch.args,
4210
+ env: publicEnv,
4211
+ cwd: bundle.execution.cwd
4212
+ },
4213
+ ...bundle.knowledge ? { knowledgeManifestDigest: bundle.knowledge.manifest.sha256 } : {},
4214
+ memory,
4215
+ limits: task.limits,
4216
+ network: { mode: "disabled" }
4217
+ };
4218
+ agentCandidateExecutionPlanMaterialSchema.parse(executionMaterial);
4219
+ const executionBytes = canonicalCandidateBytes(executionMaterial);
4220
+ const executionDigest = canonicalCandidateDigest(executionMaterial);
4221
+ if (sha256Bytes(executionBytes) !== executionDigest) {
4222
+ throw new Error("execution plan canonical serializers disagree");
4223
+ }
4224
+ const executionPlan = agentCandidateExecutionPlanEvidenceSchema2.parse({
4225
+ schemaVersion: 1,
4226
+ kind: "agent-candidate-execution-plan",
4227
+ digest: executionDigest,
4228
+ material: executionMaterial,
4229
+ artifact: embeddedCandidateArtifact(executionBytes)
4230
+ });
4231
+ const entrypoint = candidateEntrypointReceipt(candidate);
4232
+ const materializationReceipt = canonicalCandidateDocument(
4233
+ {
4234
+ schemaVersion: 1,
4235
+ kind: "agent-candidate-materialization",
4236
+ digestAlgorithm: "rfc8785-sha256",
4237
+ bundleDigest: bundle.digest,
4238
+ profilePlan: profileApplication.profilePlan,
4239
+ executionPlan,
4240
+ ...bundle.execution.workspace ? { candidateWorkspace: bundle.execution.workspace } : {},
4241
+ codeKind: bundle.code.kind,
4242
+ ...candidate.materializedTree ? { materializedTree: candidate.materializedTree } : {},
4243
+ harness: bundle.execution.harness,
4244
+ harnessVersion: bundle.execution.harnessVersion,
4245
+ container,
4246
+ resolvedModel,
4247
+ ...bundle.knowledge ? { knowledgeManifestDigest: bundle.knowledge.manifest.sha256 } : {},
4248
+ ...entrypoint ? { entrypoint } : {}
4249
+ }
4250
+ );
4251
+ agentCandidateMaterializationReceiptSchema2.parse(materializationReceipt.value);
4252
+ const traceRunId = `${task.executionId}:attempt-${task.attempt.number}:${canonicalCandidateDigest({ preparationId }).slice(7, 23)}`;
4253
+ const traceTags = {
4254
+ [CANDIDATE_TRACE_TAGS.executionId]: task.executionId,
4255
+ [CANDIDATE_TRACE_TAGS.bundleDigest]: bundle.digest,
4256
+ [CANDIDATE_TRACE_TAGS.executionPlanDigest]: executionPlan.digest,
4257
+ [CANDIDATE_TRACE_TAGS.materializationReceiptDigest]: materializationReceipt.digest
4258
+ };
4259
+ const traceEnv = {
4260
+ [CANDIDATE_TRACE_ENV.executionId]: task.executionId,
4261
+ [CANDIDATE_TRACE_ENV.bundleDigest]: bundle.digest,
4262
+ [CANDIDATE_TRACE_ENV.executionPlanDigest]: executionPlan.digest,
4263
+ [CANDIDATE_TRACE_ENV.materializationReceiptDigest]: materializationReceipt.digest,
4264
+ [CANDIDATE_TRACE_ENV.traceRunId]: traceRunId
4265
+ };
4266
+ assertEnvironmentDisjoint(publicEnv, traceEnv);
4267
+ return createPreparedCandidateExecution({
4268
+ ports,
4269
+ bundle,
4270
+ executionId: task.executionId,
4271
+ roots: {
4272
+ execution: { ...task.executionRoots },
4273
+ staging: { ...task.stagingRoots }
4274
+ },
4275
+ profilePlan: {
4276
+ value: profileApplication.profilePlan,
4277
+ bytes: profilePlanBytes,
4278
+ written: [...profileApplication.application.mountPaths]
4279
+ },
4280
+ executionPlan: { value: executionPlan, bytes: executionBytes },
4281
+ materializationReceipt,
4282
+ launch: {
4283
+ executable: baseLaunch.executable,
4284
+ args: baseLaunch.args.map((value) => value.value),
4285
+ env: unwrapPublicEnvironment(publicEnv),
4286
+ flags: profileApplication.flags.map((value) => value.value),
4287
+ cwd: absoluteExecutionCwd(bundle.execution.cwd, task.executionRoots)
4288
+ },
4289
+ instruction: {
4290
+ bytes: Uint8Array.from(instructionBytes),
4291
+ delivery: bundle.execution.instructionDelivery
4292
+ },
4293
+ resolvedModel,
4294
+ preparationId,
4295
+ reservationExpiresAtMs,
4296
+ cleanupTimeoutMs,
4297
+ resultTimeoutMs,
4298
+ modelReservation: {
4299
+ preparationId: modelReservation.preparationId,
4300
+ digest: modelReservation.digest,
4301
+ expiresAtMs: modelReservation.expiresAtMs,
4302
+ enforcedLimits: modelReservation.enforcedLimits,
4303
+ network: modelReservation.network
4304
+ },
4305
+ executorInputs: {
4306
+ taskFiles: taskExecutorFiles,
4307
+ ...candidateExecutorFiles ? { candidateFiles: candidateExecutorFiles } : {},
4308
+ profileFiles: exactProfileExecutorFiles(
4309
+ profileWorkspacePlan.files,
4310
+ profileApplication.profilePlan.material.files
4311
+ )
4312
+ },
4313
+ ...preparedMemory.accessDigest && preparedMemory.value.mode === "isolated" ? {
4314
+ memoryReservation: {
4315
+ preparationId,
4316
+ accessDigest: preparedMemory.accessDigest,
4317
+ expiresAtMs: reservationExpiresAtMs,
4318
+ effectiveNamespace: preparedMemory.value.effectiveNamespace
4319
+ }
4320
+ } : {},
4321
+ ...knowledge ? { knowledge } : {},
4322
+ trace: { runId: traceRunId, tags: traceTags, env: traceEnv },
4323
+ memory
4324
+ });
4325
+ } catch (error) {
4326
+ const cleanupDeadlineAtMs = candidateCleanupDeadline(cleanupTimeoutMs);
4327
+ const cleanup = [];
4328
+ if (preparedMemory?.value.mode === "isolated") {
4329
+ const accessDigest = preparedMemory.accessDigest;
4330
+ const effectiveNamespace = preparedMemory.value.effectiveNamespace;
4331
+ if (!accessDigest) throw new Error("isolated memory preparation is missing access identity");
4332
+ cleanup.push(
4333
+ withinCandidateCleanupDeadline(
4334
+ async () => {
4335
+ const closed = await ports.memory.close({
4336
+ executionId: task.executionId,
4337
+ preparationId,
4338
+ accessDigest,
4339
+ effectiveNamespace,
4340
+ reason: "preparation-failed"
4341
+ });
4342
+ if (closed.closed !== true || Object.keys(closed).some((key) => key !== "closed")) {
4343
+ throw new Error("failed preparation did not close isolated memory access");
4344
+ }
4345
+ },
4346
+ cleanupDeadlineAtMs,
4347
+ "failed preparation memory cleanup"
4348
+ )
4349
+ );
4350
+ }
4351
+ cleanup.push(
4352
+ withinCandidateCleanupDeadline(
4353
+ async () => {
4354
+ const settlement = sealAgentCandidateModelSettlement(
4355
+ await ports.models.settleGrant({
4356
+ executionId: task.executionId,
4357
+ preparationId,
4358
+ grantDigest: modelReservation.digest,
4359
+ resolved: resolvedModel,
4360
+ reason: "preparation-failed"
4361
+ }),
4362
+ {
4363
+ preparationId,
4364
+ grantDigest: modelReservation.digest,
4365
+ model: resolvedModel.model
4366
+ }
4367
+ );
4368
+ if (settlement.usage.modelCalls !== 0) {
4369
+ throw new Error("failed preparation unexpectedly contains model calls");
4370
+ }
4371
+ },
4372
+ cleanupDeadlineAtMs,
4373
+ "failed preparation model cleanup"
4374
+ )
4375
+ );
4376
+ const cleanupResults = await Promise.allSettled(cleanup);
4377
+ const cleanupErrors = cleanupResults.filter((result) => result.status === "rejected").map((result) => result.reason);
4378
+ if (cleanupErrors.length > 0) {
4379
+ throw new Error(
4380
+ `candidate preparation failed and protected access cleanup failed: ${cleanupErrors.map(errorMessage2).join("; ")}`,
4381
+ { cause: error }
4382
+ );
4383
+ }
4384
+ throw error;
4385
+ }
4386
+ }
4387
+ function assertSameVerificationPorts(verified, execution) {
4388
+ if (verified.artifacts !== execution.artifacts || verified.repositories !== execution.repositories) {
4389
+ throw new Error(
4390
+ "prepare must use the same artifact and repository ports that verified the bundle"
4391
+ );
4392
+ }
4393
+ }
4394
+ function assertTaskInput(task, delivery) {
4395
+ const requiredStrings = [
4396
+ ["executionId", task.executionId],
4397
+ ["benchmark", task.benchmark],
4398
+ ["benchmarkVersion", task.benchmarkVersion],
4399
+ ["taskId", task.taskId],
4400
+ ["repository identity", task.repository.identity],
4401
+ ["repository root identity", task.repository.rootIdentity]
4402
+ ];
4403
+ for (const [name, value] of requiredStrings) {
4404
+ if (!value.trim()) throw new Error(`${name} must be non-empty`);
4405
+ }
4406
+ if (!/^[A-Za-z0-9._:-]{1,200}$/.test(task.executionId)) {
4407
+ throw new Error("executionId must be a stable filesystem-neutral identifier");
4408
+ }
4409
+ if (!task.instruction || !isWellFormedUnicode(task.instruction)) {
4410
+ throw new Error("task instruction must be non-empty well-formed Unicode");
4411
+ }
4412
+ sha256DigestSchema.parse(task.splitDigest);
4413
+ agentCandidateWorkspaceSnapshotEvidenceSchema3.parse(task.workspace);
4414
+ agentCandidateExecutionLimitsSchema.parse(task.limits);
4415
+ if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(task.repository.baseCommit)) {
4416
+ throw new Error("task repository base commit is not a full Git object id");
4417
+ }
4418
+ if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(task.repository.baseTree)) {
4419
+ throw new Error("task repository base tree is not a full Git object id");
4420
+ }
4421
+ if (task.repository.baseCommit.length !== task.repository.baseTree.length) {
4422
+ throw new Error("task repository Git object formats disagree");
4423
+ }
4424
+ for (const [name, root] of [
4425
+ ["execution task root", task.executionRoots.taskRoot],
4426
+ ["execution candidate root", task.executionRoots.candidateRoot],
4427
+ ["staging task root", task.stagingRoots.taskRoot],
4428
+ ["staging candidate root", task.stagingRoots.candidateRoot],
4429
+ ["staging profile root", task.stagingRoots.profileRoot]
4430
+ ]) {
4431
+ if (root === void 0) continue;
4432
+ const canonical = name.startsWith("execution") ? posix.isAbsolute(root) && posix.normalize(root) === root : isAbsolute(root) && resolveHostPath(root) === root;
4433
+ if (!canonical) throw new Error(`${name} must be a canonical absolute path`);
4434
+ }
4435
+ if (!Number.isInteger(task.attempt.number) || !Number.isInteger(task.attempt.maxAttempts) || task.attempt.number < 1 || task.attempt.number > task.attempt.maxAttempts || task.attempt.retryPolicy === "none" && task.attempt.maxAttempts !== 1) {
4436
+ throw new Error("task attempt policy is invalid");
4437
+ }
4438
+ const limits = task.limits;
4439
+ if (!Number.isInteger(limits.timeoutMs) || limits.timeoutMs <= 0 || limits.timeoutMs > MAX_CANDIDATE_TIMER_INTERVAL_MS || !Number.isInteger(limits.maxSteps) || limits.maxSteps <= 0 || !Number.isInteger(limits.maxModelCalls) || limits.maxModelCalls < 0 || !Number.isInteger(limits.maxInputTokens) || limits.maxInputTokens < 0 || !Number.isInteger(limits.maxOutputTokens) || limits.maxOutputTokens < 0 || !Number.isFinite(limits.maxCostUsd) || limits.maxCostUsd < 0) {
4440
+ throw new Error("task execution limits are invalid");
4441
+ }
4442
+ usdToNanos(limits.maxCostUsd, "task maxCostUsd");
4443
+ if (!task.model.requested.trim()) throw new Error("evaluator model request must be non-empty");
4444
+ if (!task.grader.name.trim() || !task.grader.version.trim()) {
4445
+ throw new Error("evaluator benchmark grader identity must be non-empty");
4446
+ }
4447
+ if (!Number.isInteger(task.grader.artifact.byteLength) || task.grader.artifact.byteLength <= 0) {
4448
+ throw new Error("evaluator benchmark grader artifact must be non-empty");
4449
+ }
4450
+ sha256DigestSchema.parse(task.grader.artifact.sha256);
4451
+ if (task.evaluatorTaskContainer) {
4452
+ if (task.evaluatorTaskContainer.source !== "evaluator-task-container" || !task.evaluatorTaskContainer.image.trim() || !task.evaluatorTaskContainer.platform.os.trim() || !task.evaluatorTaskContainer.platform.architecture.trim()) {
4453
+ throw new Error("evaluator task container evidence is incomplete");
4454
+ }
4455
+ sha256DigestSchema.parse(task.evaluatorTaskContainer.indexDigest);
4456
+ sha256DigestSchema.parse(task.evaluatorTaskContainer.manifestDigest);
4457
+ agentCandidateContainerSchema.parse({
4458
+ image: task.evaluatorTaskContainer.image,
4459
+ indexDigest: task.evaluatorTaskContainer.indexDigest
4460
+ });
4461
+ }
4462
+ if (delivery.kind === "utf8-file") {
4463
+ if (executionPathsOverlap(task.executionRoots.taskRoot, delivery.path) || task.executionRoots.candidateRoot !== void 0 && executionPathsOverlap(task.executionRoots.candidateRoot, delivery.path)) {
4464
+ throw new Error("task instruction file must remain outside execution workspaces");
4465
+ }
4466
+ }
4467
+ }
4468
+ function executionPathsOverlap(left, right) {
4469
+ const a = posix.normalize(left);
4470
+ const b = posix.normalize(right);
4471
+ return a === b || b.startsWith(a === "/" ? "/" : `${a}/`) || a.startsWith(b === "/" ? "/" : `${b}/`);
4472
+ }
4473
+ function assertDisjointHostStagingRoots(task) {
4474
+ const roots = [
4475
+ task.stagingRoots.taskRoot,
4476
+ task.stagingRoots.candidateRoot,
4477
+ task.stagingRoots.profileRoot
4478
+ ].filter((value) => value !== void 0).map((value) => resolveHostPath(value));
4479
+ for (let left = 0; left < roots.length; left++) {
4480
+ for (let right = left + 1; right < roots.length; right++) {
4481
+ const a = roots[left];
4482
+ const b = roots[right];
4483
+ if (a && b && (a === b || isContainedPath(a, b) || isContainedPath(b, a))) {
4484
+ throw new Error("host task, candidate, and profile staging roots must be disjoint");
4485
+ }
4486
+ }
4487
+ }
4488
+ }
4489
+ function isContainedPath(parent, child) {
4490
+ const path = relative2(parent, child);
4491
+ return path !== "" && !path.startsWith("..") && !isAbsolute(path);
4492
+ }
4493
+ async function assertEmptyDirectory(path) {
4494
+ const stats = await lstat2(path);
4495
+ if (!stats.isDirectory() || stats.isSymbolicLink()) {
4496
+ throw new Error("profile staging root must be a real directory");
4497
+ }
4498
+ if ((await readdir2(path)).length !== 0) {
4499
+ throw new Error("profile staging root must be empty before materialization");
4500
+ }
4501
+ }
4502
+ function materializerHarness(harness) {
4503
+ if (!MATERIALIZER_HARNESSES.has(harness)) {
4504
+ throw new Error(
4505
+ `sealed candidate profile materialization is unsupported for harness ${harness}`
4506
+ );
4507
+ }
4508
+ return harness;
4509
+ }
4510
+ async function resolveContainer(candidate, task, ports) {
4511
+ const environment = candidate.bundle.execution.environment;
4512
+ const pinned = environment.kind === "pinned-container" ? environment.container : void 0;
4513
+ if (environment.kind === "evaluator-task-container" && !task.evaluatorTaskContainer) {
4514
+ throw new Error("evaluator-task-container candidate requires an evaluator-owned task image");
4515
+ }
4516
+ if (environment.kind === "pinned-container" && task.evaluatorTaskContainer) {
4517
+ throw new Error("pinned candidate containers cannot be replaced by a task image");
4518
+ }
4519
+ const resolved = await ports.containers.resolve({
4520
+ candidate: pinned,
4521
+ evaluatorTaskContainer: task.evaluatorTaskContainer
4522
+ });
4523
+ if (resolved.source !== environment.kind) throw new Error("resolved container source drifted");
4524
+ if (pinned && (resolved.image !== pinned.image || resolved.indexDigest !== pinned.indexDigest)) {
4525
+ throw new Error("resolved pinned container does not match the candidate image index");
4526
+ }
4527
+ if (task.evaluatorTaskContainer && JSON.stringify(resolved) !== JSON.stringify(task.evaluatorTaskContainer)) {
4528
+ throw new Error("resolved task container does not match evaluator-owned image evidence");
4529
+ }
4530
+ return resolved;
4531
+ }
4532
+ async function resolveModel(candidate, task, ports) {
4533
+ const hints = candidate.bundle.profile.model;
4534
+ if (hints?.default !== void 0 && hints.default !== task.model.requested) {
4535
+ throw new Error("candidate model preference conflicts with the evaluator-owned model");
4536
+ }
4537
+ if (hints?.reasoningEffort !== void 0 && hints.reasoningEffort !== task.model.reasoningEffort) {
4538
+ throw new Error("candidate reasoning effort conflicts with the evaluator-owned effort");
4539
+ }
4540
+ const resolved = await ports.models.resolve({
4541
+ requested: task.model.requested,
4542
+ harness: candidate.bundle.execution.harness,
4543
+ reasoningEffort: task.model.reasoningEffort
4544
+ });
4545
+ if (resolved.requested !== task.model.requested || resolved.reasoningEffort !== task.model.reasoningEffort) {
4546
+ throw new Error("model resolver drifted from the evaluator-owned request");
4547
+ }
4548
+ return resolved;
4549
+ }
4550
+ async function prepareMemory(candidate, task, ports, preparationId, expiresAtMs, cleanupTimeoutMs) {
4551
+ const policy = candidate.bundle.memory;
4552
+ if (policy.mode === "disabled") return { value: { mode: "disabled" } };
4553
+ const seed = policy.seed ? await verifiedArtifactBytes(candidate, policy.seed) : void 0;
4554
+ const executionSegment = canonicalCandidateDigest({ executionId: task.executionId }).slice(7);
4555
+ const taskSegment = canonicalCandidateDigest({ taskId: task.taskId }).slice(7);
4556
+ const preparationSegment = canonicalCandidateDigest({ preparationId }).slice(7, 23);
4557
+ const effectiveNamespace = `candidate/${candidate.bundle.digest.slice(7, 23)}/${executionSegment}/${taskSegment}/${preparationSegment}`;
4558
+ const reset = await withinCandidateCleanupDeadline(
4559
+ () => ports.memory.reset({
4560
+ executionId: task.executionId,
4561
+ preparationId,
4562
+ expiresAtMs,
4563
+ effectiveNamespace,
4564
+ ...seed ? { seed } : {},
4565
+ ...policy.seed ? { seedDigest: policy.seed.sha256 } : {}
4566
+ }),
4567
+ candidateCleanupDeadline(cleanupTimeoutMs),
4568
+ "isolated memory reset"
4569
+ );
4570
+ try {
4571
+ if (reset.preparationId !== preparationId || reset.expiresAtMs !== expiresAtMs || !/^sha256:[a-f0-9]{64}$/.test(reset.accessDigest)) {
4572
+ throw new Error("isolated memory reservation is not scoped to this preparation");
4573
+ }
4574
+ await readVerifiedArtifact(reset.evidence, ports.artifacts);
4575
+ await verifyWorkspaceSnapshotArtifacts(reset.beforeState, ports.artifacts);
4576
+ return {
4577
+ value: {
4578
+ mode: "isolated",
4579
+ scope: "task",
4580
+ effectiveNamespace,
4581
+ reset: {
4582
+ kind: "fresh",
4583
+ evidence: reset.evidence,
4584
+ emptyStateDigest: reset.emptyStateDigest
4585
+ },
4586
+ beforeState: reset.beforeState,
4587
+ ...policy.seed ? { seedDigest: policy.seed.sha256 } : {}
4588
+ },
4589
+ accessDigest: reset.accessDigest
4590
+ };
4591
+ } catch (error) {
4592
+ try {
4593
+ const closed = await withinCandidateCleanupDeadline(
4594
+ () => ports.memory.close({
4595
+ executionId: task.executionId,
4596
+ preparationId,
4597
+ accessDigest: reset.accessDigest,
4598
+ effectiveNamespace,
4599
+ reason: "preparation-failed"
4600
+ }),
4601
+ candidateCleanupDeadline(cleanupTimeoutMs),
4602
+ "invalid isolated memory reset cleanup"
4603
+ );
4604
+ if (closed.closed !== true || Object.keys(closed).some((key) => key !== "closed")) {
4605
+ throw new Error("invalid isolated memory reset did not acknowledge closure");
4606
+ }
4607
+ } catch (closeError) {
4608
+ throw new Error("isolated memory preparation and cleanup both failed", {
4609
+ cause: new AggregateError([error, closeError])
4610
+ });
4611
+ }
4612
+ throw error;
4613
+ }
4614
+ }
4615
+ function buildLaunch(candidate, task, profileFlags) {
4616
+ const launch = candidate.bundle.execution.launch;
4617
+ if (launch.kind === "container-command") {
4618
+ return { executable: launch.executable, args: [...launch.args ?? [], ...profileFlags] };
4619
+ }
4620
+ const candidateRoot = task.executionRoots.candidateRoot;
4621
+ if (!candidateRoot) throw new Error("candidate entrypoint requires a container candidate root");
4622
+ const entrypoint = posix.join(candidateRoot, launch.entrypoint);
4623
+ const candidateArgs = launch.args ?? [];
4624
+ if (launch.interpreter) {
4625
+ return {
4626
+ executable: launch.interpreter,
4627
+ args: [{ kind: "public", value: entrypoint }, ...candidateArgs, ...profileFlags]
4628
+ };
4629
+ }
4630
+ return { executable: entrypoint, args: [...candidateArgs, ...profileFlags] };
4631
+ }
4632
+ function mergePublicEnvironment(...records) {
4633
+ const output = {};
4634
+ for (const record of records) {
4635
+ for (const [name, value] of Object.entries(record)) {
4636
+ const previous = output[name];
4637
+ if (previous && previous.value !== value.value) {
4638
+ throw new Error(`candidate and profile environment disagree on ${name}`);
4639
+ }
4640
+ output[name] = value;
4641
+ }
4642
+ }
4643
+ return output;
4644
+ }
4645
+ function unwrapPublicEnvironment(values) {
4646
+ return Object.fromEntries(Object.entries(values).map(([name, value]) => [name, value.value]));
4647
+ }
4648
+ function modelRoutes(profile, requested) {
4649
+ const routes = [
4650
+ { kind: "primary", requested }
4651
+ ];
4652
+ if (profile.model?.small) routes.push({ kind: "small", requested });
4653
+ for (const name of Object.keys(profile.modes ?? {}).sort()) {
4654
+ if (profile.modes?.[name]?.model) routes.push({ kind: "mode", name, requested });
4655
+ }
4656
+ for (const name of Object.keys(profile.subagents ?? {}).sort()) {
4657
+ if (profile.subagents?.[name]?.model) routes.push({ kind: "subagent", name, requested });
4658
+ }
4659
+ return routes;
4660
+ }
4661
+ function candidateEntrypointReceipt(candidate) {
4662
+ const launch = candidate.bundle.execution.launch;
4663
+ const workspace = candidate.bundle.execution.workspace;
4664
+ if (launch.kind !== "candidate-entrypoint" || !workspace) return void 0;
4665
+ const file = workspace.material.files.find((entry) => entry.path === launch.entrypoint);
4666
+ if (!file) throw new Error("candidate entrypoint is absent from the verified workspace");
4667
+ return { path: file.path, sha256: file.sha256, byteLength: file.byteLength };
4668
+ }
4669
+ function absoluteExecutionCwd(cwd, roots) {
4670
+ const root = cwd.workspace === "task" ? roots.taskRoot : roots.candidateRoot;
4671
+ if (!root) throw new Error("candidate cwd is missing its execution workspace root");
4672
+ const absolute = cwd.path === "." ? root : posix.join(root, cwd.path);
4673
+ if (absolute !== root && !absolute.startsWith(`${root}/`)) {
4674
+ throw new Error("candidate cwd escapes its execution workspace");
4675
+ }
4676
+ return absolute;
4677
+ }
4678
+ function validateProtectedModelReservation(reservation, expectedLimits, preparationId, expiresAtMs) {
4679
+ if (!/^sha256:[a-f0-9]{64}$/.test(reservation.digest)) {
4680
+ throw new Error("protected model reservation has an invalid identity digest");
4681
+ }
4682
+ if (reservation.preparationId !== preparationId || reservation.expiresAtMs !== expiresAtMs) {
4683
+ throw new Error("protected model reservation is not scoped to this preparation");
4684
+ }
4685
+ const limits = modelLimits2(expectedLimits);
4686
+ if (canonicalCandidateDigest(reservation.enforcedLimits) !== canonicalCandidateDigest(limits)) {
4687
+ throw new Error("protected model reservation does not enforce the frozen model limits");
4688
+ }
4689
+ const expectedNetworkMode = limits.maxModelCalls === 0 ? "disabled" : "gateway-only";
4690
+ const network = agentCandidateModelAccessNetworkSchema.parse(reservation.network);
4691
+ if (network.mode !== expectedNetworkMode) {
4692
+ throw new Error("protected model reservation has the wrong network policy for its call limit");
4693
+ }
4694
+ }
4695
+ function assertEnvironmentDisjoint(publicEnv, traceEnv) {
4696
+ const seen = new Set(Object.keys(publicEnv));
4697
+ for (const name of Object.keys(traceEnv)) {
4698
+ if (seen.has(name)) throw new Error(`evaluator environment binding collides with ${name}`);
4699
+ seen.add(name);
4700
+ }
4701
+ }
4702
+ function modelLimits2(limits) {
4703
+ return {
4704
+ maxModelCalls: limits.maxModelCalls,
4705
+ maxInputTokens: limits.maxInputTokens,
4706
+ maxOutputTokens: limits.maxOutputTokens,
4707
+ maxCostUsd: limits.maxCostUsd
4708
+ };
4709
+ }
4710
+ function exactProfileExecutorFiles(sourceFiles, expectedFiles) {
4711
+ const byPath = new Map(sourceFiles.map((file) => [file.relPath, file]));
4712
+ if (byPath.size !== sourceFiles.length || sourceFiles.length !== expectedFiles.length) {
4713
+ throw new Error("profile source files do not match the signed profile plan");
4714
+ }
4715
+ return expectedFiles.map((expected) => {
4716
+ const source = byPath.get(expected.relPath);
4717
+ const mode = source?.mode ?? 420;
4718
+ const bytes = Buffer.from(source?.content ?? "", "utf8");
4719
+ if (!source || mode !== 420 && mode !== 493 || mode !== expected.mode || sha256Bytes(bytes) !== expected.contentSha256) {
4720
+ throw new Error("profile source files do not match the signed profile plan");
4721
+ }
4722
+ return { path: expected.relPath, mode, bytes: Uint8Array.from(bytes) };
4723
+ });
4724
+ }
4725
+ function isWellFormedUnicode(value) {
4726
+ for (let index = 0; index < value.length; index++) {
4727
+ const code = value.charCodeAt(index);
4728
+ if (code >= 55296 && code <= 56319) {
4729
+ const next = value.charCodeAt(index + 1);
4730
+ if (!(next >= 56320 && next <= 57343)) return false;
4731
+ index++;
4732
+ } else if (code >= 56320 && code <= 57343) {
4733
+ return false;
4734
+ }
4735
+ }
4736
+ return true;
4737
+ }
4738
+ function errorMessage2(error) {
4739
+ return error instanceof Error ? error.message : String(error);
4740
+ }
4741
+
4742
+ export {
4743
+ CLAIM_FORMAT_VERSION,
4744
+ PENDING_FORMAT_VERSION,
4745
+ TERMINAL_FORMAT_VERSION,
4746
+ PHASE_FORMAT_VERSION,
4747
+ canonicalCandidateBytes,
4748
+ canonicalCandidateDigest,
4749
+ immutableCandidateValue,
4750
+ canonicalCandidateDocument,
4751
+ omitTopLevelDigest,
4752
+ assertExactObjectKeys,
4753
+ terminalRecord,
4754
+ recoveredTerminalRecord,
4755
+ assertTerminalAllowedInPhase,
4756
+ rejectedFinish,
4757
+ rejectedStage,
4758
+ requireStagedTerminal,
4759
+ sealTerminalDigest,
4760
+ assertRecoveryMatchesStaged,
4761
+ assertTerminalMatchesClaim,
4762
+ assertTerminalMatchesStaged,
4763
+ candidateCleanupTimeout,
4764
+ candidateCleanupDeadline,
4765
+ withinCandidateCleanupDeadline,
4766
+ CANDIDATE_TRACE_TAGS,
4767
+ CANDIDATE_TRACE_ENV,
4768
+ assertPreparedCandidateIntegrity,
4769
+ beginPreparedCandidateDisposal,
4770
+ consumePreparedCandidateExecution,
4771
+ candidateExecutionClaim,
4772
+ InMemoryAgentCandidateExecutionClaimStore,
4773
+ candidateClaimFileInternals,
4774
+ sealAgentCandidateModelSettlement,
4775
+ usdToNanos,
4776
+ sealAgentCandidateExecutorFinalCapture,
4777
+ persistCandidateOutputArtifact,
4778
+ persistCandidateModelSettlementEvidence,
4779
+ RecoveryAgentCandidateTraceStore,
4780
+ executePreparedAgentCandidate,
4781
+ verifyAgentCandidateBundle,
4782
+ prepareAgentCandidateExecution
4783
+ };
4784
+ //# sourceMappingURL=chunk-A62TP7SK.js.map