@tangle-network/agent-runtime 0.94.12 → 0.95.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 (80) hide show
  1. package/dist/agent.d.ts +2 -25
  2. package/dist/agent.js +9 -12
  3. package/dist/agent.js.map +1 -1
  4. package/dist/{agentic-generator-DDMM45kZ.d.ts → agentic-generator-hCaQRAes.d.ts} +0 -1
  5. package/dist/analyst-loop.d.ts +1 -1
  6. package/dist/candidate-execution/index.d.ts +43 -16
  7. package/dist/candidate-execution/index.js +18 -8
  8. package/dist/{chunk-VYA2YEKA.js → chunk-2KGAN2HM.js} +83 -14
  9. package/dist/chunk-2KGAN2HM.js.map +1 -0
  10. package/dist/{chunk-FTXM7Q7P.js → chunk-6YBA64Z2.js} +120 -724
  11. package/dist/chunk-6YBA64Z2.js.map +1 -0
  12. package/dist/{chunk-HGRW27YY.js → chunk-AP7CPGMZ.js} +139 -19
  13. package/dist/chunk-AP7CPGMZ.js.map +1 -0
  14. package/dist/{chunk-XP5KDM3R.js → chunk-BPGXIKK7.js} +3 -3
  15. package/dist/{chunk-D3H7F6L2.js → chunk-DHCHL6OG.js} +2 -3
  16. package/dist/chunk-DHCHL6OG.js.map +1 -0
  17. package/dist/{chunk-PCURO3DL.js → chunk-G55QE4IQ.js} +512 -36
  18. package/dist/chunk-G55QE4IQ.js.map +1 -0
  19. package/dist/{chunk-C3UKLQ54.js → chunk-IADLKE7I.js} +14 -4
  20. package/dist/chunk-IADLKE7I.js.map +1 -0
  21. package/dist/{chunk-WIPGQ4GT.js → chunk-IMSNJSXH.js} +1 -1
  22. package/dist/{chunk-WIPGQ4GT.js.map → chunk-IMSNJSXH.js.map} +1 -1
  23. package/dist/{chunk-VSWBYWFK.js → chunk-M6MD6JBS.js} +20 -27
  24. package/dist/chunk-M6MD6JBS.js.map +1 -0
  25. package/dist/chunk-MKGRLDWB.js +684 -0
  26. package/dist/chunk-MKGRLDWB.js.map +1 -0
  27. package/dist/{chunk-AEG3NGJ2.js → chunk-Q2JSAVQ3.js} +34 -2
  28. package/dist/chunk-Q2JSAVQ3.js.map +1 -0
  29. package/dist/{chunk-37V4KQDC.js → chunk-WTZ37EQY.js} +1021 -514
  30. package/dist/chunk-WTZ37EQY.js.map +1 -0
  31. package/dist/{chunk-U33YZ7B2.js → chunk-YLUOTX6U.js} +4 -4
  32. package/dist/{chunk-33OG2NN3.js → chunk-Z5I642SY.js} +2 -2
  33. package/dist/{completion-gate-D1gX1-hg.d.ts → completion-gate-C80jiRfN.d.ts} +1 -1
  34. package/dist/conversation.d.ts +12 -1
  35. package/dist/conversation.js +2 -2
  36. package/dist/{coordination-Dr_axlAf.d.ts → coordination-BFE3Den7.d.ts} +10 -11
  37. package/dist/environment-provider.d.ts +2 -2
  38. package/dist/environment-provider.js +1 -1
  39. package/dist/{improve-BN3HyXIO.d.ts → improve-B-UYaEH5.d.ts} +3 -3
  40. package/dist/index.d.ts +22 -25
  41. package/dist/index.js +45 -50
  42. package/dist/index.js.map +1 -1
  43. package/dist/intelligence.d.ts +177 -119
  44. package/dist/intelligence.js +501 -342
  45. package/dist/intelligence.js.map +1 -1
  46. package/dist/knowledge.d.ts +22 -11
  47. package/dist/knowledge.js +9 -4
  48. package/dist/lifecycle.d.ts +2 -2
  49. package/dist/lifecycle.js +1 -1
  50. package/dist/{loop-runner-bin-BRQSQdHa.d.ts → loop-runner-bin-BIQldFS8.d.ts} +2 -2
  51. package/dist/loop-runner-bin.d.ts +5 -5
  52. package/dist/loop-runner-bin.js +6 -6
  53. package/dist/loops.d.ts +12 -12
  54. package/dist/loops.js +5 -5
  55. package/dist/mcp/bin.js +3 -3
  56. package/dist/mcp/index.d.ts +6 -6
  57. package/dist/mcp/index.js +6 -6
  58. package/dist/{mcp-serve-verifier-DQQDbuyz.d.ts → mcp-serve-verifier-Bs_n0xPc.d.ts} +1 -1
  59. package/dist/primeintellect/index.js +1 -1
  60. package/dist/profile-DbfaMTdk.d.ts +233 -0
  61. package/dist/profiles.d.ts +1 -1
  62. package/dist/{supervise-DmYOug5f.d.ts → supervise-BLPI50-w.d.ts} +3 -3
  63. package/dist/{types-ByAYqlVb.d.ts → types-B3vAW0Oq.d.ts} +1 -1
  64. package/dist/types-CWqfCO8s.d.ts +491 -0
  65. package/dist/{types-1d5QGK3t.d.ts → types-CmnA2iL3.d.ts} +3 -3
  66. package/dist/{worktree-fanout-CPprU-qI.d.ts → worktree-fanout-DCA3G4bO.d.ts} +3 -3
  67. package/package.json +13 -10
  68. package/dist/chunk-37V4KQDC.js.map +0 -1
  69. package/dist/chunk-AEG3NGJ2.js.map +0 -1
  70. package/dist/chunk-C3UKLQ54.js.map +0 -1
  71. package/dist/chunk-D3H7F6L2.js.map +0 -1
  72. package/dist/chunk-FTXM7Q7P.js.map +0 -1
  73. package/dist/chunk-HGRW27YY.js.map +0 -1
  74. package/dist/chunk-PCURO3DL.js.map +0 -1
  75. package/dist/chunk-VSWBYWFK.js.map +0 -1
  76. package/dist/chunk-VYA2YEKA.js.map +0 -1
  77. package/dist/prepare-DIeVgQG3.d.ts +0 -718
  78. /package/dist/{chunk-XP5KDM3R.js.map → chunk-BPGXIKK7.js.map} +0 -0
  79. /package/dist/{chunk-U33YZ7B2.js.map → chunk-YLUOTX6U.js.map} +0 -0
  80. /package/dist/{chunk-33OG2NN3.js.map → chunk-Z5I642SY.js.map} +0 -0
@@ -1,9 +1,15 @@
1
1
  import {
2
2
  contentAddress
3
- } from "./chunk-WIPGQ4GT.js";
3
+ } from "./chunk-IMSNJSXH.js";
4
4
 
5
- // src/candidate-execution/bundle.ts
6
- import { agentCandidateBundleSchema } from "@tangle-network/agent-interface";
5
+ // src/candidate-execution/profile.ts
6
+ import {
7
+ agentCandidateProfileActivationSchema,
8
+ agentCandidateProfileSchema,
9
+ agentProfileDiffSchema,
10
+ agentProfileSchema,
11
+ applyAgentProfileDiff
12
+ } from "@tangle-network/agent-interface";
7
13
 
8
14
  // src/candidate-execution/digest.ts
9
15
  import { createHash } from "crypto";
@@ -38,6 +44,12 @@ function canonicalCandidateDocument(valueWithoutDigest) {
38
44
  digest
39
45
  });
40
46
  }
47
+ function verifyCanonicalCandidateDocument(value, label) {
48
+ if (canonicalCandidateDigest(omitTopLevelDigest(value)) !== value.digest) {
49
+ throw new Error(`${label} digest does not match`);
50
+ }
51
+ return immutableCandidateValue(value);
52
+ }
41
53
  function embeddedCandidateArtifact(bytes) {
42
54
  return {
43
55
  encoding: "base64",
@@ -61,24 +73,69 @@ function deepFreezeCandidate(value, seen = /* @__PURE__ */ new Set()) {
61
73
  return Object.freeze(value);
62
74
  }
63
75
 
64
- // src/candidate-execution/bundle.ts
65
- function sealAgentCandidateBundle(input) {
66
- const digest = canonicalCandidateDigest(input);
67
- const parsed = agentCandidateBundleSchema.parse({ ...input, digest });
68
- const parsedDigest = canonicalCandidateDigest(omitTopLevelDigest(parsed));
69
- if (parsedDigest !== digest) {
70
- throw new Error("candidate bundle changed while validating its canonical wire shape");
76
+ // src/candidate-execution/profile.ts
77
+ var MATERIALIZER_HARNESSES = /* @__PURE__ */ new Set([
78
+ "claude-code",
79
+ "claude",
80
+ "claudish",
81
+ "nanoclaw",
82
+ "codex",
83
+ "opencode",
84
+ "kimi-code",
85
+ "kimi",
86
+ "pi",
87
+ "gemini",
88
+ "hermes",
89
+ "openclaw"
90
+ ]);
91
+ function candidateMaterializerHarness(harness) {
92
+ if (!MATERIALIZER_HARNESSES.has(harness)) {
93
+ throw new Error(
94
+ `sealed candidate profile materialization is unsupported for harness ${harness}`
95
+ );
71
96
  }
72
- return immutableCandidateValue(parsed);
97
+ return harness;
98
+ }
99
+ function createAgentCandidateProfileActivation(plan, profilePlan) {
100
+ const sourceByPath = new Map(plan.files.map((file) => [file.relPath, file]));
101
+ if (sourceByPath.size !== plan.files.length) {
102
+ throw new Error("candidate profile activation contains duplicate native file paths");
103
+ }
104
+ const files = profilePlan.material.files.map((expected) => {
105
+ const source = sourceByPath.get(expected.relPath);
106
+ if (!source) {
107
+ throw new Error(`candidate profile activation is missing ${expected.relPath}`);
108
+ }
109
+ const mode = source.mode ?? 420;
110
+ if (!Number.isSafeInteger(mode) || mode < 0 || mode > 511) {
111
+ throw new Error(`candidate profile activation has invalid mode for ${expected.relPath}`);
112
+ }
113
+ return { path: expected.relPath, mode, content: source.content };
114
+ });
115
+ if (files.length !== plan.files.length) {
116
+ throw new Error("candidate profile activation contains unplanned native files");
117
+ }
118
+ return parseAgentCandidateProfileActivation(
119
+ canonicalCandidateDocument({
120
+ kind: "agent-candidate-profile-activation",
121
+ profilePlan,
122
+ files
123
+ }).value,
124
+ profilePlan.digest
125
+ );
126
+ }
127
+ function parseAgentCandidateProfileActivation(input, expectedProfilePlanDigest) {
128
+ const activation = agentCandidateProfileActivationSchema.parse(input);
129
+ const planBytes = canonicalCandidateBytes(activation.profilePlan.material);
130
+ const profilePlanArtifact = activation.profilePlan.artifact;
131
+ if (sha256Bytes(planBytes) !== activation.profilePlan.digest || profilePlanArtifact.sha256 !== activation.profilePlan.digest || profilePlanArtifact.byteLength !== planBytes.byteLength || "content" in profilePlanArtifact && !Buffer.from(profilePlanArtifact.content, "base64").equals(Buffer.from(planBytes)) || expectedProfilePlanDigest !== void 0 && activation.profilePlan.digest !== expectedProfilePlanDigest) {
132
+ throw new Error("candidate profile activation has an invalid canonical profile plan");
133
+ }
134
+ if (canonicalCandidateDigest(omitTopLevelDigest(activation)) !== activation.digest) {
135
+ throw new Error("candidate profile activation digest does not match");
136
+ }
137
+ return immutableCandidateValue(activation);
73
138
  }
74
-
75
- // src/candidate-execution/profile.ts
76
- import {
77
- agentCandidateProfileSchema,
78
- agentProfileDiffSchema,
79
- agentProfileSchema,
80
- applyAgentProfileDiff
81
- } from "@tangle-network/agent-interface";
82
139
  var CANDIDATE_PROFILE_DIRECT_FIELDS = [
83
140
  "name",
84
141
  "description",
@@ -137,18 +194,28 @@ function assertCandidateProfileBinding(measuredInput, bundled) {
137
194
  if (measured.connections || measured.metadata || measured.extensions) {
138
195
  throw new Error("proposal candidate profile contains fields unsupported by sealed candidates");
139
196
  }
140
- const normalized = candidateProfileAsAgentProfile(bundled);
197
+ const normalized = agentCandidateProfileAsAgentProfile(bundled);
141
198
  if (canonicalCandidateDigest(measured) !== canonicalCandidateDigest(normalized)) {
142
199
  throw new Error("proposal candidateProfile does not match candidateBundle.profile");
143
200
  }
144
201
  }
145
202
  function parseExactAgentProfile(input, label) {
146
- const parsed = agentProfileSchema.parse(input);
203
+ let parsed;
204
+ try {
205
+ parsed = agentProfileSchema.parse(input);
206
+ } catch (cause) {
207
+ throw new Error(`${label} contains unsupported or non-canonical fields`, { cause });
208
+ }
147
209
  assertCanonicalParse(input, parsed, label);
148
210
  return parsed;
149
211
  }
150
212
  function parseExactAgentProfileDiff(input, label) {
151
- const parsed = agentProfileDiffSchema.parse(input);
213
+ let parsed;
214
+ try {
215
+ parsed = agentProfileDiffSchema.parse(input);
216
+ } catch (cause) {
217
+ throw new Error(`${label} contains unsupported or non-canonical fields`, { cause });
218
+ }
152
219
  assertCanonicalParse(input, parsed, label);
153
220
  return parsed;
154
221
  }
@@ -172,7 +239,7 @@ function assertCandidateProfileExecutionSupport(profile) {
172
239
  );
173
240
  }
174
241
  }
175
- function candidateProfileAsAgentProfile(candidate) {
242
+ function agentCandidateProfileAsAgentProfile(candidate) {
176
243
  const output = {};
177
244
  copyDirectProfileFields(output, candidate);
178
245
  if (candidate.model) output.model = { ...candidate.model };
@@ -375,13 +442,9 @@ import {
375
442
  } from "@tangle-network/agent-interface";
376
443
 
377
444
  // src/candidate-execution/claim-file-formats.ts
378
- var CLAIM_FORMAT_VERSION = 7;
379
- var PENDING_FORMAT_VERSION = 1;
380
- var TERMINAL_FORMAT_VERSION = 3;
381
- var PHASE_FORMAT_VERSION = 1;
382
-
383
- // src/candidate-execution/claim-terminal.ts
384
- import { agentCandidateArtifactRefSchema } from "@tangle-network/agent-interface";
445
+ import {
446
+ agentCandidateArtifactRefSchema
447
+ } from "@tangle-network/agent-interface";
385
448
 
386
449
  // src/candidate-execution/exact-object.ts
387
450
  function assertExactObjectKeys(value, required, label, optional = []) {
@@ -400,7 +463,31 @@ function assertExactObjectKeys(value, required, label, optional = []) {
400
463
  }
401
464
  }
402
465
 
466
+ // src/candidate-execution/claim-file-formats.ts
467
+ function sealCandidatePreparationEvidence(value, executionPlanDigest) {
468
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
469
+ throw new Error("candidate execution preparation evidence must be an object");
470
+ }
471
+ const record = value;
472
+ assertExactObjectKeys(
473
+ record,
474
+ ["executionPlan", "materializationReceipt"],
475
+ "candidate execution preparation evidence"
476
+ );
477
+ const executionPlan = immutableCandidateValue(
478
+ agentCandidateArtifactRefSchema.parse(record.executionPlan)
479
+ );
480
+ const materializationReceipt = immutableCandidateValue(
481
+ agentCandidateArtifactRefSchema.parse(record.materializationReceipt)
482
+ );
483
+ if (executionPlan.sha256 !== executionPlanDigest) {
484
+ throw new Error("candidate execution plan artifact digest does not match its claim");
485
+ }
486
+ return Object.freeze({ executionPlan, materializationReceipt });
487
+ }
488
+
403
489
  // src/candidate-execution/claim-terminal.ts
490
+ import { agentCandidateArtifactRefSchema as agentCandidateArtifactRefSchema2 } from "@tangle-network/agent-interface";
404
491
  var SHA256_PATTERN = /^sha256:[a-f0-9]{64}$/;
405
492
  function terminalRecord(claim, result) {
406
493
  const terminal = sealTerminalResult(result);
@@ -409,6 +496,7 @@ function terminalRecord(claim, result) {
409
496
  attempt: claim.attempt,
410
497
  bundleDigest: claim.bundleDigest,
411
498
  executionPlanDigest: claim.executionPlanDigest,
499
+ preparationEvidence: claim.preparationEvidence,
412
500
  ...terminal
413
501
  };
414
502
  return immutableCandidateValue({
@@ -419,7 +507,6 @@ function terminalRecord(claim, result) {
419
507
  function recoveredTerminalRecord(claim, phase, evidence) {
420
508
  const recovered = sealRecoveryEvidence(evidence, claim);
421
509
  return terminalRecord(claim, {
422
- schemaVersion: 1,
423
510
  status: "failed",
424
511
  failureClass: recovered.failureClass === "pre-model-infrastructure" && phase !== "claimed" ? "unknown" : recovered.failureClass,
425
512
  usage: recovered.usage,
@@ -474,8 +561,8 @@ function sealTerminalRecordValue(value, label) {
474
561
  "attempt",
475
562
  "bundleDigest",
476
563
  "executionPlanDigest",
564
+ "preparationEvidence",
477
565
  "terminalDigest",
478
- "schemaVersion",
479
566
  "status",
480
567
  "usage",
481
568
  "modelSettlement",
@@ -487,8 +574,8 @@ function sealTerminalRecordValue(value, label) {
487
574
  "attempt",
488
575
  "bundleDigest",
489
576
  "executionPlanDigest",
577
+ "preparationEvidence",
490
578
  "terminalDigest",
491
- "schemaVersion",
492
579
  "status",
493
580
  "failureClass",
494
581
  "usage",
@@ -497,14 +584,19 @@ function sealTerminalRecordValue(value, label) {
497
584
  ],
498
585
  label
499
586
  );
587
+ const executionPlanDigest = requireString(
588
+ value.executionPlanDigest,
589
+ label,
590
+ "executionPlanDigest"
591
+ );
500
592
  const identity = {
501
593
  executionId: requireString(value.executionId, label, "executionId"),
502
594
  attempt: requireNumber(value.attempt, label, "attempt"),
503
595
  bundleDigest: requireString(value.bundleDigest, label, "bundleDigest"),
504
- executionPlanDigest: requireString(
505
- value.executionPlanDigest,
506
- label,
507
- "executionPlanDigest"
596
+ executionPlanDigest,
597
+ preparationEvidence: sealCandidatePreparationEvidence(
598
+ value.preparationEvidence,
599
+ executionPlanDigest
508
600
  )
509
601
  };
510
602
  assertExecutionId(identity.executionId);
@@ -513,28 +605,21 @@ function sealTerminalRecordValue(value, label) {
513
605
  }
514
606
  assertSha256Digest(identity.bundleDigest, "bundleDigest");
515
607
  assertSha256Digest(identity.executionPlanDigest, "executionPlanDigest");
608
+ if (identity.preparationEvidence.executionPlan.sha256 !== identity.executionPlanDigest) {
609
+ throw new Error(`${label} execution plan artifact does not match executionPlanDigest`);
610
+ }
516
611
  const result = sealTerminalResult(
517
612
  status === "succeeded" ? {
518
- schemaVersion: requireNumber(value.schemaVersion, label, "schemaVersion"),
519
613
  status,
520
- usage: requireObject(
521
- value.usage,
522
- label,
523
- "usage"
524
- ),
614
+ usage: requireObject(value.usage, label, "usage"),
525
615
  modelSettlement: requireArtifactRef(value.modelSettlement, label, "modelSettlement"),
526
616
  taskOutcome: requireArtifactRef(value.taskOutcome, label, "taskOutcome"),
527
617
  benchmarkResult: requireArtifactRef(value.benchmarkResult, label, "benchmarkResult"),
528
618
  runReceipt: requireArtifactRef(value.runReceipt, label, "runReceipt")
529
619
  } : {
530
- schemaVersion: requireNumber(value.schemaVersion, label, "schemaVersion"),
531
620
  status,
532
621
  failureClass: requireFailureClass(value.failureClass, label),
533
- usage: requireObject(
534
- value.usage,
535
- label,
536
- "usage"
537
- ),
622
+ usage: requireObject(value.usage, label, "usage"),
538
623
  modelSettlement: requireArtifactRef(value.modelSettlement, label, "modelSettlement"),
539
624
  ...value.failureEvidence ? {
540
625
  failureEvidence: requireArtifactRef(
@@ -561,7 +646,7 @@ function sealTerminalRecordValue(value, label) {
561
646
  });
562
647
  }
563
648
  function assertTerminalMatchesClaim(terminal, claim, path) {
564
- if (terminal.executionId !== claim.executionId || terminal.attempt !== claim.attempt || terminal.bundleDigest !== claim.bundleDigest || terminal.executionPlanDigest !== claim.executionPlanDigest) {
649
+ if (terminal.executionId !== claim.executionId || terminal.attempt !== claim.attempt || terminal.bundleDigest !== claim.bundleDigest || terminal.executionPlanDigest !== claim.executionPlanDigest || canonicalCandidateDigest(terminal.preparationEvidence) !== canonicalCandidateDigest(claim.preparationEvidence)) {
565
650
  throw new Error(`candidate execution terminal record at ${path} does not match its claim`);
566
651
  }
567
652
  }
@@ -640,16 +725,7 @@ function sealTerminalResult(result) {
640
725
  }
641
726
  assertExactObjectKeys(
642
727
  result,
643
- result.status === "succeeded" ? [
644
- "schemaVersion",
645
- "status",
646
- "usage",
647
- "modelSettlement",
648
- "taskOutcome",
649
- "benchmarkResult",
650
- "runReceipt"
651
- ] : [
652
- "schemaVersion",
728
+ result.status === "succeeded" ? ["status", "usage", "modelSettlement", "taskOutcome", "benchmarkResult", "runReceipt"] : [
653
729
  "status",
654
730
  "failureClass",
655
731
  "usage",
@@ -658,14 +734,10 @@ function sealTerminalResult(result) {
658
734
  ],
659
735
  "candidate execution terminal result"
660
736
  );
661
- if (result.schemaVersion !== 1) {
662
- throw new Error("candidate execution terminal schemaVersion must be 1");
663
- }
664
737
  const usage = sealUsage(result.usage);
665
738
  const modelSettlement = sealArtifactRef(result.modelSettlement, "modelSettlement");
666
739
  if (result.status === "succeeded") {
667
740
  return Object.freeze({
668
- schemaVersion: 1,
669
741
  status: "succeeded",
670
742
  usage,
671
743
  modelSettlement,
@@ -679,7 +751,6 @@ function sealTerminalResult(result) {
679
751
  throw new Error("pre-model infrastructure failure cannot contain model calls");
680
752
  }
681
753
  return Object.freeze({
682
- schemaVersion: 1,
683
754
  status: "failed",
684
755
  failureClass: result.failureClass,
685
756
  usage,
@@ -713,7 +784,7 @@ function sealUsage(usage) {
713
784
  });
714
785
  }
715
786
  function sealArtifactRef(ref, label) {
716
- const parsed = agentCandidateArtifactRefSchema.parse(ref);
787
+ const parsed = agentCandidateArtifactRefSchema2.parse(ref);
717
788
  if (!Number.isSafeInteger(parsed.byteLength)) {
718
789
  throw new Error(`candidate execution terminal ${label} byteLength exceeds safe integer range`);
719
790
  }
@@ -798,29 +869,15 @@ function candidateResultTimeout(timeoutMs, taskTimeoutMs) {
798
869
  return effective;
799
870
  }
800
871
  async function withinCandidateCleanupDeadline(operation, deadlineAtMs, label) {
801
- const remainingMs = deadlineAtMs - Date.now();
802
- if (remainingMs <= 0) throw new CandidateCleanupTimeoutError(label);
803
- const pending = Promise.resolve().then(operation);
804
- void pending.catch(() => void 0);
805
- let timer;
806
- try {
807
- const result = await Promise.race([
808
- pending,
809
- new Promise((_resolve, reject) => {
810
- timer = setTimeout(() => reject(new CandidateCleanupTimeoutError(label)), remainingMs);
811
- })
812
- ]);
813
- if (Date.now() >= deadlineAtMs) throw new CandidateCleanupTimeoutError(label);
814
- return result;
815
- } finally {
816
- if (timer) clearTimeout(timer);
817
- }
872
+ return withinCandidateDeadline(operation, deadlineAtMs, new CandidateCleanupTimeoutError(label));
818
873
  }
819
874
  async function withinCandidateResultDeadline(operation, deadlineAtMs, label) {
875
+ return withinCandidateDeadline(operation, deadlineAtMs, new CandidateResultTimeoutError(label));
876
+ }
877
+ async function withinCandidateDeadline(operation, deadlineAtMs, timeoutError) {
820
878
  const remainingMs = deadlineAtMs - Date.now();
821
- if (remainingMs <= 0) throw new CandidateResultTimeoutError(label);
879
+ if (remainingMs <= 0) throw timeoutError;
822
880
  const controller = new AbortController();
823
- const timeoutError = new CandidateResultTimeoutError(label);
824
881
  const pending = Promise.resolve().then(() => operation(controller.signal));
825
882
  void pending.catch(() => void 0);
826
883
  let timer;
@@ -949,8 +1006,8 @@ var InMemoryAgentCandidateExecutionClaimStore = class {
949
1006
  }
950
1007
  };
951
1008
  var SHA256_PATTERN2 = /^sha256:[a-f0-9]{64}$/;
952
- var LEASE_TOKEN_PATTERN = /^candidate-execution-lease-v1\.[A-Za-z0-9_-]{43}$/;
953
- var PREPARATION_ID_PATTERN = /^candidate-preparation-v1\.[A-Za-z0-9_-]{43}$/;
1009
+ var LEASE_TOKEN_PATTERN = /^candidate-execution-lease\.[A-Za-z0-9_-]{43}$/;
1010
+ var PREPARATION_ID_PATTERN = /^candidate-preparation\.[A-Za-z0-9_-]{43}$/;
954
1011
  function sealClaim(claim) {
955
1012
  assertExactObjectKeys(
956
1013
  claim,
@@ -961,6 +1018,7 @@ function sealClaim(claim) {
961
1018
  "retryPolicy",
962
1019
  "bundleDigest",
963
1020
  "executionPlanDigest",
1021
+ "preparationEvidence",
964
1022
  "retryLineageDigest",
965
1023
  "leaseExpiresAtMs",
966
1024
  "resultTimeoutMs",
@@ -986,6 +1044,10 @@ function sealClaim(claim) {
986
1044
  }
987
1045
  assertSha256Digest2(claim.bundleDigest, "bundleDigest");
988
1046
  assertSha256Digest2(claim.executionPlanDigest, "executionPlanDigest");
1047
+ const preparationEvidence = sealCandidatePreparationEvidence(
1048
+ claim.preparationEvidence,
1049
+ claim.executionPlanDigest
1050
+ );
989
1051
  assertSha256Digest2(claim.retryLineageDigest, "retryLineageDigest");
990
1052
  assertPositiveTimestamp(claim.leaseExpiresAtMs, "leaseExpiresAtMs");
991
1053
  candidateResultTimeout(claim.resultTimeoutMs, claim.resultTimeoutMs);
@@ -997,6 +1059,7 @@ function sealClaim(claim) {
997
1059
  retryPolicy: claim.retryPolicy,
998
1060
  bundleDigest: claim.bundleDigest,
999
1061
  executionPlanDigest: claim.executionPlanDigest,
1062
+ preparationEvidence,
1000
1063
  retryLineageDigest: claim.retryLineageDigest,
1001
1064
  leaseExpiresAtMs: claim.leaseExpiresAtMs,
1002
1065
  resultTimeoutMs: claim.resultTimeoutMs,
@@ -1080,7 +1143,7 @@ function newLease(claim) {
1080
1143
  return Object.freeze({
1081
1144
  executionId: claim.executionId,
1082
1145
  attempt: claim.attempt,
1083
- token: `candidate-execution-lease-v1.${randomBytes(32).toString("base64url")}`,
1146
+ token: `candidate-execution-lease.${randomBytes(32).toString("base64url")}`,
1084
1147
  expiresAtMs: claim.leaseExpiresAtMs
1085
1148
  });
1086
1149
  }
@@ -1131,19 +1194,16 @@ function rejectedRetry(claim, detail) {
1131
1194
  async function readClaim(path) {
1132
1195
  const parsed = await readJsonObject(path, "claim");
1133
1196
  const record = parsed;
1134
- if (record.version !== CLAIM_FORMAT_VERSION) {
1135
- throw new Error(`candidate execution claim at ${path} has unsupported version`);
1136
- }
1137
1197
  assertExactObjectKeys(
1138
1198
  parsed,
1139
1199
  [
1140
- "version",
1141
1200
  "executionId",
1142
1201
  "attempt",
1143
1202
  "maxAttempts",
1144
1203
  "retryPolicy",
1145
1204
  "bundleDigest",
1146
1205
  "executionPlanDigest",
1206
+ "preparationEvidence",
1147
1207
  "retryLineageDigest",
1148
1208
  "leaseExpiresAtMs",
1149
1209
  "resultTimeoutMs",
@@ -1164,6 +1224,11 @@ async function readClaim(path) {
1164
1224
  path,
1165
1225
  "executionPlanDigest"
1166
1226
  ),
1227
+ preparationEvidence: requireObject2(
1228
+ record.preparationEvidence,
1229
+ path,
1230
+ "preparationEvidence"
1231
+ ),
1167
1232
  retryLineageDigest: requireString2(
1168
1233
  record.retryLineageDigest,
1169
1234
  path,
@@ -1199,10 +1264,7 @@ async function readClaimIfPresent(path) {
1199
1264
  async function readTerminal(path) {
1200
1265
  const parsed = await readJsonObject(path, "terminal record");
1201
1266
  const record = parsed;
1202
- if (record.version !== TERMINAL_FORMAT_VERSION) {
1203
- throw new Error(`candidate execution terminal record at ${path} has unsupported version`);
1204
- }
1205
- assertExactObjectKeys(parsed, ["version", "terminal"], `candidate execution terminal record at ${path}`);
1267
+ assertExactObjectKeys(parsed, ["terminal"], `candidate execution terminal record at ${path}`);
1206
1268
  return sealTerminalRecordValue(
1207
1269
  requireObject2(record.terminal, path, "terminal"),
1208
1270
  `candidate execution terminal record at ${path}`
@@ -1226,12 +1288,9 @@ async function readTransitionIfPresent(path, claim) {
1226
1288
  }
1227
1289
  if (parsed.kind === "candidate-execution-phase") {
1228
1290
  const record = parsed;
1229
- if (record.version !== PHASE_FORMAT_VERSION) {
1230
- throw new Error(`candidate execution phase record at ${path} has unsupported version`);
1231
- }
1232
1291
  assertExactObjectKeys(
1233
1292
  parsed,
1234
- ["version", "kind", "executionId", "attempt", "executionPlanDigest", "phase"],
1293
+ ["kind", "executionId", "attempt", "executionPlanDigest", "phase"],
1235
1294
  `candidate execution phase record at ${path}`
1236
1295
  );
1237
1296
  if (record.executionId !== claim.executionId || record.attempt !== claim.attempt || record.executionPlanDigest !== claim.executionPlanDigest || record.phase !== "candidate-may-run") {
@@ -1241,14 +1300,7 @@ async function readTransitionIfPresent(path, claim) {
1241
1300
  }
1242
1301
  if (parsed.kind === "candidate-execution-pending-terminal") {
1243
1302
  const record = parsed;
1244
- if (record.version !== PENDING_FORMAT_VERSION) {
1245
- throw new Error(`candidate execution pending record at ${path} has unsupported version`);
1246
- }
1247
- assertExactObjectKeys(
1248
- parsed,
1249
- ["version", "kind", "terminal"],
1250
- `candidate execution pending record at ${path}`
1251
- );
1303
+ assertExactObjectKeys(parsed, ["kind", "terminal"], `candidate execution pending record at ${path}`);
1252
1304
  const terminal = sealTerminalRecordValue(
1253
1305
  requireObject2(record.terminal, path, "terminal"),
1254
1306
  `candidate execution pending record at ${path}`
@@ -1398,6 +1450,8 @@ function candidateTerminalWindowMs(cleanupTimeoutMs) {
1398
1450
 
1399
1451
  // src/candidate-execution/prepared-state.ts
1400
1452
  import {
1453
+ agentCandidateBenchmarkSuiteSchema,
1454
+ agentCandidateBenchmarkTaskSchema,
1401
1455
  agentCandidateExecutionPlanEvidenceSchema,
1402
1456
  agentCandidateMaterializationReceiptSchema,
1403
1457
  agentCandidateProfilePlanEvidenceSchema
@@ -1464,6 +1518,17 @@ async function readMaterializedWorkspaceFiles(root, expected, options = {}) {
1464
1518
  (file) => Object.freeze({ path: file.path, mode: file.mode, bytes: Uint8Array.from(file.bytes) })
1465
1519
  );
1466
1520
  }
1521
+ function candidateWorkspaceManifest(files) {
1522
+ return {
1523
+ kind: "agent-candidate-workspace-manifest",
1524
+ files: files.map((file) => ({
1525
+ path: file.path,
1526
+ mode: file.mode,
1527
+ sha256: sha256Bytes(file.bytes),
1528
+ byteLength: file.bytes.byteLength
1529
+ })).sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0)
1530
+ };
1531
+ }
1467
1532
  function assertWorkspaceManifest(observed, expected) {
1468
1533
  if (!Buffer.from(canonicalCandidateBytes(observed)).equals(canonicalCandidateBytes(expected))) {
1469
1534
  throw new Error(
@@ -1493,7 +1558,6 @@ async function scanWorkspace(root, ignoredProtectedRootEntries, limits) {
1493
1558
  if (await realpath(absoluteRoot) !== absoluteRoot) {
1494
1559
  throw new Error("workspace root has a symlinked path component");
1495
1560
  }
1496
- const files = [];
1497
1561
  const capturedFiles = [];
1498
1562
  let totalBytes = 0;
1499
1563
  async function visit(directory) {
@@ -1519,7 +1583,7 @@ async function scanWorkspace(root, ignoredProtectedRootEntries, limits) {
1519
1583
  if (!stats.isFile()) {
1520
1584
  throw new Error(`workspace contains a non-regular entry: ${relPath}`);
1521
1585
  }
1522
- if (limits && files.length >= limits.maxFiles) {
1586
+ if (limits && capturedFiles.length >= limits.maxFiles) {
1523
1587
  throw new Error("workspace exceeds maxFiles");
1524
1588
  }
1525
1589
  const descriptor = await open(
@@ -1535,9 +1599,6 @@ async function scanWorkspace(root, ignoredProtectedRootEntries, limits) {
1535
1599
  throw new Error(`workspace contains a hard-linked file: ${relPath}`);
1536
1600
  }
1537
1601
  const mode = openedStats.mode & 511;
1538
- if (mode !== 420 && mode !== 493) {
1539
- throw new Error(`workspace file has unsupported mode ${mode.toString(8)}: ${relPath}`);
1540
- }
1541
1602
  if (limits && openedStats.size > limits.maxFileBytes) {
1542
1603
  throw new Error(`workspace file exceeds maxFileBytes: ${relPath}`);
1543
1604
  }
@@ -1551,28 +1612,15 @@ async function scanWorkspace(root, ignoredProtectedRootEntries, limits) {
1551
1612
  relPath
1552
1613
  );
1553
1614
  totalBytes += bytes.byteLength;
1554
- const supportedMode = mode;
1555
- files.push({
1556
- path: relPath,
1557
- mode: supportedMode,
1558
- sha256: sha256Bytes(bytes),
1559
- byteLength: bytes.byteLength
1560
- });
1561
- capturedFiles.push({ path: relPath, mode: supportedMode, bytes: Uint8Array.from(bytes) });
1615
+ capturedFiles.push({ path: relPath, mode, bytes: Uint8Array.from(bytes) });
1562
1616
  } finally {
1563
1617
  await descriptor.close();
1564
1618
  }
1565
1619
  }
1566
1620
  }
1567
1621
  await visit(absoluteRoot);
1568
- files.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
1569
- capturedFiles.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
1570
1622
  return {
1571
- manifest: {
1572
- schemaVersion: 1,
1573
- kind: "agent-candidate-workspace-manifest",
1574
- files
1575
- },
1623
+ manifest: candidateWorkspaceManifest(capturedFiles),
1576
1624
  files: capturedFiles
1577
1625
  };
1578
1626
  }
@@ -1797,19 +1845,9 @@ async function assertSafeTree(repositoryRoot, tree, environment = {}) {
1797
1845
  }
1798
1846
  }
1799
1847
  async function workspaceManifestFromGitTree(repositoryRoot, tree, environment) {
1800
- const files = (await readCandidateGitTreeFiles(repositoryRoot, tree, environment)).map(
1801
- ({ path, mode, bytes }) => ({
1802
- path,
1803
- mode,
1804
- sha256: sha256Bytes(bytes),
1805
- byteLength: bytes.byteLength
1806
- })
1848
+ return candidateWorkspaceManifest(
1849
+ await readCandidateGitTreeFiles(repositoryRoot, tree, environment)
1807
1850
  );
1808
- return {
1809
- schemaVersion: 1,
1810
- kind: "agent-candidate-workspace-manifest",
1811
- files
1812
- };
1813
1851
  }
1814
1852
  async function readCandidateGitTreeFiles(repositoryRoot, tree, environment = {}, limits) {
1815
1853
  const listing = (await runCandidateGit(
@@ -1959,9 +1997,11 @@ function createPreparedCandidateExecution(input) {
1959
1997
  assertPrivateCandidateIntegrity(state);
1960
1998
  const prepared = Object.freeze({
1961
1999
  bundle: state.bundle,
2000
+ benchmark: Object.freeze({ suite: state.benchmarkSuite, task: state.benchmarkTask }),
1962
2001
  executionId: state.executionId,
1963
2002
  roots: state.roots,
1964
2003
  profilePlan: evidenceView(state.profilePlan),
2004
+ profileActivation: state.profileActivation,
1965
2005
  executionPlan: evidenceView(state.executionPlan),
1966
2006
  materializationReceipt: state.materializationReceipt,
1967
2007
  launch: state.launch,
@@ -2014,8 +2054,9 @@ function beginPreparedCandidateRun(prepared, modelAccess, memoryAccess) {
2014
2054
  const material = state.executionPlan.value.material;
2015
2055
  const request = Object.freeze({
2016
2056
  executionId: state.executionId,
2057
+ benchmark: preparedBenchmark(state),
2017
2058
  inputs: Object.freeze({
2018
- task: workspaceInputView(material.task.workspace, state.executorInputs.taskFiles),
2059
+ task: workspaceInputView(state.benchmarkTask.workspace, state.executorInputs.taskFiles),
2019
2060
  ...material.candidateWorkspace && state.executorInputs.candidateFiles ? {
2020
2061
  candidate: workspaceInputView(
2021
2062
  material.candidateWorkspace,
@@ -2030,6 +2071,7 @@ function beginPreparedCandidateRun(prepared, modelAccess, memoryAccess) {
2030
2071
  }),
2031
2072
  roots: state.roots.execution,
2032
2073
  profilePlan: evidenceView(state.profilePlan),
2074
+ profileActivation: state.profileActivation,
2033
2075
  executionPlan: evidenceView(state.executionPlan),
2034
2076
  materializationReceipt: state.materializationReceipt,
2035
2077
  launch: immutableCandidateValue({ ...state.launch, env: completeEnvironment }),
@@ -2043,6 +2085,9 @@ function beginPreparedCandidateRun(prepared, modelAccess, memoryAccess) {
2043
2085
  });
2044
2086
  return { state, request };
2045
2087
  }
2088
+ function preparedBenchmark(state) {
2089
+ return Object.freeze({ suite: state.benchmarkSuite, task: state.benchmarkTask });
2090
+ }
2046
2091
  function consumePreparedCandidateExecution(prepared, outcome) {
2047
2092
  transitionLifecycle(
2048
2093
  prepared,
@@ -2055,10 +2100,16 @@ function beginPreparedCandidateSettlement(prepared) {
2055
2100
  }
2056
2101
  async function assertPreparedCandidateWorkspaces(state) {
2057
2102
  const plan = state.executionPlan.value.material;
2058
- await verifyMaterializedWorkspace(state.roots.staging.taskRoot, plan.task.workspace.material, {
2059
- ignoredProtectedRootEntries: [".git", ".sidecar"]
2060
- });
2061
- await verifyTaskCheckout(state.roots.staging.taskRoot, plan.task.repository);
2103
+ await verifyMaterializedWorkspace(
2104
+ state.roots.staging.taskRoot,
2105
+ state.benchmarkTask.workspace.material,
2106
+ {
2107
+ ignoredProtectedRootEntries: [".git", ".sidecar"]
2108
+ }
2109
+ );
2110
+ if (state.benchmarkTask.repository) {
2111
+ await verifyTaskCheckout(state.roots.staging.taskRoot, state.benchmarkTask.repository);
2112
+ }
2062
2113
  await verifyMaterializedProfileWorkspace(
2063
2114
  state.roots.staging.profileRoot,
2064
2115
  state.profilePlan.value.material
@@ -2072,9 +2123,19 @@ async function assertPreparedCandidateWorkspaces(state) {
2072
2123
  }
2073
2124
  }
2074
2125
  function detachPreparedCandidateState(input) {
2126
+ const benchmarkSuite = immutableCandidateValue(
2127
+ agentCandidateBenchmarkSuiteSchema.parse(input.benchmarkSuite)
2128
+ );
2129
+ const benchmarkTask = immutableCandidateValue(
2130
+ agentCandidateBenchmarkTaskSchema.parse(input.benchmarkTask)
2131
+ );
2075
2132
  const profilePlan = immutableCandidateValue(
2076
2133
  agentCandidateProfilePlanEvidenceSchema.parse(input.profilePlan.value)
2077
2134
  );
2135
+ const profileActivation = parseAgentCandidateProfileActivation(
2136
+ input.profileActivation,
2137
+ profilePlan.digest
2138
+ );
2078
2139
  const executionPlan = immutableCandidateValue(
2079
2140
  agentCandidateExecutionPlanEvidenceSchema.parse(input.executionPlan.value)
2080
2141
  );
@@ -2090,6 +2151,8 @@ function detachPreparedCandidateState(input) {
2090
2151
  return Object.freeze({
2091
2152
  ports: input.ports,
2092
2153
  bundle: input.bundle,
2154
+ benchmarkSuite,
2155
+ benchmarkTask,
2093
2156
  executionId: input.executionId,
2094
2157
  roots: immutableCandidateValue(input.roots),
2095
2158
  profilePlan: Object.freeze({
@@ -2097,6 +2160,7 @@ function detachPreparedCandidateState(input) {
2097
2160
  bytes: Uint8Array.from(input.profilePlan.bytes),
2098
2161
  written: Object.freeze([...input.profilePlan.written])
2099
2162
  }),
2163
+ profileActivation,
2100
2164
  executionPlan: Object.freeze({
2101
2165
  value: executionPlan,
2102
2166
  bytes: Uint8Array.from(input.executionPlan.bytes)
@@ -2116,18 +2180,15 @@ function detachPreparedCandidateState(input) {
2116
2180
  executorInputs: Object.freeze({
2117
2181
  taskFiles: immutableExecutorFiles(input.executorInputs.taskFiles),
2118
2182
  ...input.executorInputs.candidateFiles ? { candidateFiles: immutableExecutorFiles(input.executorInputs.candidateFiles) } : {},
2119
- profileFiles: Object.freeze(
2120
- input.executorInputs.profileFiles.map(
2121
- (file) => Object.freeze({ ...file, bytes: Uint8Array.from(file.bytes) })
2122
- )
2123
- )
2183
+ profileFiles: immutableExecutorFiles(input.executorInputs.profileFiles)
2124
2184
  }),
2125
2185
  ...input.memoryReservation ? { memoryReservation: immutableCandidateValue(input.memoryReservation) } : {},
2126
2186
  ...input.knowledge ? {
2127
2187
  knowledge: Object.freeze({
2128
- snapshotId: input.knowledge.snapshotId,
2129
- manifestDigest: input.knowledge.manifestDigest,
2130
- manifest: Uint8Array.from(input.knowledge.manifest)
2188
+ candidate: immutableCandidateValue(input.knowledge.candidate),
2189
+ snapshot: immutableCandidateValue(input.knowledge.snapshot),
2190
+ files: immutableExecutorFiles(input.knowledge.files),
2191
+ ...input.knowledge.retrievalConfig ? { retrievalConfig: Uint8Array.from(input.knowledge.retrievalConfig) } : {}
2131
2192
  })
2132
2193
  } : {},
2133
2194
  trace: immutableCandidateValue(input.trace),
@@ -2140,6 +2201,7 @@ function assertPrivateCandidateIntegrity(state) {
2140
2201
  throw new Error("prepared candidate bundle no longer matches its digest");
2141
2202
  }
2142
2203
  assertPlanEvidence(state.profilePlan.value, state.profilePlan.bytes, "profile plan");
2204
+ parseAgentCandidateProfileActivation(state.profileActivation, state.profilePlan.value.digest);
2143
2205
  assertPlanEvidence(state.executionPlan.value, state.executionPlan.bytes, "execution plan");
2144
2206
  agentCandidateExecutionPlanEvidenceSchema.parse(state.executionPlan.value);
2145
2207
  const receipt = agentCandidateMaterializationReceiptSchema.parse(
@@ -2149,14 +2211,16 @@ function assertPrivateCandidateIntegrity(state) {
2149
2211
  if (canonicalCandidateDigest(omitTopLevelDigest(receipt)) !== state.materializationReceipt.digest || !Buffer.from(receiptBytes).equals(Buffer.from(state.materializationReceipt.bytes))) {
2150
2212
  throw new Error("prepared materialization receipt no longer matches its canonical bytes");
2151
2213
  }
2152
- const instruction = state.executionPlan.value.material.task.instruction;
2153
- if (sha256Bytes(state.instruction.bytes) !== instruction.sha256 || state.instruction.bytes.byteLength !== instruction.byteLength || JSON.stringify(state.instruction.delivery) !== JSON.stringify(instruction.delivery)) {
2214
+ assertSignedBenchmarkInput(state);
2215
+ const instruction = Buffer.from(state.benchmarkTask.instruction, "utf8");
2216
+ if (!Buffer.from(state.instruction.bytes).equals(instruction) || JSON.stringify(state.instruction.delivery) !== JSON.stringify(state.executionPlan.value.material.instructionDelivery)) {
2154
2217
  throw new Error("prepared instruction no longer matches the signed execution plan");
2155
2218
  }
2156
- 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))) {
2219
+ if (!/^candidate-preparation\.[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))) {
2157
2220
  throw new Error("prepared model access no longer matches the signed execution plan");
2158
2221
  }
2159
2222
  assertExecutorInputs(state);
2223
+ assertPreparedKnowledge(state);
2160
2224
  if (state.memory.mode === "isolated" && !state.memoryReservation || state.memory.mode === "disabled" && state.memoryReservation) {
2161
2225
  throw new Error("prepared memory reservation does not match the signed execution plan");
2162
2226
  }
@@ -2180,7 +2244,7 @@ function assertPrivateCandidateIntegrity(state) {
2180
2244
  [CANDIDATE_TRACE_ENV.traceRunId]: state.trace.runId
2181
2245
  };
2182
2246
  if (!state.trace.runId.startsWith(
2183
- `${state.executionId}:attempt-${state.executionPlan.value.material.attempt.number}:`
2247
+ `${state.executionId}:attempt-${state.executionPlan.value.material.runCell.attempt}:`
2184
2248
  ) || canonicalCandidateDigest(state.trace.tags) !== canonicalCandidateDigest(expectedTags) || canonicalCandidateDigest(state.trace.env) !== canonicalCandidateDigest(expectedTraceEnvironment)) {
2185
2249
  throw new Error("prepared trace identity no longer matches the signed execution");
2186
2250
  }
@@ -2210,19 +2274,22 @@ function bytesView(value, key) {
2210
2274
  });
2211
2275
  }
2212
2276
  function knowledgeView(knowledge) {
2213
- const manifest = Uint8Array.from(knowledge.manifest);
2277
+ const retrievalConfig = knowledge.retrievalConfig ? Uint8Array.from(knowledge.retrievalConfig) : void 0;
2214
2278
  return Object.freeze({
2215
- snapshotId: knowledge.snapshotId,
2216
- manifestDigest: knowledge.manifestDigest,
2217
- get manifest() {
2218
- return Uint8Array.from(manifest);
2219
- }
2279
+ candidate: knowledge.candidate,
2280
+ snapshot: knowledge.snapshot,
2281
+ files: Object.freeze(knowledge.files.map((file) => profileFileView(file))),
2282
+ ...retrievalConfig ? {
2283
+ get retrievalConfig() {
2284
+ return Uint8Array.from(retrievalConfig);
2285
+ }
2286
+ } : {}
2220
2287
  });
2221
2288
  }
2222
2289
  function workspaceInputView(snapshot, sourceFiles) {
2223
2290
  return Object.freeze({
2224
2291
  snapshot,
2225
- files: Object.freeze(sourceFiles.map((file) => profileFileView(file)))
2292
+ files: Object.freeze(sourceFiles.map((file) => executorFileView(file)))
2226
2293
  });
2227
2294
  }
2228
2295
  function profileFileView(source) {
@@ -2235,9 +2302,22 @@ function profileFileView(source) {
2235
2302
  }
2236
2303
  });
2237
2304
  }
2305
+ function executorFileView(source) {
2306
+ const bytes = Uint8Array.from(source.bytes);
2307
+ return Object.freeze({
2308
+ path: source.path,
2309
+ mode: source.mode,
2310
+ get bytes() {
2311
+ return Uint8Array.from(bytes);
2312
+ }
2313
+ });
2314
+ }
2238
2315
  function assertExecutorInputs(state) {
2239
2316
  const material = state.executionPlan.value.material;
2240
- assertWorkspaceExecutorFiles(state.executorInputs.taskFiles, material.task.workspace.material);
2317
+ assertWorkspaceExecutorFiles(
2318
+ state.executorInputs.taskFiles,
2319
+ state.benchmarkTask.workspace.material
2320
+ );
2241
2321
  if (material.candidateWorkspace) {
2242
2322
  if (!state.executorInputs.candidateFiles) {
2243
2323
  throw new Error("prepared candidate executor files are missing");
@@ -2261,6 +2341,28 @@ function assertExecutorInputs(state) {
2261
2341
  }
2262
2342
  }
2263
2343
  }
2344
+ function assertPreparedKnowledge(state) {
2345
+ const expected = state.bundle.knowledge;
2346
+ const actual = state.knowledge;
2347
+ if (!expected || !actual) {
2348
+ if (expected || actual)
2349
+ throw new Error("prepared knowledge does not match the candidate bundle");
2350
+ return;
2351
+ }
2352
+ if (canonicalCandidateDigest(actual.candidate) !== canonicalCandidateDigest(expected.candidate) || canonicalCandidateDigest(actual.snapshot) !== canonicalCandidateDigest(expected.snapshot) || state.executionPlan.value.material.knowledgeManifestDigest !== expected.snapshot.digest) {
2353
+ throw new Error("prepared knowledge identity does not match the candidate bundle");
2354
+ }
2355
+ assertWorkspaceExecutorFiles(actual.files, expected.snapshot.material);
2356
+ if (!expected.retrievalConfig || !actual.retrievalConfig) {
2357
+ if (expected.retrievalConfig || actual.retrievalConfig) {
2358
+ throw new Error("prepared knowledge retrieval config does not match the candidate bundle");
2359
+ }
2360
+ return;
2361
+ }
2362
+ if (actual.retrievalConfig.byteLength !== expected.retrievalConfig.byteLength || sha256Bytes(actual.retrievalConfig) !== expected.retrievalConfig.sha256) {
2363
+ throw new Error("prepared knowledge retrieval config does not match the candidate bundle");
2364
+ }
2365
+ }
2264
2366
  function assertWorkspaceExecutorFiles(actualFiles, expected) {
2265
2367
  if (actualFiles.length !== expected.files.length) {
2266
2368
  throw new Error("prepared workspace executor files do not match the signed manifest");
@@ -2273,6 +2375,22 @@ function assertWorkspaceExecutorFiles(actualFiles, expected) {
2273
2375
  }
2274
2376
  }
2275
2377
  }
2378
+ function assertSignedBenchmarkInput(state) {
2379
+ const plan = state.executionPlan.value.material;
2380
+ const cell = plan.runCell;
2381
+ const suite = state.benchmarkSuite;
2382
+ const task = state.benchmarkTask;
2383
+ const receipt = state.materializationReceipt.value;
2384
+ const cellIndex = cell.taskIndex * suite.reps + cell.repetition;
2385
+ if (canonicalCandidateDigest(omitTopLevelDigest(suite)) !== suite.digest || canonicalCandidateDigest(omitTopLevelDigest(task)) !== task.digest || canonicalCandidateDigest(omitTopLevelDigest(cell)) !== cell.digest || cell.bundleDigest !== state.bundle.digest || cell.suiteDigest !== suite.digest || cell.taskDigest !== task.digest || suite.taskDigests[cell.taskIndex] !== task.digest || suite.seeds[cellIndex] !== cell.seed || cell.repetition >= suite.reps || cell.attempt < 1 || cell.attempt > task.attempt.maxAttempts) {
2386
+ throw new Error("prepared candidate no longer matches its signed experiment cell");
2387
+ }
2388
+ const suiteBytes = canonicalCandidateBytes(omitTopLevelDigest(suite));
2389
+ const taskBytes = canonicalCandidateBytes(omitTopLevelDigest(task));
2390
+ if (receipt.benchmark.suite.digest !== suite.digest || receipt.benchmark.suite.material.sha256 !== sha256Bytes(suiteBytes) || receipt.benchmark.suite.material.byteLength !== suiteBytes.byteLength || receipt.benchmark.task.digest !== task.digest || receipt.benchmark.task.material.sha256 !== sha256Bytes(taskBytes) || receipt.benchmark.task.material.byteLength !== taskBytes.byteLength) {
2391
+ throw new Error("materialization receipt no longer matches its signed benchmark input");
2392
+ }
2393
+ }
2276
2394
  function immutableExecutorFiles(files) {
2277
2395
  return Object.freeze(
2278
2396
  files.map((file) => Object.freeze({ ...file, bytes: Uint8Array.from(file.bytes) }))
@@ -2310,10 +2428,14 @@ function assertProtectedEnvironment(state, modelEnvironment, memoryEnvironment)
2310
2428
  }
2311
2429
 
2312
2430
  // src/candidate-execution/claim-plan.ts
2313
- function candidateExecutionClaim(prepared) {
2431
+ function candidateExecutionClaim(prepared, preparationEvidence) {
2314
2432
  const state = assertPreparedCandidateIntegrity(prepared);
2315
2433
  const material = prepared.executionPlan.value.material;
2316
- const attempt = material.attempt;
2434
+ const attempt = {
2435
+ number: material.runCell.attempt,
2436
+ maxAttempts: state.benchmarkTask.attempt.maxAttempts,
2437
+ retryPolicy: state.benchmarkTask.attempt.retryPolicy
2438
+ };
2317
2439
  const nowMs = Date.now();
2318
2440
  if (!Number.isSafeInteger(nowMs) || nowMs < 0) {
2319
2441
  throw new Error("candidate execution claim-store clock returned an invalid timestamp");
@@ -2331,6 +2453,14 @@ function candidateExecutionClaim(prepared) {
2331
2453
  "candidate preparation expires before its full execution and cleanup owner window"
2332
2454
  );
2333
2455
  }
2456
+ if (preparationEvidence.executionPlan.sha256 !== prepared.executionPlan.value.digest || preparationEvidence.executionPlan.byteLength !== state.executionPlan.bytes.byteLength) {
2457
+ throw new Error("persisted execution plan does not match its canonical preparation bytes");
2458
+ }
2459
+ if (preparationEvidence.materializationReceipt.sha256 !== state.materializationReceipt.digest || preparationEvidence.materializationReceipt.byteLength !== state.materializationReceipt.bytes.byteLength) {
2460
+ throw new Error(
2461
+ "persisted materialization receipt does not match its canonical preparation bytes"
2462
+ );
2463
+ }
2334
2464
  return candidateClaimFileInternals.sealClaim({
2335
2465
  executionId: prepared.executionId,
2336
2466
  attempt: attempt.number,
@@ -2338,6 +2468,7 @@ function candidateExecutionClaim(prepared) {
2338
2468
  retryPolicy: attempt.retryPolicy,
2339
2469
  bundleDigest: prepared.bundle.digest,
2340
2470
  executionPlanDigest: prepared.executionPlan.value.digest,
2471
+ preparationEvidence,
2341
2472
  retryLineageDigest: retryLineageDigest(prepared, state.resultTimeoutMs),
2342
2473
  leaseExpiresAtMs,
2343
2474
  resultTimeoutMs: state.resultTimeoutMs,
@@ -2362,7 +2493,11 @@ function retryLineageDigest(prepared, resultTimeoutMs) {
2362
2493
  resultTimeoutMs,
2363
2494
  executionPlan: {
2364
2495
  ...material,
2365
- attempt: { ...material.attempt, number: 0 },
2496
+ runCell: {
2497
+ ...material.runCell,
2498
+ attempt: 0,
2499
+ digest: `sha256:${"0".repeat(64)}`
2500
+ },
2366
2501
  model: {
2367
2502
  ...material.model,
2368
2503
  access: {
@@ -2398,13 +2533,13 @@ function retryLineageDigest(prepared, resultTimeoutMs) {
2398
2533
 
2399
2534
  // src/candidate-execution/output-artifacts.ts
2400
2535
  import {
2401
- agentCandidateArtifactRefSchema as agentCandidateArtifactRefSchema2
2536
+ agentCandidateArtifactRefSchema as agentCandidateArtifactRefSchema3
2402
2537
  } from "@tangle-network/agent-interface";
2403
2538
  async function persistCandidateOutputArtifact(port, input) {
2404
2539
  input.signal?.throwIfAborted();
2405
2540
  const bytes = Uint8Array.from(input.bytes);
2406
2541
  const expectedDigest = sha256Bytes(bytes);
2407
- const ref = agentCandidateArtifactRefSchema2.parse(
2542
+ const ref = agentCandidateArtifactRefSchema3.parse(
2408
2543
  await port.put({
2409
2544
  executionId: input.executionId,
2410
2545
  purpose: input.purpose,
@@ -2427,6 +2562,7 @@ import {
2427
2562
  agentCandidateTerminationSchema,
2428
2563
  agentCandidateWorkspaceManifestMaterialSchema
2429
2564
  } from "@tangle-network/agent-interface";
2565
+ var sealedFinalCaptureBrand = /* @__PURE__ */ Symbol("sealedAgentCandidateExecutorFinalCapture");
2430
2566
  function sealAgentCandidateProtectedRunCapture(value) {
2431
2567
  const capture = requireRecord(value, "candidate execution capture");
2432
2568
  assertExactObjectKeys(capture, ["executionId", "termination"], "candidate execution capture");
@@ -2438,20 +2574,33 @@ function sealAgentCandidateProtectedRunCapture(value) {
2438
2574
  termination: Object.freeze(agentCandidateTerminationSchema.parse(capture.termination))
2439
2575
  });
2440
2576
  }
2441
- function sealAgentCandidateExecutorFinalCapture(value) {
2577
+ function sealAgentCandidateExecutorFinalCapture(value, expectedOutcome) {
2442
2578
  const capture = requireRecord(value, "candidate final capture");
2443
- assertExactObjectKeys(capture, ["stopped"], "candidate final capture", ["taskOutcome", "memoryAfter"]);
2444
- if (capture.stopped !== true) {
2445
- throw new Error("candidate final capture does not prove process death");
2446
- }
2447
- const taskOutcome = capture.taskOutcome ? sealTaskOutcomeCapture(capture.taskOutcome) : void 0;
2579
+ assertExactObjectKeys(capture, [], "candidate final capture", [
2580
+ "taskOutcome",
2581
+ "memoryAfter",
2582
+ "evidence"
2583
+ ]);
2584
+ const taskOutcome = capture.taskOutcome ? sealTaskOutcomeCapture(capture.taskOutcome, expectedOutcome) : void 0;
2448
2585
  const memoryAfter = capture.memoryAfter ? sealMemoryCapture(capture.memoryAfter) : void 0;
2586
+ if (capture.evidence !== void 0 && !(capture.evidence instanceof Uint8Array)) {
2587
+ throw new Error("candidate executor evidence must be a byte array");
2588
+ }
2589
+ const evidence = capture.evidence ? Uint8Array.from(capture.evidence) : void 0;
2449
2590
  return Object.freeze({
2450
- stopped: true,
2451
2591
  ...taskOutcome ? { taskOutcome } : {},
2452
- ...memoryAfter ? { memoryAfter: Object.freeze(memoryAfter) } : {}
2592
+ ...memoryAfter ? { memoryAfter: Object.freeze(memoryAfter) } : {},
2593
+ ...evidence ? { evidence } : {},
2594
+ [sealedFinalCaptureBrand]: true
2453
2595
  });
2454
2596
  }
2597
+ function sealAgentCandidateExecutorStopAcknowledgement(value) {
2598
+ const capture = requireRecord(value, "candidate stop acknowledgement");
2599
+ assertExactObjectKeys(capture, ["stopped"], "candidate stop acknowledgement");
2600
+ if (capture.stopped !== true) {
2601
+ throw new Error("candidate stop acknowledgement does not prove process death");
2602
+ }
2603
+ }
2455
2604
  function sealMemoryCapture(value) {
2456
2605
  const capture = requireRecord(value, "candidate memory capture");
2457
2606
  assertExactObjectKeys(capture, ["afterState", "archive"], "candidate memory capture");
@@ -2465,13 +2614,32 @@ function sealMemoryCapture(value) {
2465
2614
  archive: Uint8Array.from(capture.archive)
2466
2615
  });
2467
2616
  }
2468
- function sealTaskOutcomeCapture(value) {
2617
+ function sealTaskOutcomeCapture(value, expected) {
2469
2618
  const capture = requireRecord(value, "candidate task capture");
2619
+ if (capture.kind === "output") {
2620
+ assertExactObjectKeys(capture, ["kind", "bytes"], "candidate task output capture");
2621
+ if (expected.kind !== "output") {
2622
+ throw new Error("candidate task output capture does not match the signed outcome kind");
2623
+ }
2624
+ if (!(capture.bytes instanceof Uint8Array)) {
2625
+ throw new Error("candidate task output capture must contain a byte array");
2626
+ }
2627
+ if (capture.bytes.byteLength > expected.maxBytes) {
2628
+ throw new Error(`candidate task output exceeds the frozen ${expected.maxBytes}-byte maximum`);
2629
+ }
2630
+ return Object.freeze({ kind: "output", bytes: Uint8Array.from(capture.bytes) });
2631
+ }
2470
2632
  assertExactObjectKeys(
2471
2633
  capture,
2472
- ["resultTree", "afterState", "archive", "gitDiff"],
2634
+ ["kind", "resultTree", "afterState", "archive", "gitDiff"],
2473
2635
  "candidate task capture"
2474
2636
  );
2637
+ if (capture.kind !== "workspace") {
2638
+ throw new Error("candidate task capture has an invalid outcome kind");
2639
+ }
2640
+ if (expected.kind !== "workspace") {
2641
+ throw new Error("candidate workspace capture does not match the signed outcome kind");
2642
+ }
2475
2643
  if (typeof capture.resultTree !== "string" || !/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(capture.resultTree)) {
2476
2644
  throw new Error("candidate task capture resultTree is not a Git object id");
2477
2645
  }
@@ -2480,6 +2648,7 @@ function sealTaskOutcomeCapture(value) {
2480
2648
  }
2481
2649
  const afterState = agentCandidateWorkspaceManifestMaterialSchema.parse(capture.afterState);
2482
2650
  return Object.freeze({
2651
+ kind: "workspace",
2483
2652
  resultTree: capture.resultTree,
2484
2653
  afterState: Object.freeze(afterState),
2485
2654
  archive: Uint8Array.from(capture.archive),
@@ -2494,11 +2663,11 @@ function requireRecord(value, label) {
2494
2663
  }
2495
2664
 
2496
2665
  // src/candidate-execution/finalize.ts
2497
- import { mkdtemp as mkdtemp2, rm as rm2 } from "fs/promises";
2498
- import { tmpdir as tmpdir2 } from "os";
2499
- import { join as join2 } from "path";
2500
2666
  import { isLlmSpan as isLlmSpan2, REDACTION_VERSION as REDACTION_VERSION2 } from "@tangle-network/agent-eval";
2501
- import { agentCandidateRunReceiptV2Schema } from "@tangle-network/agent-interface";
2667
+ import {
2668
+ agentCandidateRunReceiptSchema,
2669
+ agentCandidateWorkspaceSnapshotEvidenceSchema
2670
+ } from "@tangle-network/agent-interface";
2502
2671
 
2503
2672
  // src/candidate-execution/model-settlement.ts
2504
2673
  import { isLlmSpan } from "@tangle-network/agent-eval";
@@ -2525,7 +2694,6 @@ function sealAgentCandidateModelSettlement(settlement, expected) {
2525
2694
  let outputTokens = 0;
2526
2695
  let cachedInputTokens = 0;
2527
2696
  let reasoningTokens = 0;
2528
- let hasCachedInput = false;
2529
2697
  let costUsdNanos = 0;
2530
2698
  const calls = settlement.calls.map((source, index) => {
2531
2699
  assertExactObjectKeys(
@@ -2578,7 +2746,6 @@ function sealAgentCandidateModelSettlement(settlement, expected) {
2578
2746
  source.cachedInputTokens,
2579
2747
  "cached input token total"
2580
2748
  );
2581
- hasCachedInput = true;
2582
2749
  assertCount2(source.reasoningTokens, `model settlement call ${index} reasoningTokens`);
2583
2750
  reasoningTokens = safeAdd(reasoningTokens, source.reasoningTokens, "reasoning token total");
2584
2751
  assertCount2(source.costUsdNanos, `model settlement call ${index} costUsdNanos`);
@@ -2588,13 +2755,6 @@ function sealAgentCandidateModelSettlement(settlement, expected) {
2588
2755
  return Object.freeze({ ...source });
2589
2756
  });
2590
2757
  const usage = Object.freeze({
2591
- costUsd: costUsdNanos / USD_NANOS,
2592
- inputTokens,
2593
- outputTokens,
2594
- ...hasCachedInput ? { cachedInputTokens } : {},
2595
- modelCalls: calls.length
2596
- });
2597
- const fixedUsage = Object.freeze({
2598
2758
  costUsdNanos,
2599
2759
  inputTokens,
2600
2760
  outputTokens,
@@ -2609,9 +2769,7 @@ function sealAgentCandidateModelSettlement(settlement, expected) {
2609
2769
  closed: true,
2610
2770
  calls: Object.freeze(calls)
2611
2771
  }),
2612
- usage,
2613
- fixedUsage,
2614
- costUsdNanos
2772
+ usage
2615
2773
  });
2616
2774
  }
2617
2775
  async function appendAuthoritativeModelSettlementSpans(traceStore, runId, settlement) {
@@ -2872,66 +3030,15 @@ function escapeRegularExpression(value) {
2872
3030
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2873
3031
  }
2874
3032
 
2875
- // src/candidate-execution/workspace-snapshot.ts
2876
- import {
2877
- agentCandidateWorkspaceManifestMaterialSchema as agentCandidateWorkspaceManifestMaterialSchema2,
2878
- agentCandidateWorkspaceSnapshotEvidenceSchema
2879
- } from "@tangle-network/agent-interface";
2880
- function provisionalCandidateWorkspaceSnapshot(materialInput, archive) {
2881
- const material = immutableCandidateValue(
2882
- agentCandidateWorkspaceManifestMaterialSchema2.parse(materialInput)
2883
- );
2884
- const manifestBytes = canonicalCandidateBytes(material);
2885
- const snapshot = Object.freeze({
2886
- schemaVersion: 1,
2887
- kind: "agent-candidate-workspace-snapshot",
2888
- digest: sha256Bytes(manifestBytes),
2889
- material,
2890
- manifest: Object.freeze(embeddedCandidateArtifact(manifestBytes)),
2891
- archive: Object.freeze(embeddedCandidateArtifact(archive))
2892
- });
2893
- return Object.freeze({ material, manifestBytes, snapshot });
2894
- }
2895
- async function persistCandidateWorkspaceSnapshot(port, input) {
2896
- input.signal?.throwIfAborted();
2897
- const material = immutableCandidateValue(input.material);
2898
- const manifestBytes = canonicalCandidateBytes(material);
2899
- const [manifest, archive] = await Promise.all([
2900
- persistCandidateOutputArtifact(port, {
2901
- executionId: input.executionId,
2902
- purpose: input.purpose === "task" ? "task-manifest" : "memory-after-manifest",
2903
- bytes: manifestBytes,
2904
- ...input.signal ? { signal: input.signal } : {}
2905
- }),
2906
- persistCandidateOutputArtifact(port, {
2907
- executionId: input.executionId,
2908
- purpose: input.purpose === "task" ? "task-archive" : "memory-after-archive",
2909
- bytes: input.archive,
2910
- ...input.signal ? { signal: input.signal } : {}
2911
- })
2912
- ]);
2913
- return immutableCandidateValue(
2914
- agentCandidateWorkspaceSnapshotEvidenceSchema.parse({
2915
- schemaVersion: 1,
2916
- kind: "agent-candidate-workspace-snapshot",
2917
- digest: sha256Bytes(manifestBytes),
2918
- material,
2919
- manifest,
2920
- archive
2921
- })
2922
- );
2923
- }
2924
-
2925
3033
  // src/candidate-execution/finalize.ts
2926
3034
  async function finalizeAgentCandidateRun(state, capture, traceStore, settlement, evidence, protectedValues, writeRedactionReport, signal) {
2927
3035
  let termination;
2928
3036
  try {
2929
3037
  signal?.throwIfAborted();
2930
- const protectedCapture = sealAgentCandidateProtectedRunCapture(capture);
2931
- if (protectedCapture.executionId !== state.executionId) {
3038
+ if (capture.executionId !== state.executionId) {
2932
3039
  throw new Error("protected capture execution id does not match the prepared execution");
2933
3040
  }
2934
- termination = protectedCapture.termination;
3041
+ termination = capture.termination;
2935
3042
  if (termination.kind === "timeout" && termination.timeoutMs !== state.executionPlan.value.material.limits.timeoutMs) {
2936
3043
  throw new Error("timeout termination does not match the frozen execution limit");
2937
3044
  }
@@ -2961,19 +3068,15 @@ async function finalizeAgentCandidateRun(state, capture, traceStore, settlement,
2961
3068
  );
2962
3069
  const modelSpans = orderedSpans.filter(isLlmSpan2);
2963
3070
  assertTraceMatchesModelSettlement(modelSpans, settlement);
2964
- const usage = settlement.usage;
2965
3071
  enforceLimits(state, run.startedAt, run.endedAt, orderedSpans, settlement);
2966
- const finalCapture = sealAgentCandidateExecutorFinalCapture(evidence.finalCapture);
2967
3072
  const memory = await memoryReceipt(
2968
3073
  state,
2969
- finalCapture,
2970
- evidence.outputArtifacts,
2971
- protectedValues,
3074
+ evidence.finalCapture,
3075
+ evidence.persistedCapture.memoryAfter,
2972
3076
  signal
2973
3077
  );
2974
3078
  const redacted = redactProtectedValue(
2975
3079
  {
2976
- schemaVersion: 1,
2977
3080
  run: { ...run, redactionVersion: REDACTION_VERSION2 },
2978
3081
  spans: orderedSpans,
2979
3082
  events: orderedEvents,
@@ -3004,29 +3107,31 @@ async function finalizeAgentCandidateRun(state, capture, traceStore, settlement,
3004
3107
  signal
3005
3108
  });
3006
3109
  const trace = {
3007
- schemaVersion: 1,
3008
3110
  artifact: traceArtifact,
3009
3111
  eventCount: 1 + orderedSpans.length + orderedEvents.length + orderedBudget.length + orderedArtifacts.length,
3010
3112
  modelCallCount: modelSpans.length
3011
3113
  };
3012
3114
  const document = canonicalCandidateDocument({
3013
- schemaVersion: 2,
3014
3115
  kind: "agent-candidate-run",
3015
3116
  digestAlgorithm: "rfc8785-sha256",
3016
3117
  bundleDigest: state.bundle.digest,
3118
+ runCellDigest: state.executionPlan.value.material.runCell.digest,
3017
3119
  materializationReceiptDigest: state.materializationReceipt.digest,
3018
3120
  executionPlanDigest: state.executionPlan.value.digest,
3121
+ timing: {
3122
+ startedAtMs: run.startedAt,
3123
+ endedAtMs: run.endedAt,
3124
+ durationMs: run.endedAt - run.startedAt
3125
+ },
3019
3126
  memory,
3020
- usage,
3021
- modelUsage: { resolved: state.resolvedModel, usage },
3022
3127
  trace,
3023
3128
  termination,
3024
- fixedUsage: settlement.fixedUsage,
3129
+ executorCapture: evidence.persistedCapture.evidence,
3025
3130
  modelSettlement: evidence.modelSettlement,
3026
3131
  taskOutcome: evidence.taskOutcome.evidence,
3027
3132
  benchmarkResult: evidence.benchmarkResult
3028
3133
  });
3029
- agentCandidateRunReceiptV2Schema.parse(document.value);
3134
+ agentCandidateRunReceiptSchema.parse(document.value);
3030
3135
  const runReceipt = await persistCandidateOutputArtifact(evidence.outputArtifacts, {
3031
3136
  executionId: state.executionId,
3032
3137
  purpose: "run-receipt",
@@ -3038,6 +3143,7 @@ async function finalizeAgentCandidateRun(state, capture, traceStore, settlement,
3038
3143
  receipt: document,
3039
3144
  artifacts: {
3040
3145
  modelSettlement: evidence.modelSettlement.artifact,
3146
+ executorCapture: evidence.persistedCapture.evidence,
3041
3147
  taskOutcome: evidence.taskOutcome.evidence.artifact,
3042
3148
  benchmarkResult: evidence.benchmarkResult.artifact,
3043
3149
  runReceipt
@@ -3082,45 +3188,30 @@ function enforceLimits(state, startedAt, endedAt, spans, settlement) {
3082
3188
  for (const [actual, limit, label] of checks) {
3083
3189
  if (actual > limit) throw new Error(`protected ${label} ${actual} exceeds ${limit}`);
3084
3190
  }
3085
- if (settlement.costUsdNanos > usdToNanos(limits.maxCostUsd, "frozen maxCostUsd")) {
3086
- throw new Error(`protected cost USD ${usage.costUsd} exceeds ${limits.maxCostUsd}`);
3191
+ if (usage.costUsdNanos > usdToNanos(limits.maxCostUsd, "frozen maxCostUsd")) {
3192
+ throw new Error(
3193
+ `protected cost USD ${usage.costUsdNanos / 1e9} exceeds ${limits.maxCostUsd}`
3194
+ );
3087
3195
  }
3088
3196
  }
3089
- async function memoryReceipt(state, capture, outputArtifacts, protectedValues, signal) {
3197
+ async function memoryReceipt(state, capture, persisted, signal) {
3090
3198
  signal?.throwIfAborted();
3091
3199
  if (state.memory.mode === "disabled") {
3092
- if (capture.memoryAfter !== void 0) {
3200
+ if (capture.memoryAfter !== void 0 || persisted !== void 0) {
3093
3201
  throw new Error("disabled memory cannot return an after-state");
3094
3202
  }
3095
3203
  return { mode: "disabled" };
3096
3204
  }
3097
3205
  if (!capture.memoryAfter) throw new Error("isolated memory is missing its protected after-state");
3098
- const archive = Uint8Array.from(capture.memoryAfter.archive);
3099
- if (archive.byteLength === 0) throw new Error("isolated memory archive cannot be empty");
3100
- const provisional = provisionalCandidateWorkspaceSnapshot(capture.memoryAfter.afterState, archive);
3101
- const afterState = provisional.material;
3102
- assertNoProtectedBytes(provisional.manifestBytes, protectedValues);
3103
- assertNoProtectedBytes(archive, protectedValues);
3104
- const root = await mkdtemp2(join2(tmpdir2(), "agent-candidate-memory-after-"));
3105
- try {
3106
- await state.ports.workspaces.materialize({
3107
- role: "memory",
3108
- snapshot: provisional.snapshot,
3109
- archive: Uint8Array.from(archive),
3110
- destination: root
3111
- });
3112
- const files = await readMaterializedWorkspaceFiles(root, afterState);
3113
- for (const file of files) assertNoProtectedBytes(file.bytes, protectedValues);
3114
- signal?.throwIfAborted();
3115
- } finally {
3116
- await rm2(root, { recursive: true, force: true });
3117
- }
3118
- const snapshot = await persistCandidateWorkspaceSnapshot(outputArtifacts, {
3119
- executionId: state.executionId,
3206
+ if (!persisted) throw new Error("isolated memory is missing persisted capture evidence");
3207
+ const afterState = capture.memoryAfter.afterState;
3208
+ const manifestBytes = canonicalCandidateBytes(afterState);
3209
+ const snapshot = agentCandidateWorkspaceSnapshotEvidenceSchema.parse({
3210
+ kind: "agent-candidate-workspace-snapshot",
3211
+ digest: sha256Bytes(manifestBytes),
3120
3212
  material: afterState,
3121
- archive,
3122
- purpose: "memory-after",
3123
- signal
3213
+ manifest: persisted.manifest,
3214
+ archive: persisted.archive
3124
3215
  });
3125
3216
  return {
3126
3217
  mode: "isolated",
@@ -3150,19 +3241,20 @@ function compareStrings(a, b) {
3150
3241
  }
3151
3242
 
3152
3243
  // src/candidate-execution/outcome-evidence.ts
3153
- import { mkdtemp as mkdtemp3, rm as rm3 } from "fs/promises";
3154
- import { tmpdir as tmpdir3 } from "os";
3155
- import { join as join3 } from "path";
3244
+ import { mkdtemp as mkdtemp2, rm as rm2 } from "fs/promises";
3245
+ import { tmpdir as tmpdir2 } from "os";
3246
+ import { join as join2 } from "path";
3156
3247
  import {
3157
3248
  agentCandidateBenchmarkResultEvidenceSchema,
3158
3249
  agentCandidateModelSettlementEvidenceSchema,
3159
- agentCandidateTaskOutcomeEvidenceSchema
3250
+ agentCandidateTaskOutcomeEvidenceSchema,
3251
+ agentCandidateWorkspaceSnapshotEvidenceSchema as agentCandidateWorkspaceSnapshotEvidenceSchema2
3160
3252
  } from "@tangle-network/agent-interface";
3161
3253
 
3162
3254
  // src/candidate-execution/benchmark-grader.ts
3163
3255
  async function runBoundCandidateBenchmarkGrader(input) {
3164
3256
  input.signal?.throwIfAborted();
3165
- const descriptor = snapshotGraderDescriptor(input.grader);
3257
+ const descriptor = snapshotGraderDescriptor(input.grader, input.expectedGrader);
3166
3258
  const implementationBytes = await readVerifiedArtifact(descriptor.artifact, input.artifacts);
3167
3259
  if (implementationBytes.byteLength === 0) {
3168
3260
  throw new Error("candidate benchmark grader implementation cannot be empty");
@@ -3170,6 +3262,7 @@ async function runBoundCandidateBenchmarkGrader(input) {
3170
3262
  const expectedImplementationDigest = sha256Bytes(implementationBytes);
3171
3263
  const termination = immutableCandidateValue(input.termination);
3172
3264
  const run = input.grader.run;
3265
+ const startedAtMs = Date.now();
3173
3266
  const result = await run(
3174
3267
  Object.freeze({
3175
3268
  executionId: input.executionId,
@@ -3179,6 +3272,7 @@ async function runBoundCandidateBenchmarkGrader(input) {
3179
3272
  signal: input.signal ?? new AbortController().signal
3180
3273
  })
3181
3274
  );
3275
+ const endedAtMs = Math.max(startedAtMs, Date.now());
3182
3276
  input.signal?.throwIfAborted();
3183
3277
  assertExactRunnerResult(result);
3184
3278
  const evidence = Uint8Array.from(result.evidence);
@@ -3198,19 +3292,42 @@ async function runBoundCandidateBenchmarkGrader(input) {
3198
3292
  }
3199
3293
  return Object.freeze({
3200
3294
  grader: descriptor,
3295
+ grading: immutableCandidateValue({
3296
+ usage: emptyFixedSpend(),
3297
+ timing: {
3298
+ startedAtMs,
3299
+ endedAtMs,
3300
+ durationMs: endedAtMs - startedAtMs
3301
+ }
3302
+ }),
3201
3303
  evaluation: result.evaluation,
3202
3304
  evidence
3203
3305
  });
3204
3306
  }
3205
- function snapshotGraderDescriptor(grader) {
3307
+ function snapshotGraderDescriptor(grader, expected) {
3206
3308
  if (!grader.name || !grader.version) {
3207
3309
  throw new Error("candidate benchmark grader name and version must be non-empty");
3208
3310
  }
3209
- return immutableCandidateValue({
3311
+ const actual = {
3210
3312
  name: grader.name,
3211
3313
  version: grader.version,
3314
+ format: "tangle-grader",
3212
3315
  artifact: grader.artifact
3213
- });
3316
+ };
3317
+ if (canonicalCandidateDigest(actual) !== canonicalCandidateDigest(expected)) {
3318
+ throw new Error("candidate benchmark grader does not match the signed task grader");
3319
+ }
3320
+ return immutableCandidateValue(expected);
3321
+ }
3322
+ function emptyFixedSpend() {
3323
+ return {
3324
+ inputTokens: 0,
3325
+ outputTokens: 0,
3326
+ cachedInputTokens: 0,
3327
+ reasoningTokens: 0,
3328
+ modelCalls: 0,
3329
+ costUsdNanos: 0
3330
+ };
3214
3331
  }
3215
3332
  function detachedImplementation(bytes) {
3216
3333
  const stored = Uint8Array.from(bytes);
@@ -3242,6 +3359,104 @@ function assertExactRunnerResult(value) {
3242
3359
  }
3243
3360
  }
3244
3361
 
3362
+ // src/candidate-execution/executor-capture-evidence.ts
3363
+ async function persistAgentCandidateExecutorCapture(identity, expected, capture, outputArtifacts, signal) {
3364
+ const executorEvidence = capture.evidence ? await persistCandidateOutputArtifact(outputArtifacts, {
3365
+ executionId: identity.executionId,
3366
+ purpose: "executor-native-evidence",
3367
+ bytes: capture.evidence,
3368
+ signal
3369
+ }) : void 0;
3370
+ const taskOutcome = capture.taskOutcome ? await persistTaskCapture(
3371
+ identity.executionId,
3372
+ expected,
3373
+ capture.taskOutcome,
3374
+ outputArtifacts,
3375
+ signal
3376
+ ) : void 0;
3377
+ const memoryAfter = capture.memoryAfter ? await persistWorkspaceCapture(
3378
+ identity.executionId,
3379
+ "memory-after-manifest",
3380
+ "memory-after-archive",
3381
+ capture.memoryAfter.afterState,
3382
+ capture.memoryAfter.archive,
3383
+ outputArtifacts,
3384
+ signal
3385
+ ) : void 0;
3386
+ const bytes = canonicalCandidateBytes({
3387
+ kind: "agent-candidate-executor-capture",
3388
+ executionPlanDigest: identity.executionPlanDigest,
3389
+ ...executorEvidence ? { executorEvidence } : {},
3390
+ ...taskOutcome ? { taskOutcome } : {},
3391
+ ...memoryAfter ? { memoryAfter } : {}
3392
+ });
3393
+ const evidence = await persistCandidateOutputArtifact(outputArtifacts, {
3394
+ executionId: identity.executionId,
3395
+ purpose: "executor-capture",
3396
+ bytes,
3397
+ signal
3398
+ });
3399
+ return Object.freeze({
3400
+ evidence,
3401
+ ...taskOutcome ? { taskOutcome: Object.freeze(taskOutcome) } : {},
3402
+ ...memoryAfter ? { memoryAfter: Object.freeze(memoryAfter) } : {}
3403
+ });
3404
+ }
3405
+ async function persistTaskCapture(executionId, expected, capture, outputArtifacts, signal) {
3406
+ if (capture.kind === "output") {
3407
+ if (expected.kind !== "output")
3408
+ throw new Error("captured output does not match the signed task");
3409
+ const artifact = await persistCandidateOutputArtifact(outputArtifacts, {
3410
+ executionId,
3411
+ purpose: "task-output",
3412
+ bytes: capture.bytes,
3413
+ signal
3414
+ });
3415
+ return {
3416
+ kind: "output",
3417
+ spec: { mediaType: expected.mediaType, maxBytes: expected.maxBytes },
3418
+ artifact
3419
+ };
3420
+ }
3421
+ if (expected.kind !== "workspace") {
3422
+ throw new Error("captured workspace does not match the signed task");
3423
+ }
3424
+ const workspace = await persistWorkspaceCapture(
3425
+ executionId,
3426
+ "task-manifest",
3427
+ "task-archive",
3428
+ capture.afterState,
3429
+ capture.archive,
3430
+ outputArtifacts,
3431
+ signal
3432
+ );
3433
+ const gitDiff = await persistCandidateOutputArtifact(outputArtifacts, {
3434
+ executionId,
3435
+ purpose: "task-patch",
3436
+ bytes: capture.gitDiff,
3437
+ signal
3438
+ });
3439
+ return { kind: "workspace", resultTree: capture.resultTree, ...workspace, gitDiff };
3440
+ }
3441
+ async function persistWorkspaceCapture(executionId, manifestPurpose, archivePurpose, afterState, archiveBytes, outputArtifacts, signal) {
3442
+ const manifestBytes = canonicalCandidateBytes(afterState);
3443
+ const [manifest, archive] = await Promise.all([
3444
+ persistCandidateOutputArtifact(outputArtifacts, {
3445
+ executionId,
3446
+ purpose: manifestPurpose,
3447
+ bytes: manifestBytes,
3448
+ signal
3449
+ }),
3450
+ persistCandidateOutputArtifact(outputArtifacts, {
3451
+ executionId,
3452
+ purpose: archivePurpose,
3453
+ bytes: archiveBytes,
3454
+ signal
3455
+ })
3456
+ ]);
3457
+ return { afterState, manifest, archive };
3458
+ }
3459
+
3245
3460
  // src/candidate-execution/outcome-evidence.ts
3246
3461
  async function persistCandidateModelSettlement(state, settlement, outputArtifacts) {
3247
3462
  return await persistCandidateModelSettlementEvidence(
@@ -3256,7 +3471,6 @@ async function persistCandidateModelSettlement(state, settlement, outputArtifact
3256
3471
  }
3257
3472
  async function persistCandidateModelSettlementEvidence(identity, settlement, outputArtifacts) {
3258
3473
  const material = {
3259
- schemaVersion: 2,
3260
3474
  kind: "agent-candidate-model-settlement-material",
3261
3475
  executionPlanDigest: identity.executionPlanDigest,
3262
3476
  preparationId: settlement.value.preparationId,
@@ -3277,7 +3491,7 @@ async function persistCandidateModelSettlementEvidence(identity, settlement, out
3277
3491
  reasoningTokens: call.reasoningTokens ?? 0,
3278
3492
  costUsdNanos: call.costUsdNanos
3279
3493
  })),
3280
- usage: settlement.fixedUsage
3494
+ usage: settlement.usage
3281
3495
  };
3282
3496
  const bytes = canonicalCandidateBytes(material);
3283
3497
  const digest = sha256Bytes(bytes);
@@ -3288,7 +3502,6 @@ async function persistCandidateModelSettlementEvidence(identity, settlement, out
3288
3502
  });
3289
3503
  return immutableCandidateValue(
3290
3504
  agentCandidateModelSettlementEvidenceSchema.parse({
3291
- schemaVersion: 1,
3292
3505
  kind: "agent-candidate-model-settlement",
3293
3506
  digest,
3294
3507
  material,
@@ -3296,16 +3509,53 @@ async function persistCandidateModelSettlementEvidence(identity, settlement, out
3296
3509
  })
3297
3510
  );
3298
3511
  }
3299
- async function persistVerifiedCandidateTaskOutcome(state, capture, outputArtifacts, protectedValues, signal) {
3512
+ async function persistVerifiedAgentCandidateExecutorCapture(state, capture, outputArtifacts, protectedValues, signal) {
3300
3513
  signal?.throwIfAborted();
3514
+ const taskCapture = capture.taskOutcome;
3515
+ if (!taskCapture) throw new Error("candidate final capture is missing the task outcome");
3516
+ if (capture.evidence) assertNoProtectedBytes(capture.evidence, protectedValues);
3517
+ const expected = state.benchmarkTask.outcome;
3518
+ if (taskCapture.kind !== expected.kind) {
3519
+ throw new Error(
3520
+ `candidate captured ${taskCapture.kind} outcome does not match expected ${expected.kind} outcome`
3521
+ );
3522
+ }
3523
+ const verified = taskCapture.kind === "output" && expected.kind === "output" ? verifyOutputTaskCapture(taskCapture.bytes, expected, protectedValues) : taskCapture.kind === "workspace" && expected.kind === "workspace" ? await verifyWorkspaceTaskCapture(state, taskCapture, protectedValues, signal) : void 0;
3524
+ if (!verified) throw new Error("candidate task outcome kind could not be narrowed");
3525
+ await verifyMemoryCapture(state, capture, protectedValues, signal);
3526
+ const persistedCapture = await persistAgentCandidateExecutorCapture(
3527
+ {
3528
+ executionId: state.executionId,
3529
+ executionPlanDigest: state.executionPlan.value.digest
3530
+ },
3531
+ expected,
3532
+ capture,
3533
+ outputArtifacts,
3534
+ signal
3535
+ );
3536
+ const persisted = persistedCapture.taskOutcome;
3537
+ if (!persisted || persisted.kind !== verified.kind) {
3538
+ throw new Error("persisted task capture kind changed");
3539
+ }
3540
+ const taskOutcome = verified.kind === "output" && persisted.kind === "output" ? await persistVerifiedOutputTaskOutcome(state, verified, persisted, outputArtifacts, signal) : verified.kind === "workspace" && persisted.kind === "workspace" ? await persistVerifiedWorkspaceTaskOutcome(
3541
+ state,
3542
+ verified,
3543
+ persisted,
3544
+ outputArtifacts,
3545
+ signal
3546
+ ) : void 0;
3547
+ if (!taskOutcome) throw new Error("persisted task outcome kind could not be narrowed");
3548
+ return Object.freeze({ persistedCapture, taskOutcome });
3549
+ }
3550
+ async function verifyWorkspaceTaskCapture(state, capture, protectedValues, signal) {
3551
+ const repository = state.benchmarkTask.repository;
3552
+ if (!repository) throw new Error("workspace task outcome is missing repository identity");
3301
3553
  const patch = Uint8Array.from(capture.gitDiff);
3302
3554
  const archive = Uint8Array.from(capture.archive);
3303
3555
  if (archive.byteLength === 0) throw new Error("candidate task archive cannot be empty");
3304
3556
  assertNoProtectedBytes(patch, protectedValues);
3305
3557
  assertNoProtectedBytes(archive, protectedValues);
3306
- const provisional = provisionalCandidateWorkspaceSnapshot(capture.afterState, archive);
3307
- const afterState = provisional.material;
3308
- const repository = state.executionPlan.value.material.task.repository;
3558
+ const afterState = immutableCandidateValue(capture.afterState);
3309
3559
  const verified = await verifyTaskOutcomePatch({
3310
3560
  repositoryRoot: state.roots.staging.taskRoot,
3311
3561
  baseCommit: repository.baseCommit,
@@ -3315,44 +3565,111 @@ async function persistVerifiedCandidateTaskOutcome(state, capture, outputArtifac
3315
3565
  afterState
3316
3566
  });
3317
3567
  signal?.throwIfAborted();
3318
- assertNoProtectedBytes(provisional.manifestBytes, protectedValues);
3319
- await verifyTaskOutcomeArchive(state, provisional.snapshot, archive, protectedValues);
3320
- signal?.throwIfAborted();
3321
- const snapshot = await persistCandidateWorkspaceSnapshot(outputArtifacts, {
3322
- executionId: state.executionId,
3568
+ const manifestBytes = canonicalCandidateBytes(afterState);
3569
+ assertNoProtectedBytes(manifestBytes, protectedValues);
3570
+ const provisionalSnapshot = agentCandidateWorkspaceSnapshotEvidenceSchema2.parse({
3571
+ kind: "agent-candidate-workspace-snapshot",
3572
+ digest: sha256Bytes(manifestBytes),
3323
3573
  material: afterState,
3324
- archive,
3325
- purpose: "task",
3326
- signal
3574
+ manifest: embeddedCandidateArtifact(manifestBytes),
3575
+ archive: embeddedCandidateArtifact(archive)
3327
3576
  });
3328
- const gitDiff = await persistCandidateOutputArtifact(outputArtifacts, {
3329
- executionId: state.executionId,
3330
- purpose: "task-patch",
3331
- bytes: patch,
3332
- signal
3577
+ await verifyTaskOutcomeArchive(state, provisionalSnapshot, archive, protectedValues);
3578
+ signal?.throwIfAborted();
3579
+ return {
3580
+ kind: "workspace",
3581
+ patch,
3582
+ archive,
3583
+ afterState,
3584
+ manifestBytes,
3585
+ resultCommit: verified.resultCommit,
3586
+ resultTree: verified.resultTree,
3587
+ repository
3588
+ };
3589
+ }
3590
+ async function persistVerifiedWorkspaceTaskOutcome(state, verified, persisted, outputArtifacts, signal) {
3591
+ const { afterState, manifestBytes, patch, repository } = verified;
3592
+ const snapshot = agentCandidateWorkspaceSnapshotEvidenceSchema2.parse({
3593
+ kind: "agent-candidate-workspace-snapshot",
3594
+ digest: sha256Bytes(manifestBytes),
3595
+ material: afterState,
3596
+ manifest: persisted.manifest,
3597
+ archive: persisted.archive
3333
3598
  });
3334
3599
  const material = {
3335
- schemaVersion: 1,
3336
3600
  kind: "agent-candidate-task-outcome-material",
3337
3601
  executionPlanDigest: state.executionPlan.value.digest,
3338
- baseRepository: {
3339
- identity: repository.identity,
3340
- rootIdentity: repository.rootIdentity,
3341
- commit: repository.baseCommit,
3342
- tree: repository.baseTree
3343
- },
3344
- resultRepository: {
3345
- identity: repository.identity,
3346
- rootIdentity: repository.rootIdentity,
3347
- commit: verified.resultCommit,
3348
- tree: verified.resultTree
3602
+ outcome: {
3603
+ kind: "workspace",
3604
+ baseRepository: {
3605
+ identity: repository.identity,
3606
+ rootIdentity: repository.rootIdentity,
3607
+ commit: repository.baseCommit,
3608
+ tree: repository.baseTree
3609
+ },
3610
+ resultRepository: {
3611
+ identity: repository.identity,
3612
+ rootIdentity: repository.rootIdentity,
3613
+ commit: verified.resultCommit,
3614
+ tree: verified.resultTree
3615
+ },
3616
+ afterState: snapshot,
3617
+ gitDiff: {
3618
+ format: "git-diff-binary",
3619
+ artifact: persisted.gitDiff
3620
+ }
3621
+ }
3622
+ };
3623
+ const evidence = await persistTaskOutcomeEvidence(state, material, outputArtifacts, signal);
3624
+ const storedPatch = Uint8Array.from(patch);
3625
+ return Object.freeze({
3626
+ kind: "workspace",
3627
+ evidence,
3628
+ get patch() {
3629
+ return Uint8Array.from(storedPatch);
3349
3630
  },
3350
- afterState: snapshot,
3351
- gitDiff: {
3352
- format: "git-diff-binary",
3353
- artifact: gitDiff
3631
+ [verifiedTaskOutcomeBrand]: true
3632
+ });
3633
+ }
3634
+ function verifyOutputTaskCapture(capturedBytes, expected, protectedValues) {
3635
+ if (capturedBytes.byteLength === 0) throw new Error("candidate task output cannot be empty");
3636
+ if (capturedBytes.byteLength > expected.maxBytes) {
3637
+ throw new Error(`candidate task output exceeds the frozen ${expected.maxBytes}-byte maximum`);
3638
+ }
3639
+ const output = Uint8Array.from(capturedBytes);
3640
+ assertNoProtectedBytes(output, protectedValues);
3641
+ return {
3642
+ kind: "output",
3643
+ bytes: output,
3644
+ spec: { mediaType: expected.mediaType, maxBytes: expected.maxBytes }
3645
+ };
3646
+ }
3647
+ async function persistVerifiedOutputTaskOutcome(state, verified, persisted, outputArtifacts, signal) {
3648
+ if (persisted.spec.mediaType !== verified.spec.mediaType || persisted.spec.maxBytes !== verified.spec.maxBytes) {
3649
+ throw new Error("persisted task output changed the signed media constraints");
3650
+ }
3651
+ const material = {
3652
+ kind: "agent-candidate-task-outcome-material",
3653
+ executionPlanDigest: state.executionPlan.value.digest,
3654
+ outcome: {
3655
+ kind: "output",
3656
+ spec: verified.spec,
3657
+ artifact: persisted.artifact
3354
3658
  }
3355
3659
  };
3660
+ const evidence = await persistTaskOutcomeEvidence(state, material, outputArtifacts, signal);
3661
+ const storedOutput = Uint8Array.from(verified.bytes);
3662
+ return Object.freeze({
3663
+ kind: "output",
3664
+ evidence,
3665
+ spec: immutableCandidateValue(verified.spec),
3666
+ get bytes() {
3667
+ return Uint8Array.from(storedOutput);
3668
+ },
3669
+ [verifiedTaskOutcomeBrand]: true
3670
+ });
3671
+ }
3672
+ async function persistTaskOutcomeEvidence(state, material, outputArtifacts, signal) {
3356
3673
  const bytes = canonicalCandidateBytes(material);
3357
3674
  const digest = sha256Bytes(bytes);
3358
3675
  const artifact = await persistCandidateOutputArtifact(outputArtifacts, {
@@ -3361,23 +3678,14 @@ async function persistVerifiedCandidateTaskOutcome(state, capture, outputArtifac
3361
3678
  bytes,
3362
3679
  signal
3363
3680
  });
3364
- const evidence = immutableCandidateValue(
3681
+ return immutableCandidateValue(
3365
3682
  agentCandidateTaskOutcomeEvidenceSchema.parse({
3366
- schemaVersion: 1,
3367
3683
  kind: "agent-candidate-task-outcome",
3368
3684
  digest,
3369
3685
  material,
3370
3686
  artifact
3371
3687
  })
3372
3688
  );
3373
- const storedPatch = Uint8Array.from(patch);
3374
- return Object.freeze({
3375
- evidence,
3376
- get patch() {
3377
- return Uint8Array.from(storedPatch);
3378
- },
3379
- [verifiedTaskOutcomeBrand]: true
3380
- });
3381
3689
  }
3382
3690
  async function persistCandidateBenchmarkResult(state, termination, outcome, grader, outputArtifacts, protectedValues, signal) {
3383
3691
  signal?.throwIfAborted();
@@ -3386,6 +3694,7 @@ async function persistCandidateBenchmarkResult(state, termination, outcome, grad
3386
3694
  executionId: state.executionId,
3387
3695
  termination: frozenTermination,
3388
3696
  outcome,
3697
+ expectedGrader: state.benchmarkTask.grader,
3389
3698
  grader,
3390
3699
  artifacts: outputArtifacts,
3391
3700
  signal
@@ -3401,24 +3710,13 @@ async function persistCandidateBenchmarkResult(state, termination, outcome, grad
3401
3710
  bytes: rawEvidence,
3402
3711
  signal
3403
3712
  });
3404
- const task = state.executionPlan.value.material.task;
3405
3713
  const material = {
3406
- schemaVersion: 1,
3407
3714
  kind: "agent-candidate-benchmark-result-material",
3408
3715
  executionPlanDigest: state.executionPlan.value.digest,
3409
3716
  taskOutcomeDigest: outcome.evidence.digest,
3410
- benchmark: {
3411
- name: task.benchmark,
3412
- version: task.benchmarkVersion,
3413
- taskId: task.taskId,
3414
- splitDigest: task.splitDigest
3415
- },
3416
- grader: {
3417
- name: graded.grader.name,
3418
- version: graded.grader.version,
3419
- artifact: graded.grader.artifact
3420
- },
3717
+ grader: graded.grader,
3421
3718
  evidence: evidenceRef,
3719
+ grading: graded.grading,
3422
3720
  score: evaluation.score,
3423
3721
  passed: evaluation.passed,
3424
3722
  dimensions: evaluation.dimensions
@@ -3433,7 +3731,6 @@ async function persistCandidateBenchmarkResult(state, termination, outcome, grad
3433
3731
  });
3434
3732
  return immutableCandidateValue(
3435
3733
  agentCandidateBenchmarkResultEvidenceSchema.parse({
3436
- schemaVersion: 1,
3437
3734
  kind: "agent-candidate-benchmark-result",
3438
3735
  digest,
3439
3736
  material,
@@ -3442,7 +3739,7 @@ async function persistCandidateBenchmarkResult(state, termination, outcome, grad
3442
3739
  );
3443
3740
  }
3444
3741
  async function verifyTaskOutcomeArchive(state, snapshot, archive, protectedValues) {
3445
- const root = await mkdtemp3(join3(tmpdir3(), "agent-candidate-task-archive-"));
3742
+ const root = await mkdtemp2(join2(tmpdir2(), "agent-candidate-task-archive-"));
3446
3743
  try {
3447
3744
  await state.ports.workspaces.materialize({
3448
3745
  role: "task",
@@ -3453,7 +3750,40 @@ async function verifyTaskOutcomeArchive(state, snapshot, archive, protectedValue
3453
3750
  const files = await readMaterializedWorkspaceFiles(root, snapshot.material);
3454
3751
  for (const file of files) assertNoProtectedBytes(file.bytes, protectedValues);
3455
3752
  } finally {
3456
- await rm3(root, { recursive: true, force: true });
3753
+ await rm2(root, { recursive: true, force: true });
3754
+ }
3755
+ }
3756
+ async function verifyMemoryCapture(state, capture, protectedValues, signal) {
3757
+ if (state.memory.mode === "disabled") {
3758
+ if (capture.memoryAfter) throw new Error("disabled memory cannot return an after-state");
3759
+ return;
3760
+ }
3761
+ const memory = capture.memoryAfter;
3762
+ if (!memory) throw new Error("isolated memory is missing its protected after-state");
3763
+ if (memory.archive.byteLength === 0) throw new Error("isolated memory archive cannot be empty");
3764
+ const manifestBytes = canonicalCandidateBytes(memory.afterState);
3765
+ assertNoProtectedBytes(manifestBytes, protectedValues);
3766
+ assertNoProtectedBytes(memory.archive, protectedValues);
3767
+ const snapshot = agentCandidateWorkspaceSnapshotEvidenceSchema2.parse({
3768
+ kind: "agent-candidate-workspace-snapshot",
3769
+ digest: sha256Bytes(manifestBytes),
3770
+ material: memory.afterState,
3771
+ manifest: embeddedCandidateArtifact(manifestBytes),
3772
+ archive: embeddedCandidateArtifact(memory.archive)
3773
+ });
3774
+ const root = await mkdtemp2(join2(tmpdir2(), "agent-candidate-memory-after-"));
3775
+ try {
3776
+ await state.ports.workspaces.materialize({
3777
+ role: "memory",
3778
+ snapshot,
3779
+ archive: Uint8Array.from(memory.archive),
3780
+ destination: root
3781
+ });
3782
+ const files = await readMaterializedWorkspaceFiles(root, memory.afterState);
3783
+ for (const file of files) assertNoProtectedBytes(file.bytes, protectedValues);
3784
+ signal?.throwIfAborted();
3785
+ } finally {
3786
+ await rm2(root, { recursive: true, force: true });
3457
3787
  }
3458
3788
  }
3459
3789
  function normalizeEvaluation(evaluation, termination) {
@@ -3636,9 +3966,29 @@ async function executePreparedAgentCandidate(prepared, options) {
3636
3966
  } catch (error) {
3637
3967
  return await failBeforeActivation(prepared, state, error, "failed", cleanupTimeoutMs);
3638
3968
  }
3969
+ let preparationEvidence;
3970
+ try {
3971
+ const [executionPlan, materializationReceipt] = await Promise.all([
3972
+ persistCandidateOutputArtifact(options.outputArtifacts, {
3973
+ executionId: state.executionId,
3974
+ purpose: "execution-plan",
3975
+ bytes: state.executionPlan.bytes
3976
+ }),
3977
+ persistCandidateOutputArtifact(options.outputArtifacts, {
3978
+ executionId: state.executionId,
3979
+ purpose: "materialization-receipt",
3980
+ bytes: state.materializationReceipt.bytes
3981
+ })
3982
+ ]);
3983
+ preparationEvidence = Object.freeze({ executionPlan, materializationReceipt });
3984
+ } catch (error) {
3985
+ return await failBeforeActivation(prepared, state, error, "failed", cleanupTimeoutMs);
3986
+ }
3639
3987
  let acquired;
3640
3988
  try {
3641
- acquired = await options.claimStore.tryClaim(candidateExecutionClaim(prepared));
3989
+ acquired = await options.claimStore.tryClaim(
3990
+ candidateExecutionClaim(prepared, preparationEvidence)
3991
+ );
3642
3992
  } catch (error) {
3643
3993
  return await failBeforeActivation(prepared, state, error, "failed", cleanupTimeoutMs);
3644
3994
  }
@@ -3790,6 +4140,7 @@ async function executePreparedAgentCandidate(prepared, options) {
3790
4140
  const execution = await runAndStopExecutor(
3791
4141
  options.executor,
3792
4142
  request,
4143
+ state.benchmarkTask.outcome,
3793
4144
  protectedTraceStore,
3794
4145
  deadlineAtMs,
3795
4146
  cleanupTimeoutMs
@@ -3878,9 +4229,9 @@ async function executePreparedAgentCandidate(prepared, options) {
3878
4229
  state.trace.runId,
3879
4230
  settlementResult.settlement
3880
4231
  );
3881
- const taskOutcome = await persistVerifiedCandidateTaskOutcome(
4232
+ const { persistedCapture, taskOutcome } = await persistVerifiedAgentCandidateExecutorCapture(
3882
4233
  state,
3883
- execution.finalCapture.taskOutcome,
4234
+ execution.finalCapture,
3884
4235
  options.outputArtifacts,
3885
4236
  protectedValues,
3886
4237
  signal
@@ -3901,6 +4252,7 @@ async function executePreparedAgentCandidate(prepared, options) {
3901
4252
  settlementResult.settlement,
3902
4253
  {
3903
4254
  finalCapture: execution.finalCapture,
4255
+ persistedCapture,
3904
4256
  modelSettlement,
3905
4257
  taskOutcome,
3906
4258
  benchmarkResult,
@@ -3926,18 +4278,16 @@ async function executePreparedAgentCandidate(prepared, options) {
3926
4278
  let terminal;
3927
4279
  try {
3928
4280
  terminal = result.succeeded ? {
3929
- schemaVersion: 1,
3930
4281
  status: "succeeded",
3931
- usage: settlementResult.settlement.fixedUsage,
4282
+ usage: settlementResult.settlement.usage,
3932
4283
  modelSettlement: result.artifacts.modelSettlement,
3933
4284
  taskOutcome: result.artifacts.taskOutcome,
3934
4285
  benchmarkResult: result.artifacts.benchmarkResult,
3935
4286
  runReceipt: result.artifacts.runReceipt
3936
4287
  } : {
3937
- schemaVersion: 1,
3938
4288
  status: "failed",
3939
4289
  failureClass,
3940
- usage: settlementResult.settlement.fixedUsage,
4290
+ usage: settlementResult.settlement.usage,
3941
4291
  modelSettlement: modelSettlement.artifact,
3942
4292
  failureEvidence: await withinCandidateCleanupDeadline(
3943
4293
  () => persistFailureEvidence(
@@ -3984,7 +4334,7 @@ async function executePreparedAgentCandidate(prepared, options) {
3984
4334
  settlementResult.settlement.usage
3985
4335
  );
3986
4336
  }
3987
- async function runAndStopExecutor(executor, request, traceStore, deadlineAtMs, cleanupTimeoutMs) {
4337
+ async function runAndStopExecutor(executor, request, expectedOutcome, traceStore, deadlineAtMs, cleanupTimeoutMs) {
3988
4338
  const timeoutMs = request.hardLimits.timeoutMs;
3989
4339
  const timeoutError = new CandidateExecutionDeadlineError(timeoutMs);
3990
4340
  if (Date.now() >= deadlineAtMs) {
@@ -4039,10 +4389,10 @@ async function runAndStopExecutor(executor, request, traceStore, deadlineAtMs, c
4039
4389
  }
4040
4390
  if (!capture || timedOut) controller.abort(executionError);
4041
4391
  const stopReason = timedOut ? "timeout" : capture ? "completed" : "failed";
4042
- let stopped;
4392
+ const cleanupDeadlineAtMs = Date.now() + cleanupTimeoutMs;
4043
4393
  try {
4044
- stopped = await withinCandidateCleanupDeadline(
4045
- () => executor.stopAndCapture(
4394
+ const stopped = await withinCandidateCleanupDeadline(
4395
+ (cleanupSignal) => executor.stop(
4046
4396
  {
4047
4397
  executionId: request.executionId,
4048
4398
  executionPlanDigest: request.executionPlan.value.digest
@@ -4050,35 +4400,65 @@ async function runAndStopExecutor(executor, request, traceStore, deadlineAtMs, c
4050
4400
  {
4051
4401
  traceStore,
4052
4402
  reason: stopReason,
4053
- signal: controller.signal,
4054
- deadlineAtMs
4403
+ signal: cleanupSignal,
4404
+ deadlineAtMs: cleanupDeadlineAtMs
4055
4405
  }
4056
4406
  ),
4057
- Date.now() + cleanupTimeoutMs,
4407
+ cleanupDeadlineAtMs,
4058
4408
  "candidate process termination"
4059
4409
  );
4060
- if (!stopped || typeof stopped !== "object" || stopped.stopped !== true) {
4061
- throw new Error("candidate executor did not acknowledge exact process termination");
4062
- }
4410
+ sealAgentCandidateExecutorStopAcknowledgement(stopped);
4063
4411
  } catch (stopError) {
4412
+ let disposalError2;
4413
+ try {
4414
+ await disposeExecutor(executor, request, cleanupDeadlineAtMs);
4415
+ } catch (error) {
4416
+ disposalError2 = error;
4417
+ }
4064
4418
  if (timer) clearTimeout(timer);
4065
4419
  controller.abort(stopError);
4066
4420
  return {
4067
4421
  kind: "error",
4068
- error: new Error(joinErrors(executionError, stopError)),
4422
+ error: new Error(joinErrors(executionError, stopError, disposalError2)),
4069
4423
  ...timedOut ? { termination: { kind: "timeout", timeoutMs } } : {},
4070
4424
  processStopped: false
4071
4425
  };
4072
4426
  }
4073
4427
  let finalCapture;
4428
+ let finalCaptureError;
4074
4429
  try {
4075
- finalCapture = sealAgentCandidateExecutorFinalCapture(stopped);
4430
+ finalCapture = sealAgentCandidateExecutorFinalCapture(
4431
+ await withinCandidateCleanupDeadline(
4432
+ (cleanupSignal) => executor.capture(
4433
+ {
4434
+ executionId: request.executionId,
4435
+ executionPlanDigest: request.executionPlan.value.digest
4436
+ },
4437
+ {
4438
+ traceStore,
4439
+ signal: cleanupSignal
4440
+ }
4441
+ ),
4442
+ cleanupDeadlineAtMs,
4443
+ "candidate final evidence capture"
4444
+ ),
4445
+ expectedOutcome
4446
+ );
4076
4447
  } catch (captureError) {
4448
+ finalCaptureError = captureError;
4449
+ }
4450
+ let disposalError;
4451
+ try {
4452
+ await disposeExecutor(executor, request, cleanupDeadlineAtMs);
4453
+ } catch (disposeError) {
4454
+ disposalError = disposeError;
4455
+ }
4456
+ if (finalCaptureError || disposalError || !finalCapture) {
4077
4457
  if (timer) clearTimeout(timer);
4078
- controller.abort(captureError);
4458
+ controller.abort(finalCaptureError ?? disposalError);
4079
4459
  return {
4080
4460
  kind: "error",
4081
- error: new Error(joinErrors(executionError, captureError)),
4461
+ error: new Error(joinErrors(executionError, finalCaptureError, disposalError)),
4082
4462
  ...timedOut ? { termination: { kind: "timeout", timeoutMs } } : {},
4083
4463
  processStopped: true
4084
4464
  };
@@ -4114,6 +4494,25 @@ async function runAndStopExecutor(executor, request, traceStore, deadlineAtMs, c
4114
4494
  processStopped: true
4115
4495
  };
4116
4496
  }
4497
+ async function disposeExecutor(executor, request, cleanupDeadlineAtMs) {
4498
+ const dispose = executor.dispose;
4499
+ if (!dispose) return;
4500
+ const disposed = await withinCandidateCleanupDeadline(
4501
+ (cleanupSignal) => dispose.call(
4502
+ executor,
4503
+ {
4504
+ executionId: request.executionId,
4505
+ executionPlanDigest: request.executionPlan.value.digest
4506
+ },
4507
+ { signal: cleanupSignal }
4508
+ ),
4509
+ cleanupDeadlineAtMs,
4510
+ "candidate execution resource disposal"
4511
+ );
4512
+ if (!disposed || disposed.disposed !== true || Object.keys(disposed).some((key) => key !== "disposed")) {
4513
+ throw new Error("candidate executor did not acknowledge resource disposal");
4514
+ }
4515
+ }
4117
4516
  async function failBeforeActivation(prepared, state, error, reason, cleanupTimeoutMs) {
4118
4517
  beginPreparedCandidateSettlement(prepared);
4119
4518
  const cleanupDeadlineAtMs = candidateCleanupDeadline(cleanupTimeoutMs);
@@ -4168,10 +4567,9 @@ async function failClaimedExecution(prepared, state, lease, claimStore, outputAr
4168
4567
  claimStore,
4169
4568
  lease,
4170
4569
  {
4171
- schemaVersion: 1,
4172
4570
  status: "failed",
4173
4571
  failureClass,
4174
- usage: settled.settlement.fixedUsage,
4572
+ usage: settled.settlement.usage,
4175
4573
  modelSettlement: modelSettlement.artifact,
4176
4574
  failureEvidence
4177
4575
  },
@@ -4268,7 +4666,6 @@ async function finishClaim(store, lease, terminal, deadlineAtMs) {
4268
4666
  }
4269
4667
  async function persistFailureEvidence(state, reason, failureClass, termination, outputArtifacts) {
4270
4668
  const bytes = canonicalCandidateBytes({
4271
- schemaVersion: 1,
4272
4669
  kind: "agent-candidate-execution-failure",
4273
4670
  executionId: state.executionId,
4274
4671
  bundleDigest: state.bundle.digest,
@@ -4300,10 +4697,24 @@ var CandidateExecutionDeadlineError = class extends Error {
4300
4697
  };
4301
4698
 
4302
4699
  // src/candidate-execution/verify.ts
4303
- import { agentCandidateBundleSchema as agentCandidateBundleSchema2 } from "@tangle-network/agent-interface";
4700
+ import { agentCandidateBundleSchema } from "@tangle-network/agent-interface";
4304
4701
  var verifiedCandidateState = /* @__PURE__ */ new WeakMap();
4702
+ var AGENT_CANDIDATE_EXECUTION_SUPPORT = Object.freeze({
4703
+ outcomes: Object.freeze(["workspace", "output"]),
4704
+ code: Object.freeze(["disabled", "no-op", "git-patch"]),
4705
+ memory: Object.freeze(["disabled", "isolated"]),
4706
+ knowledge: true,
4707
+ profile: Object.freeze({
4708
+ mcpTransports: Object.freeze(["stdio"]),
4709
+ remoteMcp: false,
4710
+ tools: false,
4711
+ permissions: false,
4712
+ modes: false,
4713
+ confidential: false
4714
+ })
4715
+ });
4305
4716
  async function verifyAgentCandidateBundle(input, ports) {
4306
- const parsed = agentCandidateBundleSchema2.parse(input);
4717
+ const parsed = agentCandidateBundleSchema.parse(input);
4307
4718
  const withoutDigest = omitTopLevelDigest(parsed);
4308
4719
  const actualDigest = canonicalCandidateDigest(withoutDigest);
4309
4720
  if (actualDigest !== parsed.digest) {
@@ -4311,6 +4722,7 @@ async function verifyAgentCandidateBundle(input, ports) {
4311
4722
  }
4312
4723
  const canonicalBytes = canonicalCandidateBytes(withoutDigest);
4313
4724
  verifyBytes(canonicalBytes, parsed.digest, canonicalBytes.byteLength, "candidate bundle");
4725
+ assertCandidateProfileExecutionSupport(parsed.profile);
4314
4726
  const artifactBytes = /* @__PURE__ */ new Map();
4315
4727
  const readArtifact = async (artifact) => {
4316
4728
  const key = artifactCacheKey(artifact);
@@ -4345,7 +4757,16 @@ async function verifyAgentCandidateBundle(input, ports) {
4345
4757
  artifactBytes.set(artifactCacheKey(parsed.execution.workspace.manifest), workspace.manifest);
4346
4758
  artifactBytes.set(artifactCacheKey(parsed.execution.workspace.archive), workspace.archive);
4347
4759
  }
4348
- if (parsed.knowledge) await readArtifact(parsed.knowledge.manifest);
4760
+ if (parsed.knowledge) {
4761
+ const knowledge = await verifyWorkspaceSnapshotArtifacts(
4762
+ parsed.knowledge.snapshot,
4763
+ ports.artifacts
4764
+ );
4765
+ artifactBytes.set(artifactCacheKey(parsed.knowledge.snapshot.manifest), knowledge.manifest);
4766
+ artifactBytes.set(artifactCacheKey(parsed.knowledge.snapshot.archive), knowledge.archive);
4767
+ if (parsed.knowledge.retrievalConfig) await readArtifact(parsed.knowledge.retrievalConfig);
4768
+ await readArtifact(parsed.knowledge.evaluation);
4769
+ }
4349
4770
  if (parsed.memory.mode === "isolated" && parsed.memory.seed)
4350
4771
  await readArtifact(parsed.memory.seed);
4351
4772
  deepFreezeCandidate(parsed);
@@ -4398,38 +4819,73 @@ function resourceKey(resource) {
4398
4819
  return canonicalCandidateDigest(resource);
4399
4820
  }
4400
4821
 
4822
+ // src/candidate-execution/knowledge.ts
4823
+ import { mkdtemp as mkdtemp3, rm as rm3 } from "fs/promises";
4824
+ import { tmpdir as tmpdir3 } from "os";
4825
+ import { join as join3, posix } from "path";
4826
+ var CANDIDATE_KNOWLEDGE_ROOT_ENV = "TANGLE_CANDIDATE_KNOWLEDGE_ROOT";
4827
+ var CANDIDATE_KNOWLEDGE_RETRIEVAL_CONFIG_ENV = "TANGLE_CANDIDATE_KNOWLEDGE_RETRIEVAL_CONFIG";
4828
+ function candidateKnowledgeExecutionPaths(taskRoot, hasRetrievalConfig) {
4829
+ if (!posix.isAbsolute(taskRoot) || posix.normalize(taskRoot) !== taskRoot) {
4830
+ throw new Error("candidate knowledge requires a normalized absolute task root");
4831
+ }
4832
+ const parent = posix.join(taskRoot, ".tangle");
4833
+ return {
4834
+ root: posix.join(parent, "knowledge"),
4835
+ ...hasRetrievalConfig ? { retrievalConfig: posix.join(parent, "knowledge-retrieval-config.json") } : {}
4836
+ };
4837
+ }
4838
+ async function prepareAgentCandidateKnowledge(candidate, ports) {
4839
+ const knowledge = candidate.bundle.knowledge;
4840
+ if (!knowledge) return void 0;
4841
+ const archive = await verifiedArtifactBytes(candidate, knowledge.snapshot.archive);
4842
+ const retrievalConfig = knowledge.retrievalConfig ? await verifiedArtifactBytes(candidate, knowledge.retrievalConfig) : void 0;
4843
+ const root = await mkdtemp3(join3(tmpdir3(), "agent-candidate-knowledge-"));
4844
+ try {
4845
+ await ports.workspaces.materialize({
4846
+ role: "knowledge",
4847
+ snapshot: knowledge.snapshot,
4848
+ archive,
4849
+ destination: root
4850
+ });
4851
+ const files = await readMaterializedWorkspaceFiles(root, knowledge.snapshot.material);
4852
+ return Object.freeze({
4853
+ candidate: knowledge.candidate,
4854
+ snapshot: knowledge.snapshot,
4855
+ files: Object.freeze(
4856
+ files.map(
4857
+ (file) => Object.freeze({ path: file.path, mode: file.mode, bytes: Uint8Array.from(file.bytes) })
4858
+ )
4859
+ ),
4860
+ ...retrievalConfig ? { retrievalConfig: Uint8Array.from(retrievalConfig) } : {}
4861
+ });
4862
+ } finally {
4863
+ await rm3(root, { recursive: true, force: true });
4864
+ }
4865
+ }
4866
+
4401
4867
  // src/candidate-execution/prepare.ts
4402
4868
  import { randomBytes as randomBytes2 } from "crypto";
4403
4869
  import { lstat as lstat2, readdir as readdir2 } from "fs/promises";
4404
- import { isAbsolute, posix, relative as relative2, resolve as resolveHostPath } from "path";
4870
+ import { isAbsolute, posix as posix2, relative as relative2, resolve as resolveHostPath } from "path";
4405
4871
  import {
4872
+ agentCandidateBenchmarkSuiteSchema as agentCandidateBenchmarkSuiteSchema2,
4873
+ agentCandidateBenchmarkTaskSchema as agentCandidateBenchmarkTaskSchema2,
4406
4874
  agentCandidateContainerSchema,
4407
4875
  agentCandidateExecutionLimitsSchema,
4408
4876
  agentCandidateExecutionPlanEvidenceSchema as agentCandidateExecutionPlanEvidenceSchema2,
4409
4877
  agentCandidateExecutionPlanMaterialSchema,
4410
4878
  agentCandidateMaterializationReceiptSchema as agentCandidateMaterializationReceiptSchema2,
4411
4879
  agentCandidateModelAccessNetworkSchema,
4412
- agentCandidateWorkspaceSnapshotEvidenceSchema as agentCandidateWorkspaceSnapshotEvidenceSchema2,
4880
+ agentCandidateRunCellSchema,
4881
+ agentCandidateTaskOutcomeSpecSchema,
4882
+ agentCandidateWorkspaceSnapshotEvidenceSchema as agentCandidateWorkspaceSnapshotEvidenceSchema3,
4413
4883
  sha256DigestSchema
4414
4884
  } from "@tangle-network/agent-interface";
4415
4885
  import {
4416
4886
  applyAgentCandidateWorkspacePlan,
4417
4887
  materializeCandidateProfile
4418
4888
  } from "@tangle-network/agent-profile-materialize";
4419
- var MATERIALIZER_HARNESSES = /* @__PURE__ */ new Set([
4420
- "claude-code",
4421
- "claude",
4422
- "claudish",
4423
- "nanoclaw",
4424
- "codex",
4425
- "opencode",
4426
- "kimi-code",
4427
- "kimi",
4428
- "pi",
4429
- "gemini",
4430
- "hermes",
4431
- "openclaw"
4432
- ]);
4433
4889
  var MIN_RESERVATION_TTL_MS = 15 * 6e4;
4434
4890
  var PREPARED_HOLD_MARGIN_MS = 5 * 6e4;
4435
4891
  async function prepareAgentCandidateExecution(candidate, task, ports, options = {}) {
@@ -4437,12 +4893,23 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
4437
4893
  const verifiedState = getVerifiedCandidateState(candidate);
4438
4894
  assertSameVerificationPorts(verifiedState.ports, ports);
4439
4895
  const bundle = candidate.bundle;
4440
- assertCandidateProfileExecutionSupport(bundle.profile);
4441
- const harness = materializerHarness(bundle.execution.harness);
4896
+ if (task.runCell.bundleDigest !== bundle.digest) {
4897
+ throw new Error("candidate experiment cell does not bind the verified bundle");
4898
+ }
4899
+ const benchmarkTask = task.task;
4900
+ const attempt = {
4901
+ number: task.runCell.attempt,
4902
+ maxAttempts: benchmarkTask.attempt.maxAttempts,
4903
+ retryPolicy: benchmarkTask.attempt.retryPolicy
4904
+ };
4905
+ const harness = candidateMaterializerHarness(bundle.execution.harness);
4442
4906
  assertTaskInput(task, bundle.execution.instructionDelivery);
4443
- const resultTimeoutMs = candidateResultTimeout(options.resultTimeoutMs, task.limits.timeoutMs);
4907
+ const resultTimeoutMs = candidateResultTimeout(
4908
+ options.resultTimeoutMs,
4909
+ benchmarkTask.limits.timeoutMs
4910
+ );
4444
4911
  const ownerWindowMs = candidateExecutionOwnerWindowMs(
4445
- task.limits.timeoutMs,
4912
+ benchmarkTask.limits.timeoutMs,
4446
4913
  cleanupTimeoutMs,
4447
4914
  resultTimeoutMs
4448
4915
  );
@@ -4451,22 +4918,26 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
4451
4918
  throw new Error("candidate reservation window exceeds the supported timer range");
4452
4919
  }
4453
4920
  assertDisjointHostStagingRoots(task);
4454
- const instructionBytes = Buffer.from(task.instruction, "utf8");
4455
- const instructionDigest = sha256Bytes(instructionBytes);
4456
- const taskArtifacts = await verifyWorkspaceSnapshotArtifacts(task.workspace, ports.artifacts);
4921
+ const instructionBytes = Buffer.from(benchmarkTask.instruction, "utf8");
4922
+ const taskArtifacts = await verifyWorkspaceSnapshotArtifacts(
4923
+ benchmarkTask.workspace,
4924
+ ports.artifacts
4925
+ );
4457
4926
  await ports.workspaces.materialize({
4458
4927
  role: "task",
4459
- snapshot: task.workspace,
4928
+ snapshot: benchmarkTask.workspace,
4460
4929
  archive: taskArtifacts.archive,
4461
4930
  destination: task.stagingRoots.taskRoot
4462
4931
  });
4463
- await verifyMaterializedWorkspace(task.stagingRoots.taskRoot, task.workspace.material, {
4932
+ await verifyMaterializedWorkspace(task.stagingRoots.taskRoot, benchmarkTask.workspace.material, {
4464
4933
  ignoredProtectedRootEntries: [".git", ".sidecar"]
4465
4934
  });
4466
- await verifyTaskCheckout(task.stagingRoots.taskRoot, task.repository);
4935
+ if (benchmarkTask.repository) {
4936
+ await verifyTaskCheckout(task.stagingRoots.taskRoot, benchmarkTask.repository);
4937
+ }
4467
4938
  const taskExecutorFiles = await readMaterializedWorkspaceFiles(
4468
4939
  task.stagingRoots.taskRoot,
4469
- task.workspace.material,
4940
+ benchmarkTask.workspace.material,
4470
4941
  { ignoredProtectedRootEntries: [".git", ".sidecar"] }
4471
4942
  );
4472
4943
  let candidateArchive;
@@ -4504,30 +4975,33 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
4504
4975
  );
4505
4976
  await verifyMaterializedProfileWorkspace(
4506
4977
  task.stagingRoots.profileRoot,
4507
- profileApplication.profilePlan.material
4978
+ profileApplication.profileActivation.profilePlan.material
4508
4979
  );
4509
4980
  const profilePlanBytes = await readVerifiedArtifact(
4510
- profileApplication.profilePlan.artifact,
4981
+ profileApplication.profileActivation.profilePlan.artifact,
4511
4982
  ports.artifacts
4512
4983
  );
4513
4984
  if (!Buffer.from(profilePlanBytes).equals(
4514
- Buffer.from(canonicalCandidateBytes(profileApplication.profilePlan.material))
4985
+ Buffer.from(
4986
+ canonicalCandidateBytes(profileApplication.profileActivation.profilePlan.material)
4987
+ )
4515
4988
  )) {
4516
4989
  throw new Error("profile materializer did not capture exact canonical plan bytes");
4517
4990
  }
4991
+ const profileActivation = profileApplication.profileActivation;
4518
4992
  const container = await resolveContainer(candidate, task, ports);
4519
4993
  const resolvedModel = await resolveModel(candidate, task, ports);
4520
- const preparationId = `candidate-preparation-v1.${randomBytes2(32).toString("base64url")}`;
4994
+ const preparationId = `candidate-preparation.${randomBytes2(32).toString("base64url")}`;
4521
4995
  const reservationExpiresAtMs = Date.now() + Math.max(MIN_RESERVATION_TTL_MS, reservationWindowMs);
4522
4996
  const modelReservation = await withinCandidateCleanupDeadline(
4523
4997
  () => ports.models.reserveGrant({
4524
4998
  executionId: task.executionId,
4525
4999
  preparationId,
4526
5000
  expiresAtMs: reservationExpiresAtMs,
4527
- attempt: task.attempt,
5001
+ attempt,
4528
5002
  bundleDigest: bundle.digest,
4529
5003
  resolved: resolvedModel,
4530
- limits: modelLimits2(task.limits)
5004
+ limits: modelLimits2(benchmarkTask.limits)
4531
5005
  }),
4532
5006
  candidateCleanupDeadline(cleanupTimeoutMs),
4533
5007
  "protected model reservation"
@@ -4536,7 +5010,7 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
4536
5010
  try {
4537
5011
  validateProtectedModelReservation(
4538
5012
  modelReservation,
4539
- task.limits,
5013
+ benchmarkTask.limits,
4540
5014
  preparationId,
4541
5015
  reservationExpiresAtMs
4542
5016
  );
@@ -4549,11 +5023,11 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
4549
5023
  cleanupTimeoutMs
4550
5024
  );
4551
5025
  const memory = preparedMemory.value;
4552
- const knowledge = bundle.knowledge ? {
4553
- snapshotId: bundle.knowledge.snapshotId,
4554
- manifestDigest: bundle.knowledge.manifest.sha256,
4555
- manifest: await verifiedArtifactBytes(candidate, bundle.knowledge.manifest)
4556
- } : void 0;
5026
+ const knowledge = await prepareAgentCandidateKnowledge(candidate, ports);
5027
+ const knowledgePaths = knowledge ? candidateKnowledgeExecutionPaths(
5028
+ task.executionRoots.taskRoot,
5029
+ knowledge.retrievalConfig !== void 0
5030
+ ) : void 0;
4557
5031
  const baseLaunch = buildLaunch(candidate, task, profileApplication.flags);
4558
5032
  const publicEnv = mergePublicEnvironment(
4559
5033
  bundle.execution.env ?? {},
@@ -4563,29 +5037,25 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
4563
5037
  kind: "public",
4564
5038
  value: bundle.execution.instructionDelivery.path
4565
5039
  }
5040
+ } : {},
5041
+ knowledgePaths ? {
5042
+ [CANDIDATE_KNOWLEDGE_ROOT_ENV]: {
5043
+ kind: "public",
5044
+ value: knowledgePaths.root
5045
+ },
5046
+ ...knowledgePaths.retrievalConfig ? {
5047
+ [CANDIDATE_KNOWLEDGE_RETRIEVAL_CONFIG_ENV]: {
5048
+ kind: "public",
5049
+ value: knowledgePaths.retrievalConfig
5050
+ }
5051
+ } : {}
4566
5052
  } : {}
4567
5053
  );
4568
- const routes = modelRoutes(bundle.profile, task.model.requested);
5054
+ const routes = modelRoutes(bundle.profile, benchmarkTask.model.requested);
4569
5055
  const executionMaterial = {
4570
- schemaVersion: 1,
4571
5056
  kind: "agent-candidate-execution-plan-material",
4572
- bundleDigest: bundle.digest,
5057
+ runCell: task.runCell,
4573
5058
  executionId: task.executionId,
4574
- attempt: task.attempt,
4575
- task: {
4576
- benchmark: task.benchmark,
4577
- benchmarkVersion: task.benchmarkVersion,
4578
- taskId: task.taskId,
4579
- splitDigest: task.splitDigest,
4580
- instruction: {
4581
- encoding: "utf8",
4582
- sha256: instructionDigest,
4583
- byteLength: instructionBytes.byteLength,
4584
- delivery: bundle.execution.instructionDelivery
4585
- },
4586
- repository: task.repository,
4587
- workspace: task.workspace
4588
- },
4589
5059
  workspaces: {
4590
5060
  taskRoot: task.executionRoots.taskRoot,
4591
5061
  ...task.executionRoots.candidateRoot ? { candidateRoot: task.executionRoots.candidateRoot } : {}
@@ -4595,6 +5065,8 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
4595
5065
  profile: profileApplication.application,
4596
5066
  harness: bundle.execution.harness,
4597
5067
  harnessVersion: bundle.execution.harnessVersion,
5068
+ instructionDelivery: bundle.execution.instructionDelivery,
5069
+ limits: benchmarkTask.limits,
4598
5070
  container,
4599
5071
  model: {
4600
5072
  policy: "single",
@@ -4606,16 +5078,14 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
4606
5078
  },
4607
5079
  routes
4608
5080
  },
4609
- grader: task.grader,
4610
5081
  launch: {
4611
5082
  executable: baseLaunch.executable,
4612
5083
  args: baseLaunch.args,
4613
5084
  env: publicEnv,
4614
5085
  cwd: bundle.execution.cwd
4615
5086
  },
4616
- ...bundle.knowledge ? { knowledgeManifestDigest: bundle.knowledge.manifest.sha256 } : {},
5087
+ ...bundle.knowledge ? { knowledgeManifestDigest: bundle.knowledge.snapshot.digest } : {},
4617
5088
  memory,
4618
- limits: task.limits,
4619
5089
  network: { mode: "disabled" }
4620
5090
  };
4621
5091
  agentCandidateExecutionPlanMaterialSchema.parse(executionMaterial);
@@ -4625,7 +5095,6 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
4625
5095
  throw new Error("execution plan canonical serializers disagree");
4626
5096
  }
4627
5097
  const executionPlan = agentCandidateExecutionPlanEvidenceSchema2.parse({
4628
- schemaVersion: 1,
4629
5098
  kind: "agent-candidate-execution-plan",
4630
5099
  digest: executionDigest,
4631
5100
  material: executionMaterial,
@@ -4634,11 +5103,24 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
4634
5103
  const entrypoint = candidateEntrypointReceipt(candidate);
4635
5104
  const materializationReceipt = canonicalCandidateDocument(
4636
5105
  {
4637
- schemaVersion: 1,
4638
5106
  kind: "agent-candidate-materialization",
4639
5107
  digestAlgorithm: "rfc8785-sha256",
4640
5108
  bundleDigest: bundle.digest,
4641
- profilePlan: profileApplication.profilePlan,
5109
+ benchmark: {
5110
+ suite: {
5111
+ digest: task.benchmarkSuite.digest,
5112
+ material: embeddedCandidateArtifact(
5113
+ canonicalCandidateBytes(omitTopLevelDigest(task.benchmarkSuite))
5114
+ )
5115
+ },
5116
+ task: {
5117
+ digest: benchmarkTask.digest,
5118
+ material: embeddedCandidateArtifact(
5119
+ canonicalCandidateBytes(omitTopLevelDigest(benchmarkTask))
5120
+ )
5121
+ }
5122
+ },
5123
+ profileActivation,
4642
5124
  executionPlan,
4643
5125
  ...bundle.execution.workspace ? { candidateWorkspace: bundle.execution.workspace } : {},
4644
5126
  codeKind: bundle.code.kind,
@@ -4647,12 +5129,12 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
4647
5129
  harnessVersion: bundle.execution.harnessVersion,
4648
5130
  container,
4649
5131
  resolvedModel,
4650
- ...bundle.knowledge ? { knowledgeManifestDigest: bundle.knowledge.manifest.sha256 } : {},
5132
+ ...bundle.knowledge ? { knowledgeManifestDigest: bundle.knowledge.snapshot.digest } : {},
4651
5133
  ...entrypoint ? { entrypoint } : {}
4652
5134
  }
4653
5135
  );
4654
5136
  agentCandidateMaterializationReceiptSchema2.parse(materializationReceipt.value);
4655
- const traceRunId = `${task.executionId}:attempt-${task.attempt.number}:${canonicalCandidateDigest({ preparationId }).slice(7, 23)}`;
5137
+ const traceRunId = `${task.executionId}:attempt-${attempt.number}:${canonicalCandidateDigest({ preparationId }).slice(7, 23)}`;
4656
5138
  const traceTags = {
4657
5139
  [CANDIDATE_TRACE_TAGS.executionId]: task.executionId,
4658
5140
  [CANDIDATE_TRACE_TAGS.bundleDigest]: bundle.digest,
@@ -4670,16 +5152,19 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
4670
5152
  return createPreparedCandidateExecution({
4671
5153
  ports,
4672
5154
  bundle,
5155
+ benchmarkSuite: task.benchmarkSuite,
5156
+ benchmarkTask,
4673
5157
  executionId: task.executionId,
4674
5158
  roots: {
4675
5159
  execution: { ...task.executionRoots },
4676
5160
  staging: { ...task.stagingRoots }
4677
5161
  },
4678
5162
  profilePlan: {
4679
- value: profileApplication.profilePlan,
5163
+ value: profileApplication.profileActivation.profilePlan,
4680
5164
  bytes: profilePlanBytes,
4681
5165
  written: [...profileApplication.application.mountPaths]
4682
5166
  },
5167
+ profileActivation,
4683
5168
  executionPlan: { value: executionPlan, bytes: executionBytes },
4684
5169
  materializationReceipt,
4685
5170
  launch: {
@@ -4710,7 +5195,7 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
4710
5195
  ...candidateExecutorFiles ? { candidateFiles: candidateExecutorFiles } : {},
4711
5196
  profileFiles: exactProfileExecutorFiles(
4712
5197
  profileWorkspacePlan.files,
4713
- profileApplication.profilePlan.material.files
5198
+ profileApplication.profileActivation.profilePlan.material.files
4714
5199
  )
4715
5200
  },
4716
5201
  ...preparedMemory.accessDigest && preparedMemory.value.mode === "isolated" ? {
@@ -4795,34 +5280,54 @@ function assertSameVerificationPorts(verified, execution) {
4795
5280
  }
4796
5281
  }
4797
5282
  function assertTaskInput(task, delivery) {
5283
+ const benchmarkTask = agentCandidateBenchmarkTaskSchema2.parse(task.task);
5284
+ const benchmarkSuite = agentCandidateBenchmarkSuiteSchema2.parse(task.benchmarkSuite);
5285
+ const runCell = agentCandidateRunCellSchema.parse(task.runCell);
4798
5286
  const requiredStrings = [
4799
5287
  ["executionId", task.executionId],
4800
- ["benchmark", task.benchmark],
4801
- ["benchmarkVersion", task.benchmarkVersion],
4802
- ["taskId", task.taskId],
4803
- ["repository identity", task.repository.identity],
4804
- ["repository root identity", task.repository.rootIdentity]
5288
+ ["benchmark", benchmarkTask.benchmark.name],
5289
+ ["benchmarkVersion", benchmarkTask.benchmark.version],
5290
+ ["taskId", benchmarkTask.scenario.id]
4805
5291
  ];
5292
+ if (benchmarkTask.outcome.kind === "workspace" && !benchmarkTask.repository) {
5293
+ throw new Error("workspace task outcome requires repository identity");
5294
+ }
5295
+ if (benchmarkTask.repository) {
5296
+ requiredStrings.push(
5297
+ ["repository identity", benchmarkTask.repository.identity],
5298
+ ["repository root identity", benchmarkTask.repository.rootIdentity]
5299
+ );
5300
+ }
4806
5301
  for (const [name, value] of requiredStrings) {
4807
5302
  if (!value.trim()) throw new Error(`${name} must be non-empty`);
4808
5303
  }
4809
5304
  if (!/^[A-Za-z0-9._:-]{1,200}$/.test(task.executionId)) {
4810
5305
  throw new Error("executionId must be a stable filesystem-neutral identifier");
4811
5306
  }
4812
- if (!task.instruction || !isWellFormedUnicode(task.instruction)) {
5307
+ if (!benchmarkTask.instruction || !isWellFormedUnicode(benchmarkTask.instruction)) {
4813
5308
  throw new Error("task instruction must be non-empty well-formed Unicode");
4814
5309
  }
4815
- sha256DigestSchema.parse(task.splitDigest);
4816
- agentCandidateWorkspaceSnapshotEvidenceSchema2.parse(task.workspace);
4817
- agentCandidateExecutionLimitsSchema.parse(task.limits);
4818
- if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(task.repository.baseCommit)) {
4819
- throw new Error("task repository base commit is not a full Git object id");
5310
+ if (canonicalCandidateDigest(omitTopLevelDigest(benchmarkTask)) !== benchmarkTask.digest || canonicalCandidateDigest(omitTopLevelDigest(benchmarkSuite)) !== benchmarkSuite.digest || canonicalCandidateDigest(omitTopLevelDigest(runCell)) !== runCell.digest) {
5311
+ throw new Error("candidate experiment cell contains an invalid content digest");
4820
5312
  }
4821
- if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(task.repository.baseTree)) {
4822
- throw new Error("task repository base tree is not a full Git object id");
5313
+ const cellIndex = runCell.taskIndex * benchmarkSuite.reps + runCell.repetition;
5314
+ if (runCell.suiteDigest !== benchmarkSuite.digest || runCell.taskDigest !== benchmarkTask.digest || benchmarkSuite.taskDigests[runCell.taskIndex] !== benchmarkTask.digest || runCell.repetition >= benchmarkSuite.reps || benchmarkSuite.seeds[cellIndex] !== runCell.seed || runCell.attempt > benchmarkTask.attempt.maxAttempts) {
5315
+ throw new Error("candidate experiment cell does not match its signed suite and task");
4823
5316
  }
4824
- if (task.repository.baseCommit.length !== task.repository.baseTree.length) {
4825
- throw new Error("task repository Git object formats disagree");
5317
+ sha256DigestSchema.parse(benchmarkTask.benchmark.splitDigest);
5318
+ agentCandidateTaskOutcomeSpecSchema.parse(benchmarkTask.outcome);
5319
+ agentCandidateWorkspaceSnapshotEvidenceSchema3.parse(benchmarkTask.workspace);
5320
+ agentCandidateExecutionLimitsSchema.parse(benchmarkTask.limits);
5321
+ if (benchmarkTask.repository) {
5322
+ if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(benchmarkTask.repository.baseCommit)) {
5323
+ throw new Error("task repository base commit is not a full Git object id");
5324
+ }
5325
+ if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(benchmarkTask.repository.baseTree)) {
5326
+ throw new Error("task repository base tree is not a full Git object id");
5327
+ }
5328
+ if (benchmarkTask.repository.baseCommit.length !== benchmarkTask.repository.baseTree.length) {
5329
+ throw new Error("task repository Git object formats disagree");
5330
+ }
4826
5331
  }
4827
5332
  for (const [name, root] of [
4828
5333
  ["execution task root", task.executionRoots.taskRoot],
@@ -4832,34 +5337,36 @@ function assertTaskInput(task, delivery) {
4832
5337
  ["staging profile root", task.stagingRoots.profileRoot]
4833
5338
  ]) {
4834
5339
  if (root === void 0) continue;
4835
- const canonical = name.startsWith("execution") ? posix.isAbsolute(root) && posix.normalize(root) === root : isAbsolute(root) && resolveHostPath(root) === root;
5340
+ const canonical = name.startsWith("execution") ? posix2.isAbsolute(root) && posix2.normalize(root) === root : isAbsolute(root) && resolveHostPath(root) === root;
4836
5341
  if (!canonical) throw new Error(`${name} must be a canonical absolute path`);
4837
5342
  }
4838
- 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) {
5343
+ if (!Number.isInteger(runCell.attempt) || !Number.isInteger(benchmarkTask.attempt.maxAttempts) || runCell.attempt < 1 || runCell.attempt > benchmarkTask.attempt.maxAttempts || benchmarkTask.attempt.retryPolicy === "none" && benchmarkTask.attempt.maxAttempts !== 1) {
4839
5344
  throw new Error("task attempt policy is invalid");
4840
5345
  }
4841
- const limits = task.limits;
5346
+ const limits = benchmarkTask.limits;
4842
5347
  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) {
4843
5348
  throw new Error("task execution limits are invalid");
4844
5349
  }
4845
5350
  usdToNanos(limits.maxCostUsd, "task maxCostUsd");
4846
- if (!task.model.requested.trim()) throw new Error("evaluator model request must be non-empty");
4847
- if (!task.grader.name.trim() || !task.grader.version.trim()) {
5351
+ if (!benchmarkTask.model.requested.trim()) {
5352
+ throw new Error("evaluator model request must be non-empty");
5353
+ }
5354
+ if (!benchmarkTask.grader.name.trim() || !benchmarkTask.grader.version.trim()) {
4848
5355
  throw new Error("evaluator benchmark grader identity must be non-empty");
4849
5356
  }
4850
- if (!Number.isInteger(task.grader.artifact.byteLength) || task.grader.artifact.byteLength <= 0) {
5357
+ if (!Number.isInteger(benchmarkTask.grader.artifact.byteLength) || benchmarkTask.grader.artifact.byteLength <= 0) {
4851
5358
  throw new Error("evaluator benchmark grader artifact must be non-empty");
4852
5359
  }
4853
- sha256DigestSchema.parse(task.grader.artifact.sha256);
4854
- if (task.evaluatorTaskContainer) {
4855
- if (task.evaluatorTaskContainer.source !== "evaluator-task-container" || !task.evaluatorTaskContainer.image.trim() || !task.evaluatorTaskContainer.platform.os.trim() || !task.evaluatorTaskContainer.platform.architecture.trim()) {
5360
+ sha256DigestSchema.parse(benchmarkTask.grader.artifact.sha256);
5361
+ if (benchmarkTask.evaluatorTaskContainer) {
5362
+ if (benchmarkTask.evaluatorTaskContainer.source !== "evaluator-task-container" || !benchmarkTask.evaluatorTaskContainer.image.trim() || !benchmarkTask.evaluatorTaskContainer.platform.os.trim() || !benchmarkTask.evaluatorTaskContainer.platform.architecture.trim()) {
4856
5363
  throw new Error("evaluator task container evidence is incomplete");
4857
5364
  }
4858
- sha256DigestSchema.parse(task.evaluatorTaskContainer.indexDigest);
4859
- sha256DigestSchema.parse(task.evaluatorTaskContainer.manifestDigest);
5365
+ sha256DigestSchema.parse(benchmarkTask.evaluatorTaskContainer.indexDigest);
5366
+ sha256DigestSchema.parse(benchmarkTask.evaluatorTaskContainer.manifestDigest);
4860
5367
  agentCandidateContainerSchema.parse({
4861
- image: task.evaluatorTaskContainer.image,
4862
- indexDigest: task.evaluatorTaskContainer.indexDigest
5368
+ image: benchmarkTask.evaluatorTaskContainer.image,
5369
+ indexDigest: benchmarkTask.evaluatorTaskContainer.indexDigest
4863
5370
  });
4864
5371
  }
4865
5372
  if (delivery.kind === "utf8-file") {
@@ -4869,8 +5376,8 @@ function assertTaskInput(task, delivery) {
4869
5376
  }
4870
5377
  }
4871
5378
  function executionPathsOverlap(left, right) {
4872
- const a = posix.normalize(left);
4873
- const b = posix.normalize(right);
5379
+ const a = posix2.normalize(left);
5380
+ const b = posix2.normalize(right);
4874
5381
  return a === b || b.startsWith(a === "/" ? "/" : `${a}/`) || a.startsWith(b === "/" ? "/" : `${b}/`);
4875
5382
  }
4876
5383
  function assertDisjointHostStagingRoots(task) {
@@ -4902,51 +5409,45 @@ async function assertEmptyDirectory(path) {
4902
5409
  throw new Error("profile staging root must be empty before materialization");
4903
5410
  }
4904
5411
  }
4905
- function materializerHarness(harness) {
4906
- if (!MATERIALIZER_HARNESSES.has(harness)) {
4907
- throw new Error(
4908
- `sealed candidate profile materialization is unsupported for harness ${harness}`
4909
- );
4910
- }
4911
- return harness;
4912
- }
4913
5412
  async function resolveContainer(candidate, task, ports) {
4914
5413
  const environment = candidate.bundle.execution.environment;
5414
+ const evaluatorTaskContainer = task.task.evaluatorTaskContainer;
4915
5415
  const pinned = environment.kind === "pinned-container" ? environment.container : void 0;
4916
- if (environment.kind === "evaluator-task-container" && !task.evaluatorTaskContainer) {
5416
+ if (environment.kind === "evaluator-task-container" && !evaluatorTaskContainer) {
4917
5417
  throw new Error("evaluator-task-container candidate requires an evaluator-owned task image");
4918
5418
  }
4919
- if (environment.kind === "pinned-container" && task.evaluatorTaskContainer) {
5419
+ if (environment.kind === "pinned-container" && evaluatorTaskContainer) {
4920
5420
  throw new Error("pinned candidate containers cannot be replaced by a task image");
4921
5421
  }
4922
5422
  const resolved = await ports.containers.resolve({
4923
5423
  candidate: pinned,
4924
- evaluatorTaskContainer: task.evaluatorTaskContainer
5424
+ evaluatorTaskContainer
4925
5425
  });
4926
5426
  if (resolved.source !== environment.kind) throw new Error("resolved container source drifted");
4927
5427
  if (pinned && (resolved.image !== pinned.image || resolved.indexDigest !== pinned.indexDigest)) {
4928
5428
  throw new Error("resolved pinned container does not match the candidate image index");
4929
5429
  }
4930
- if (task.evaluatorTaskContainer && JSON.stringify(resolved) !== JSON.stringify(task.evaluatorTaskContainer)) {
5430
+ if (evaluatorTaskContainer && canonicalCandidateDigest(resolved) !== canonicalCandidateDigest(evaluatorTaskContainer)) {
4931
5431
  throw new Error("resolved task container does not match evaluator-owned image evidence");
4932
5432
  }
4933
5433
  return resolved;
4934
5434
  }
4935
5435
  async function resolveModel(candidate, task, ports) {
4936
5436
  const hints = candidate.bundle.profile.model;
4937
- if (hints?.default !== void 0 && hints.default !== task.model.requested) {
5437
+ const expected = task.task.model;
5438
+ if (hints?.default !== void 0 && hints.default !== expected.requested) {
4938
5439
  throw new Error("candidate model preference conflicts with the evaluator-owned model");
4939
5440
  }
4940
- if (hints?.reasoningEffort !== void 0 && hints.reasoningEffort !== task.model.reasoningEffort) {
5441
+ if (hints?.reasoningEffort !== void 0 && hints.reasoningEffort !== expected.reasoningEffort) {
4941
5442
  throw new Error("candidate reasoning effort conflicts with the evaluator-owned effort");
4942
5443
  }
4943
5444
  const resolved = await ports.models.resolve({
4944
- requested: task.model.requested,
5445
+ requested: expected.requested,
4945
5446
  harness: candidate.bundle.execution.harness,
4946
- reasoningEffort: task.model.reasoningEffort
5447
+ reasoningEffort: expected.reasoningEffort
4947
5448
  });
4948
- if (resolved.requested !== task.model.requested || resolved.reasoningEffort !== task.model.reasoningEffort) {
4949
- throw new Error("model resolver drifted from the evaluator-owned request");
5449
+ if (canonicalCandidateDigest(resolved) !== canonicalCandidateDigest(expected)) {
5450
+ throw new Error("model resolver drifted from the signed benchmark model");
4950
5451
  }
4951
5452
  return resolved;
4952
5453
  }
@@ -4955,7 +5456,7 @@ async function prepareMemory(candidate, task, ports, preparationId, expiresAtMs,
4955
5456
  if (policy.mode === "disabled") return { value: { mode: "disabled" } };
4956
5457
  const seed = policy.seed ? await verifiedArtifactBytes(candidate, policy.seed) : void 0;
4957
5458
  const executionSegment = canonicalCandidateDigest({ executionId: task.executionId }).slice(7);
4958
- const taskSegment = canonicalCandidateDigest({ taskId: task.taskId }).slice(7);
5459
+ const taskSegment = canonicalCandidateDigest({ taskDigest: task.task.digest }).slice(7);
4959
5460
  const preparationSegment = canonicalCandidateDigest({ preparationId }).slice(7, 23);
4960
5461
  const effectiveNamespace = `candidate/${candidate.bundle.digest.slice(7, 23)}/${executionSegment}/${taskSegment}/${preparationSegment}`;
4961
5462
  const reset = await withinCandidateCleanupDeadline(
@@ -5022,7 +5523,7 @@ function buildLaunch(candidate, task, profileFlags) {
5022
5523
  }
5023
5524
  const candidateRoot = task.executionRoots.candidateRoot;
5024
5525
  if (!candidateRoot) throw new Error("candidate entrypoint requires a container candidate root");
5025
- const entrypoint = posix.join(candidateRoot, launch.entrypoint);
5526
+ const entrypoint = posix2.join(candidateRoot, launch.entrypoint);
5026
5527
  const candidateArgs = launch.args ?? [];
5027
5528
  if (launch.interpreter) {
5028
5529
  return {
@@ -5072,7 +5573,7 @@ function candidateEntrypointReceipt(candidate) {
5072
5573
  function absoluteExecutionCwd(cwd, roots) {
5073
5574
  const root = cwd.workspace === "task" ? roots.taskRoot : roots.candidateRoot;
5074
5575
  if (!root) throw new Error("candidate cwd is missing its execution workspace root");
5075
- const absolute = cwd.path === "." ? root : posix.join(root, cwd.path);
5576
+ const absolute = cwd.path === "." ? root : posix2.join(root, cwd.path);
5076
5577
  if (absolute !== root && !absolute.startsWith(`${root}/`)) {
5077
5578
  throw new Error("candidate cwd escapes its execution workspace");
5078
5579
  }
@@ -5119,7 +5620,7 @@ function exactProfileExecutorFiles(sourceFiles, expectedFiles) {
5119
5620
  const source = byPath.get(expected.relPath);
5120
5621
  const mode = source?.mode ?? 420;
5121
5622
  const bytes = Buffer.from(source?.content ?? "", "utf8");
5122
- if (!source || mode !== 420 && mode !== 493 || mode !== expected.mode || sha256Bytes(bytes) !== expected.contentSha256) {
5623
+ if (!source || !Number.isInteger(mode) || mode < 0 || mode > 511 || mode !== expected.mode || sha256Bytes(bytes) !== expected.contentSha256) {
5123
5624
  throw new Error("profile source files do not match the signed profile plan");
5124
5625
  }
5125
5626
  return { path: expected.relPath, mode, bytes: Uint8Array.from(bytes) };
@@ -5148,20 +5649,19 @@ export {
5148
5649
  canonicalCandidateDigest,
5149
5650
  immutableCandidateValue,
5150
5651
  canonicalCandidateDocument,
5652
+ verifyCanonicalCandidateDocument,
5151
5653
  embeddedCandidateArtifact,
5152
5654
  omitTopLevelDigest,
5153
5655
  deepFreezeCandidate,
5154
- sealAgentCandidateBundle,
5656
+ candidateMaterializerHarness,
5657
+ createAgentCandidateProfileActivation,
5658
+ parseAgentCandidateProfileActivation,
5155
5659
  freezeGenericAgentCandidateProfile,
5156
- assertCandidateProfileBinding,
5157
5660
  parseExactAgentProfile,
5158
5661
  parseExactAgentProfileDiff,
5159
5662
  applyExactAgentProfileDiff,
5160
5663
  parseExactCandidateProfile,
5161
- CLAIM_FORMAT_VERSION,
5162
- PENDING_FORMAT_VERSION,
5163
- TERMINAL_FORMAT_VERSION,
5164
- PHASE_FORMAT_VERSION,
5664
+ agentCandidateProfileAsAgentProfile,
5165
5665
  assertExactObjectKeys,
5166
5666
  terminalRecord,
5167
5667
  recoveredTerminalRecord,
@@ -5176,9 +5676,11 @@ export {
5176
5676
  candidateCleanupTimeout,
5177
5677
  candidateCleanupDeadline,
5178
5678
  withinCandidateCleanupDeadline,
5679
+ readVerifiedArtifact,
5179
5680
  verifyBytes,
5180
5681
  verifyMaterializedWorkspace,
5181
5682
  captureMaterializedWorkspace,
5683
+ candidateWorkspaceManifest,
5182
5684
  assertNoGitIndirection,
5183
5685
  readCandidateGitTreeFiles,
5184
5686
  runCandidateGit,
@@ -5192,12 +5694,17 @@ export {
5192
5694
  candidateClaimFileInternals,
5193
5695
  sealAgentCandidateModelSettlement,
5194
5696
  usdToNanos,
5195
- sealAgentCandidateExecutorFinalCapture,
5697
+ sealAgentCandidateExecutorStopAcknowledgement,
5196
5698
  persistCandidateOutputArtifact,
5197
5699
  persistCandidateModelSettlementEvidence,
5198
5700
  RecoveryAgentCandidateTraceStore,
5199
5701
  executePreparedAgentCandidate,
5702
+ AGENT_CANDIDATE_EXECUTION_SUPPORT,
5200
5703
  verifyAgentCandidateBundle,
5704
+ verifiedResourceTextByDigest,
5705
+ CANDIDATE_KNOWLEDGE_ROOT_ENV,
5706
+ CANDIDATE_KNOWLEDGE_RETRIEVAL_CONFIG_ENV,
5707
+ candidateKnowledgeExecutionPaths,
5201
5708
  prepareAgentCandidateExecution
5202
5709
  };
5203
- //# sourceMappingURL=chunk-37V4KQDC.js.map
5710
+ //# sourceMappingURL=chunk-WTZ37EQY.js.map