agent-hitch 0.2.7 → 0.2.8

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 (287) hide show
  1. package/README.md +16 -2
  2. package/README.zh-CN.md +14 -2
  3. package/dist/bin/hitch.js +25 -3
  4. package/dist/bin/hitch.js.map +1 -1
  5. package/dist/scripts/canary-benchmark.js +54 -0
  6. package/dist/scripts/canary-benchmark.js.map +1 -0
  7. package/dist/scripts/canary-eval-scheduler-throughput.js +47 -0
  8. package/dist/scripts/canary-eval-scheduler-throughput.js.map +1 -0
  9. package/dist/scripts/check-architecture.js +3 -2
  10. package/dist/scripts/check-architecture.js.map +1 -1
  11. package/dist/src/adapters/catalog.js +2 -1
  12. package/dist/src/adapters/catalog.js.map +1 -1
  13. package/dist/src/adapters/providers/codex-auth.js +29 -0
  14. package/dist/src/adapters/providers/codex-auth.js.map +1 -0
  15. package/dist/src/adapters/providers/codex.js +23 -6
  16. package/dist/src/adapters/providers/codex.js.map +1 -1
  17. package/dist/src/adapters/providers/model-call.js +26 -0
  18. package/dist/src/adapters/providers/model-call.js.map +1 -0
  19. package/dist/src/artifacts/index.js +1 -1
  20. package/dist/src/artifacts/index.js.map +1 -1
  21. package/dist/src/artifacts/preparer.js +7 -2
  22. package/dist/src/artifacts/preparer.js.map +1 -1
  23. package/dist/src/backends/harbor/agent-budget.js +31 -0
  24. package/dist/src/backends/harbor/agent-budget.js.map +1 -0
  25. package/dist/src/backends/harbor/backend.js +6 -4
  26. package/dist/src/backends/harbor/backend.js.map +1 -1
  27. package/dist/src/backends/harbor/index.js +1 -0
  28. package/dist/src/backends/harbor/index.js.map +1 -1
  29. package/dist/src/backends/harbor/regrade.js +77 -0
  30. package/dist/src/backends/harbor/regrade.js.map +1 -0
  31. package/dist/src/backends/index.js +1 -0
  32. package/dist/src/backends/index.js.map +1 -1
  33. package/dist/src/benchmarks/index.js +3 -0
  34. package/dist/src/benchmarks/index.js.map +1 -0
  35. package/dist/src/benchmarks/loader.js +271 -0
  36. package/dist/src/benchmarks/loader.js.map +1 -0
  37. package/dist/src/benchmarks/metrics.js +16 -0
  38. package/dist/src/benchmarks/metrics.js.map +1 -0
  39. package/dist/src/benchmarks/toml.js +13 -0
  40. package/dist/src/benchmarks/toml.js.map +1 -0
  41. package/dist/src/benchmarks/validation.js +242 -0
  42. package/dist/src/benchmarks/validation.js.map +1 -0
  43. package/dist/src/cli/arguments.js +6 -4
  44. package/dist/src/cli/arguments.js.map +1 -1
  45. package/dist/src/cli/commands/benchmark.js +22 -0
  46. package/dist/src/cli/commands/benchmark.js.map +1 -0
  47. package/dist/src/cli/commands/capabilities.js +18 -0
  48. package/dist/src/cli/commands/capabilities.js.map +1 -0
  49. package/dist/src/cli/commands/eval.js +15 -3
  50. package/dist/src/cli/commands/eval.js.map +1 -1
  51. package/dist/src/cli/commands/run.js +37 -15
  52. package/dist/src/cli/commands/run.js.map +1 -1
  53. package/dist/src/cli/commands/trajectory.js +96 -5
  54. package/dist/src/cli/commands/trajectory.js.map +1 -1
  55. package/dist/src/cli/commands/verifier.js +36 -0
  56. package/dist/src/cli/commands/verifier.js.map +1 -0
  57. package/dist/src/cli/main.js +6 -0
  58. package/dist/src/cli/main.js.map +1 -1
  59. package/dist/src/cli/output.js +14 -2
  60. package/dist/src/cli/output.js.map +1 -1
  61. package/dist/src/control-plane/eval-control-work.js +5 -0
  62. package/dist/src/control-plane/eval-control-work.js.map +1 -1
  63. package/dist/src/control-plane/eval-scheduler.js +4 -1
  64. package/dist/src/control-plane/eval-scheduler.js.map +1 -1
  65. package/dist/src/control-plane/index.js +1 -1
  66. package/dist/src/control-plane/index.js.map +1 -1
  67. package/dist/src/control-plane/remote-result-transport.js +3 -0
  68. package/dist/src/control-plane/remote-result-transport.js.map +1 -1
  69. package/dist/src/control-plane/remote-work-coordinator.js +1 -0
  70. package/dist/src/control-plane/remote-work-coordinator.js.map +1 -1
  71. package/dist/src/control-plane/remote-work-item.js +62 -0
  72. package/dist/src/control-plane/remote-work-item.js.map +1 -0
  73. package/dist/src/control-plane/remote-work-recovery.js +44 -5
  74. package/dist/src/control-plane/remote-work-recovery.js.map +1 -1
  75. package/dist/src/control-plane/remote-worker-protocol.js +2 -23
  76. package/dist/src/control-plane/remote-worker-protocol.js.map +1 -1
  77. package/dist/src/control-plane/rerun-scheduler.js +51 -14
  78. package/dist/src/control-plane/rerun-scheduler.js.map +1 -1
  79. package/dist/src/control-plane/rerun-submission.js +10 -4
  80. package/dist/src/control-plane/rerun-submission.js.map +1 -1
  81. package/dist/src/control-plane/work-admission.js +2 -0
  82. package/dist/src/control-plane/work-admission.js.map +1 -1
  83. package/dist/src/control-plane/work-dispatcher.js +9 -1
  84. package/dist/src/control-plane/work-dispatcher.js.map +1 -1
  85. package/dist/src/controller-runtime/hash.js +7 -2
  86. package/dist/src/controller-runtime/hash.js.map +1 -1
  87. package/dist/src/daemon/auth.js +5 -0
  88. package/dist/src/daemon/auth.js.map +1 -1
  89. package/dist/src/domain/benchmarks.js +2 -0
  90. package/dist/src/domain/benchmarks.js.map +1 -0
  91. package/dist/src/domain/index.js +4 -0
  92. package/dist/src/domain/index.js.map +1 -1
  93. package/dist/src/domain/runs.js.map +1 -1
  94. package/dist/src/domain/validation.js +11 -4
  95. package/dist/src/domain/validation.js.map +1 -1
  96. package/dist/src/domain/verifier-evidence-validation.js +214 -0
  97. package/dist/src/domain/verifier-evidence-validation.js.map +1 -0
  98. package/dist/src/domain/verifier-evidence.js +3 -0
  99. package/dist/src/domain/verifier-evidence.js.map +1 -0
  100. package/dist/src/domain/verifier-score-contract.js +232 -0
  101. package/dist/src/domain/verifier-score-contract.js.map +1 -0
  102. package/dist/src/evals/benchmark-adapter-manifest.js +219 -0
  103. package/dist/src/evals/benchmark-adapter-manifest.js.map +1 -0
  104. package/dist/src/evals/benchmark-candidate.js +36 -0
  105. package/dist/src/evals/benchmark-candidate.js.map +1 -0
  106. package/dist/src/evals/benchmark-run.js +166 -0
  107. package/dist/src/evals/benchmark-run.js.map +1 -0
  108. package/dist/src/evals/collect-only-rerun.js +2 -1
  109. package/dist/src/evals/collect-only-rerun.js.map +1 -1
  110. package/dist/src/evals/directory.js +1 -1
  111. package/dist/src/evals/directory.js.map +1 -1
  112. package/dist/src/evals/duration-estimator.js +126 -0
  113. package/dist/src/evals/duration-estimator.js.map +1 -0
  114. package/dist/src/evals/eval-lifecycle-events.js +13 -0
  115. package/dist/src/evals/eval-lifecycle-events.js.map +1 -1
  116. package/dist/src/evals/eval-logical-plan.js +51 -0
  117. package/dist/src/evals/eval-logical-plan.js.map +1 -0
  118. package/dist/src/evals/eval-result-builder.js +81 -0
  119. package/dist/src/evals/eval-result-builder.js.map +1 -0
  120. package/dist/src/evals/evolution-baseline.js +191 -0
  121. package/dist/src/evals/evolution-baseline.js.map +1 -0
  122. package/dist/src/evals/execution-plan.js +39 -3
  123. package/dist/src/evals/execution-plan.js.map +1 -1
  124. package/dist/src/evals/failure-classifier.js +61 -0
  125. package/dist/src/evals/failure-classifier.js.map +1 -0
  126. package/dist/src/evals/harbor-artifact-builder.js +6 -2
  127. package/dist/src/evals/harbor-artifact-builder.js.map +1 -1
  128. package/dist/src/evals/harbor-bridge-error.js +41 -1
  129. package/dist/src/evals/harbor-bridge-error.js.map +1 -1
  130. package/dist/src/evals/harbor-node-runtime.js +146 -0
  131. package/dist/src/evals/harbor-node-runtime.js.map +1 -0
  132. package/dist/src/evals/index.js +15 -0
  133. package/dist/src/evals/index.js.map +1 -1
  134. package/dist/src/evals/infrastructure-retry.js +109 -22
  135. package/dist/src/evals/infrastructure-retry.js.map +1 -1
  136. package/dist/src/evals/native-phase-evidence.js +440 -0
  137. package/dist/src/evals/native-phase-evidence.js.map +1 -0
  138. package/dist/src/evals/physical-retry-work.js +31 -0
  139. package/dist/src/evals/physical-retry-work.js.map +1 -0
  140. package/dist/src/evals/planned-execution-support.js +22 -10
  141. package/dist/src/evals/planned-execution-support.js.map +1 -1
  142. package/dist/src/evals/planned-execution.js +120 -112
  143. package/dist/src/evals/planned-execution.js.map +1 -1
  144. package/dist/src/evals/planned-progress-publisher.js +62 -0
  145. package/dist/src/evals/planned-progress-publisher.js.map +1 -0
  146. package/dist/src/evals/planned-retry-execution.js +174 -0
  147. package/dist/src/evals/planned-retry-execution.js.map +1 -0
  148. package/dist/src/evals/planned-retry-lifecycle.js +4 -2
  149. package/dist/src/evals/planned-retry-lifecycle.js.map +1 -1
  150. package/dist/src/evals/preparation-rerun.js +225 -0
  151. package/dist/src/evals/preparation-rerun.js.map +1 -0
  152. package/dist/src/evals/progress.js +48 -8
  153. package/dist/src/evals/progress.js.map +1 -1
  154. package/dist/src/evals/recovery.js +54 -4
  155. package/dist/src/evals/recovery.js.map +1 -1
  156. package/dist/src/evals/regrade-evidence.js +77 -0
  157. package/dist/src/evals/regrade-evidence.js.map +1 -0
  158. package/dist/src/evals/remote-infrastructure-retry.js +84 -18
  159. package/dist/src/evals/remote-infrastructure-retry.js.map +1 -1
  160. package/dist/src/evals/request.js +21 -3
  161. package/dist/src/evals/request.js.map +1 -1
  162. package/dist/src/evals/rerun-inputs.js +19 -0
  163. package/dist/src/evals/rerun-inputs.js.map +1 -1
  164. package/dist/src/evals/rerun-types.js +2 -6
  165. package/dist/src/evals/rerun-types.js.map +1 -1
  166. package/dist/src/evals/rerun.js +27 -20
  167. package/dist/src/evals/rerun.js.map +1 -1
  168. package/dist/src/evals/result-helpers.js +13 -0
  169. package/dist/src/evals/result-helpers.js.map +1 -1
  170. package/dist/src/evals/retry-backoff.js +20 -0
  171. package/dist/src/evals/retry-backoff.js.map +1 -0
  172. package/dist/src/evals/retry-state.js +195 -0
  173. package/dist/src/evals/retry-state.js.map +1 -0
  174. package/dist/src/evals/scheduler-metrics.js +95 -0
  175. package/dist/src/evals/scheduler-metrics.js.map +1 -0
  176. package/dist/src/evals/scheduler-trace-replay.js +107 -0
  177. package/dist/src/evals/scheduler-trace-replay.js.map +1 -0
  178. package/dist/src/evals/service.js +87 -138
  179. package/dist/src/evals/service.js.map +1 -1
  180. package/dist/src/evals/trial-import.js +47 -50
  181. package/dist/src/evals/trial-import.js.map +1 -1
  182. package/dist/src/evals/trial-publication-recovery.js +45 -5
  183. package/dist/src/evals/trial-publication-recovery.js.map +1 -1
  184. package/dist/src/evals/trial-reference-validation.js +49 -0
  185. package/dist/src/evals/trial-reference-validation.js.map +1 -0
  186. package/dist/src/evals/verifier-artifacts.js +317 -0
  187. package/dist/src/evals/verifier-artifacts.js.map +1 -0
  188. package/dist/src/evals/verifier-eligibility.js +25 -0
  189. package/dist/src/evals/verifier-eligibility.js.map +1 -0
  190. package/dist/src/evals/verifier-only-rerun.js +210 -0
  191. package/dist/src/evals/verifier-only-rerun.js.map +1 -0
  192. package/dist/src/evals/verifier-runtime.js +61 -0
  193. package/dist/src/evals/verifier-runtime.js.map +1 -0
  194. package/dist/src/evals/verifier-score-artifacts.js +119 -0
  195. package/dist/src/evals/verifier-score-artifacts.js.map +1 -0
  196. package/dist/src/foundation/contained-file.js +85 -0
  197. package/dist/src/foundation/contained-file.js.map +1 -0
  198. package/dist/src/foundation/credential-redaction.js +26 -1
  199. package/dist/src/foundation/credential-redaction.js.map +1 -1
  200. package/dist/src/foundation/fs.js +2 -1
  201. package/dist/src/foundation/fs.js.map +1 -1
  202. package/dist/src/foundation/index.js +2 -1
  203. package/dist/src/foundation/index.js.map +1 -1
  204. package/dist/src/runs/adapter-process.js +12 -0
  205. package/dist/src/runs/adapter-process.js.map +1 -0
  206. package/dist/src/runs/executor.js +24 -30
  207. package/dist/src/runs/executor.js.map +1 -1
  208. package/dist/src/runs/finalizer.js +17 -0
  209. package/dist/src/runs/finalizer.js.map +1 -1
  210. package/dist/src/runs/index.js +5 -0
  211. package/dist/src/runs/index.js.map +1 -1
  212. package/dist/src/runs/phase-bundle.js +86 -0
  213. package/dist/src/runs/phase-bundle.js.map +1 -0
  214. package/dist/src/runs/phase-cancellation.js +107 -0
  215. package/dist/src/runs/phase-cancellation.js.map +1 -0
  216. package/dist/src/runs/phase-group.js +113 -0
  217. package/dist/src/runs/phase-group.js.map +1 -0
  218. package/dist/src/runs/query.js +1 -1
  219. package/dist/src/runs/query.js.map +1 -1
  220. package/dist/src/runs/records.js +3 -0
  221. package/dist/src/runs/records.js.map +1 -1
  222. package/dist/src/runs/request.js +4 -2
  223. package/dist/src/runs/request.js.map +1 -1
  224. package/dist/src/runs/verifier-evidence-redaction.js +61 -0
  225. package/dist/src/runs/verifier-evidence-redaction.js.map +1 -0
  226. package/dist/src/runs/verifier-evidence.js +459 -0
  227. package/dist/src/runs/verifier-evidence.js.map +1 -0
  228. package/dist/src/runs/verifier-structured-evidence.js +83 -0
  229. package/dist/src/runs/verifier-structured-evidence.js.map +1 -0
  230. package/dist/src/trajectories/analysis.js +288 -0
  231. package/dist/src/trajectories/analysis.js.map +1 -0
  232. package/dist/src/trajectories/chunk-projection.js +148 -0
  233. package/dist/src/trajectories/chunk-projection.js.map +1 -0
  234. package/dist/src/trajectories/content-projection.js +389 -0
  235. package/dist/src/trajectories/content-projection.js.map +1 -0
  236. package/dist/src/trajectories/dsh-chunk-contract.js +176 -0
  237. package/dist/src/trajectories/dsh-chunk-contract.js.map +1 -0
  238. package/dist/src/trajectories/dsh-contract.js +284 -0
  239. package/dist/src/trajectories/dsh-contract.js.map +1 -0
  240. package/dist/src/trajectories/events-chunk-drill.js +95 -0
  241. package/dist/src/trajectories/events-chunk-drill.js.map +1 -0
  242. package/dist/src/trajectories/events-page.js +367 -0
  243. package/dist/src/trajectories/events-page.js.map +1 -0
  244. package/dist/src/trajectories/index.js +3 -0
  245. package/dist/src/trajectories/index.js.map +1 -1
  246. package/dist/src/trajectories/request-attempt.js +47 -0
  247. package/dist/src/trajectories/request-attempt.js.map +1 -0
  248. package/dist/src/trajectories/stream-reader.js +311 -0
  249. package/dist/src/trajectories/stream-reader.js.map +1 -0
  250. package/dist/src/trajectories/surface-fold.js +126 -0
  251. package/dist/src/trajectories/surface-fold.js.map +1 -0
  252. package/dist/src/workers/remote-harbor-worker.js +3 -0
  253. package/dist/src/workers/remote-harbor-worker.js.map +1 -1
  254. package/docs/schemas/benchmark-hook-request-v1.schema.json +65 -0
  255. package/docs/schemas/benchmark-hook-response-v1.schema.json +75 -0
  256. package/docs/schemas/benchmark-hook-v1.schema.json +33 -0
  257. package/docs/schemas/benchmark-lock-v1.schema.json +351 -0
  258. package/docs/schemas/benchmark-metric-v1.schema.json +37 -0
  259. package/docs/schemas/benchmark-package-v1.schema.json +167 -0
  260. package/docs/schemas/benchmark-phase-group.schema.json +41 -0
  261. package/docs/schemas/benchmark-profile-v1.schema.json +141 -0
  262. package/docs/schemas/benchmark-task-v1.schema.json +384 -0
  263. package/docs/schemas/benchmark-tool-result-v1.schema.json +30 -0
  264. package/docs/schemas/error.schema.json +22 -0
  265. package/docs/schemas/eval-progress.schema.json +1 -15
  266. package/docs/schemas/eval-rerun-result.schema.json +6 -1
  267. package/docs/schemas/eval-rerun-submission.schema.json +3 -1
  268. package/docs/schemas/eval-result.schema.json +1 -15
  269. package/docs/schemas/eval-trial-publication.schema.json +1 -25
  270. package/docs/schemas/eval-trial-reference.schema.json +129 -0
  271. package/docs/schemas/regrade-assessment-reference.schema.json +11 -0
  272. package/docs/schemas/run-context.schema.json +15 -0
  273. package/docs/schemas/run-manifest.schema.json +4 -0
  274. package/docs/schemas/run-request.schema.json +4 -0
  275. package/docs/schemas/trajectory-analysis.schema.json +258 -0
  276. package/docs/schemas/trajectory-events-page.schema.json +40 -0
  277. package/docs/schemas/verifier-assessment.schema.json +77 -0
  278. package/docs/schemas/verifier-evidence.schema.json +276 -0
  279. package/integrations/harbor/hitch_benchmark.py +252 -0
  280. package/integrations/harbor/hitch_candidate_recycle.py +262 -0
  281. package/integrations/harbor/hitch_harbor_agent.py +541 -43
  282. package/integrations/harbor/hitch_harbor_environment.py +138 -0
  283. package/integrations/harbor/hitch_harbor_verifier.py +60 -2
  284. package/integrations/harbor/hitch_phase_supervisor.py +452 -0
  285. package/integrations/harbor/hitch_tool_client.mjs +91 -0
  286. package/integrations/model-call/cli.js +57 -0
  287. package/package.json +17 -6
@@ -0,0 +1,126 @@
1
+ import path from "node:path";
2
+ import { atomicWriteJSON, ensureDir, readJSON, sha256JSON, withFileLock } from "../foundation/index.js";
3
+ import { benchmarkTaskDigest } from "../runs/index.js";
4
+ const MAX_SAMPLES = 20;
5
+ const DEFAULT_ESTIMATED_DURATION_MS = 15 * 60 * 1_000;
6
+ const MAX_DURATION_MS = 7 * 24 * 60 * 60 * 1_000;
7
+ export async function planTaskSchedulingHints(input) {
8
+ const hints = [];
9
+ for (const taskId of [...input.taskIds].sort(compareBytes)) {
10
+ const identity = durationIdentity(input, taskId);
11
+ const stats = await readStats(statsPath(input.root, identity.key), identity).catch(() => null);
12
+ const baseline = input.evolutionBaselineDurations?.[taskId];
13
+ if (baseline !== undefined && (!Number.isSafeInteger(baseline) || baseline < 1 || baseline > MAX_DURATION_MS)) {
14
+ throw new TypeError(`evolution baseline duration is invalid: ${taskId}`);
15
+ }
16
+ const taskBudget = await readTaskBudget(input.dataset, taskId);
17
+ const fallback = taskBudget ?? (input.requestTimeoutMs > 0 ? input.requestTimeoutMs : DEFAULT_ESTIMATED_DURATION_MS);
18
+ const estimated = baseline ?? (stats && stats.samples.length > 0
19
+ ? percentile(stats.samples.map((sample) => sample.duration_ms), 0.75)
20
+ : fallback);
21
+ const failures = stats?.samples.filter((sample) => sample.retryable_infrastructure_failure).length ?? 0;
22
+ const retryRate = stats && stats.samples.length > 0 ? failures / stats.samples.length : 0;
23
+ const expectedRetries = Math.min(input.infrastructureRetries, 1) * retryRate;
24
+ hints.push([taskId, {
25
+ policy: "critical-path-lpt-v1",
26
+ estimated_duration_ms: estimated,
27
+ remaining_path_ms: Math.max(estimated, Math.round(estimated * (1 + expectedRetries))),
28
+ estimate_source: baseline !== undefined ? "evolution-baseline" : stats && stats.samples.length > 0 ? "history-p75" : taskBudget !== null || input.requestTimeoutMs > 0 ? "task-budget" : "default",
29
+ estimate_sample_count: baseline !== undefined ? 1 : stats?.samples.length ?? 0,
30
+ }]);
31
+ }
32
+ return Object.fromEntries(hints);
33
+ }
34
+ export async function recordTaskDuration(input) {
35
+ if (!Number.isSafeInteger(input.durationMs) || input.durationMs < 1 || input.durationMs > MAX_DURATION_MS) {
36
+ throw new TypeError("task duration sample is invalid");
37
+ }
38
+ const identity = durationIdentity(input, input.taskId);
39
+ const directory = await ensureDir(path.dirname(statsPath(input.root, identity.key)));
40
+ const locks = await ensureDir(path.join(input.root, "locks", "scheduler-duration-stats"));
41
+ await withFileLock(locks, identity.key, async () => {
42
+ const current = await readStats(path.join(directory, `${identity.key.slice("sha256:".length)}.json`), identity).catch(() => null);
43
+ const samples = [...(current?.samples ?? []), {
44
+ duration_ms: input.durationMs,
45
+ retryable_infrastructure_failure: input.retryableInfrastructureFailure,
46
+ }].slice(-MAX_SAMPLES);
47
+ await atomicWriteJSON(statsPath(input.root, identity.key), {
48
+ schema_version: "1",
49
+ ...identity,
50
+ samples,
51
+ updated_at: new Date().toISOString(),
52
+ });
53
+ }, { timeoutCode: "scheduler_duration_stats_locked", timeoutExitCode: 12 });
54
+ }
55
+ export function schedulingHintsFromPlan(plan) {
56
+ const hints = new Map();
57
+ for (const item of plan.work_items) {
58
+ const taskId = item.task_ids[0];
59
+ if (!taskId || !item.scheduling)
60
+ return undefined;
61
+ const existing = hints.get(taskId);
62
+ if (existing && JSON.stringify(existing) !== JSON.stringify(item.scheduling))
63
+ throw new TypeError(`execution plan task scheduling hint changed: ${taskId}`);
64
+ hints.set(taskId, item.scheduling);
65
+ }
66
+ return Object.fromEntries([...hints.entries()].sort((left, right) => compareBytes(left[0], right[0])));
67
+ }
68
+ function durationIdentity(input, taskId) {
69
+ const taskDigest = benchmarkTaskDigest(input.benchmarkId, input.benchmarkRevision, taskId);
70
+ const identity = {
71
+ benchmark_id: input.benchmarkId,
72
+ benchmark_revision: input.benchmarkRevision,
73
+ task_id: taskId,
74
+ task_digest: taskDigest,
75
+ provider: input.provider,
76
+ model: input.model,
77
+ };
78
+ return { key: sha256JSON(identity), ...identity };
79
+ }
80
+ function statsPath(root, key) {
81
+ return path.join(root, "indexes", "scheduler-duration-stats", `${key.slice("sha256:".length)}.json`);
82
+ }
83
+ async function readStats(file, identity) {
84
+ const value = await readJSON(file, null);
85
+ if (value === null)
86
+ return null;
87
+ if (!value || typeof value !== "object" || Array.isArray(value))
88
+ throw new TypeError("task duration stats must be an object");
89
+ const record = value;
90
+ const allowed = ["schema_version", "key", "benchmark_id", "benchmark_revision", "task_id", "task_digest", "provider", "model", "samples", "updated_at"];
91
+ if (Object.keys(record).some((key) => !allowed.includes(key)) || record.schema_version !== "1"
92
+ || record.key !== identity.key || record.benchmark_id !== identity.benchmark_id || record.benchmark_revision !== identity.benchmark_revision
93
+ || record.task_id !== identity.task_id || record.task_digest !== identity.task_digest || record.provider !== identity.provider || record.model !== identity.model
94
+ || !Array.isArray(record.samples) || record.samples.length > MAX_SAMPLES
95
+ || typeof record.updated_at !== "string" || !Number.isFinite(Date.parse(record.updated_at))) {
96
+ throw new TypeError("task duration stats identity is invalid");
97
+ }
98
+ const samples = record.samples.map((value) => {
99
+ if (!value || typeof value !== "object" || Array.isArray(value))
100
+ throw new TypeError("task duration sample is invalid");
101
+ const sample = value;
102
+ if (Object.keys(sample).some((key) => key !== "duration_ms" && key !== "retryable_infrastructure_failure")
103
+ || !Number.isSafeInteger(sample.duration_ms) || sample.duration_ms < 1 || sample.duration_ms > MAX_DURATION_MS
104
+ || typeof sample.retryable_infrastructure_failure !== "boolean")
105
+ throw new TypeError("task duration sample is invalid");
106
+ return { duration_ms: sample.duration_ms, retryable_infrastructure_failure: sample.retryable_infrastructure_failure };
107
+ });
108
+ return { schema_version: "1", ...identity, samples, updated_at: record.updated_at };
109
+ }
110
+ async function readTaskBudget(dataset, taskId) {
111
+ for (const file of [path.join(dataset, taskId, ".hitch-benchmark.json"), path.join(dataset, ".hitch-benchmark.json")]) {
112
+ const descriptor = await readJSON(file, null).catch(() => null);
113
+ const seconds = descriptor?.agent_timeout_sec;
114
+ if (typeof seconds === "number" && Number.isFinite(seconds) && seconds > 0)
115
+ return Math.max(1, Math.round(seconds * 1_000));
116
+ }
117
+ return null;
118
+ }
119
+ function percentile(values, ratio) {
120
+ const sorted = [...values].sort((left, right) => left - right);
121
+ return sorted[Math.max(0, Math.ceil(sorted.length * ratio) - 1)];
122
+ }
123
+ function compareBytes(left, right) {
124
+ return Buffer.compare(Buffer.from(left), Buffer.from(right));
125
+ }
126
+ //# sourceMappingURL=duration-estimator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duration-estimator.js","sourceRoot":"","sources":["../../../src/evals/duration-estimator.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACxG,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,MAAM,WAAW,GAAG,EAAE,CAAC;AACvB,MAAM,6BAA6B,GAAG,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;AACtD,MAAM,eAAe,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;AAoBjD,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,KAW7C;IACC,MAAM,KAAK,GAAsC,EAAE,CAAC;IACpD,KAAK,MAAM,MAAM,IAAI,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;QAC3D,MAAM,QAAQ,GAAG,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACjD,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAC/F,MAAM,QAAQ,GAAG,KAAK,CAAC,0BAA0B,EAAE,CAAC,MAAM,CAAC,CAAC;QAC5D,IAAI,QAAQ,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,IAAI,QAAQ,GAAG,eAAe,CAAC,EAAE,CAAC;YAC9G,MAAM,IAAI,SAAS,CAAC,2CAA2C,MAAM,EAAE,CAAC,CAAC;QAC3E,CAAC;QACD,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC/D,MAAM,QAAQ,GAAG,UAAU,IAAI,CAAC,KAAK,CAAC,gBAAgB,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC;QACrH,MAAM,SAAS,GAAG,QAAQ,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;YAC9D,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,IAAI,CAAC;YACrE,CAAC,CAAC,QAAQ,CAAC,CAAC;QACd,MAAM,QAAQ,GAAG,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,gCAAgC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC;QACxG,MAAM,SAAS,GAAG,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1F,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,qBAAqB,EAAE,CAAC,CAAC,GAAG,SAAS,CAAC;QAC7E,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE;gBAClB,MAAM,EAAE,sBAAsB;gBAC9B,qBAAqB,EAAE,SAAS;gBAChC,iBAAiB,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC;gBACrF,eAAe,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,KAAK,IAAI,IAAI,KAAK,CAAC,gBAAgB,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS;gBAClM,qBAAqB,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,IAAI,CAAC;aAC/E,CAAC,CAAC,CAAC;IACN,CAAC;IACD,OAAO,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,KASxC;IACC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,UAAU,GAAG,CAAC,IAAI,KAAK,CAAC,UAAU,GAAG,eAAe,EAAE,CAAC;QAC1G,MAAM,IAAI,SAAS,CAAC,iCAAiC,CAAC,CAAC;IACzD,CAAC;IACD,MAAM,QAAQ,GAAG,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACrF,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,0BAA0B,CAAC,CAAC,CAAC;IAC1F,MAAM,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,EAAE,KAAK,IAAI,EAAE;QACjD,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAClI,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC,EAAE;gBAC5C,WAAW,EAAE,KAAK,CAAC,UAAU;gBAC7B,gCAAgC,EAAE,KAAK,CAAC,8BAA8B;aACvE,CAAC,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC;QACvB,MAAM,eAAe,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE;YACzD,cAAc,EAAE,GAAG;YACnB,GAAG,QAAQ;YACX,OAAO;YACP,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACP,CAAC,CAAC;IACnC,CAAC,EAAE,EAAE,WAAW,EAAE,iCAAiC,EAAE,eAAe,EAAE,EAAE,EAAE,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,IAAyB;IAC/D,MAAM,KAAK,GAAG,IAAI,GAAG,EAA4B,CAAC;IAClD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;QACnC,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAChC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE,OAAO,SAAS,CAAC;QAClD,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACnC,IAAI,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC;YAAE,MAAM,IAAI,SAAS,CAAC,gDAAgD,MAAM,EAAE,CAAC,CAAC;QAC5J,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzG,CAAC;AAED,SAAS,gBAAgB,CAAC,KAKzB,EAAE,MAAc;IACf,MAAM,UAAU,GAAG,mBAAmB,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;IAC3F,MAAM,QAAQ,GAAG;QACf,YAAY,EAAE,KAAK,CAAC,WAAW;QAC/B,kBAAkB,EAAE,KAAK,CAAC,iBAAiB;QAC3C,OAAO,EAAE,MAAM;QACf,WAAW,EAAE,UAAU;QACvB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,KAAK,EAAE,KAAK,CAAC,KAAK;KACnB,CAAC;IACF,OAAO,EAAE,GAAG,EAAE,UAAU,CAAC,QAAQ,CAAC,EAAE,GAAG,QAAQ,EAAE,CAAC;AACpD,CAAC;AAED,SAAS,SAAS,CAAC,IAAY,EAAE,GAAW;IAC1C,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,0BAA0B,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AACvG,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,IAAY,EAAE,QAA6C;IAClF,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAiB,IAAI,EAAE,IAAI,CAAC,CAAC;IACzD,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAChC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,uCAAuC,CAAC,CAAC;IAC9H,MAAM,MAAM,GAAG,KAAgC,CAAC;IAChD,MAAM,OAAO,GAAG,CAAC,gBAAgB,EAAE,KAAK,EAAE,cAAc,EAAE,oBAAoB,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;IACxJ,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,MAAM,CAAC,cAAc,KAAK,GAAG;WACzF,MAAM,CAAC,GAAG,KAAK,QAAQ,CAAC,GAAG,IAAI,MAAM,CAAC,YAAY,KAAK,QAAQ,CAAC,YAAY,IAAI,MAAM,CAAC,kBAAkB,KAAK,QAAQ,CAAC,kBAAkB;WACzI,MAAM,CAAC,OAAO,KAAK,QAAQ,CAAC,OAAO,IAAI,MAAM,CAAC,WAAW,KAAK,QAAQ,CAAC,WAAW,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,CAAC,QAAQ,IAAI,MAAM,CAAC,KAAK,KAAK,QAAQ,CAAC,KAAK;WAC9J,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,WAAW;WACrE,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC;QAC9F,MAAM,IAAI,SAAS,CAAC,yCAAyC,CAAC,CAAC;IACjE,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QAC3C,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,MAAM,IAAI,SAAS,CAAC,iCAAiC,CAAC,CAAC;QACxH,MAAM,MAAM,GAAG,KAAgC,CAAC;QAChD,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,aAAa,IAAI,GAAG,KAAK,kCAAkC,CAAC;eACrG,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,WAAW,CAAC,IAAK,MAAM,CAAC,WAAsB,GAAG,CAAC,IAAK,MAAM,CAAC,WAAsB,GAAG,eAAe;eACnI,OAAO,MAAM,CAAC,gCAAgC,KAAK,SAAS;YAAE,MAAM,IAAI,SAAS,CAAC,iCAAiC,CAAC,CAAC;QAC1H,OAAO,EAAE,WAAW,EAAE,MAAM,CAAC,WAAqB,EAAE,gCAAgC,EAAE,MAAM,CAAC,gCAA2C,EAAE,CAAC;IAC7I,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,cAAc,EAAE,GAAG,EAAE,GAAG,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC;AACtF,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,OAAe,EAAE,MAAc;IAC3D,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,uBAAuB,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,uBAAuB,CAAC,CAAC,EAAE,CAAC;QACtH,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAiC,IAAI,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAChG,MAAM,OAAO,GAAG,UAAU,EAAE,iBAAiB,CAAC;QAC9C,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC;IAC9H,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,UAAU,CAAC,MAAgB,EAAE,KAAa;IACjD,MAAM,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC;IAC/D,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAW,CAAC;AAC7E,CAAC;AAED,SAAS,YAAY,CAAC,IAAY,EAAE,KAAa;IAC/C,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AAC/D,CAAC"}
@@ -12,5 +12,18 @@ export function emitEvalPlanLifecycle(sink, plan, planningStartedAt) {
12
12
  task_ids: workItem.task_ids,
13
13
  reservation: workItem.reservation,
14
14
  });
15
+ for (const workItem of plan.work_items)
16
+ if (workItem.scheduling)
17
+ sink.emit({
18
+ type: "eval.work.priority-computed",
19
+ work_id: workItem.work_id,
20
+ slot_id: workItem.slots[0],
21
+ task_id: workItem.task_ids[0],
22
+ policy: workItem.scheduling.policy,
23
+ estimated_duration_ms: workItem.scheduling.estimated_duration_ms,
24
+ remaining_path_ms: workItem.scheduling.remaining_path_ms,
25
+ estimate_source: workItem.scheduling.estimate_source,
26
+ estimate_sample_count: workItem.scheduling.estimate_sample_count,
27
+ });
15
28
  }
16
29
  //# sourceMappingURL=eval-lifecycle-events.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"eval-lifecycle-events.js","sourceRoot":"","sources":["../../../src/evals/eval-lifecycle-events.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,qBAAqB,CAAC,IAAmB,EAAE,IAAyB,EAAE,iBAAyB;IAC7G,IAAI,CAAC,IAAI,CAAC;QACR,IAAI,EAAE,mBAAmB;QACzB,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,iBAAiB;QAC3C,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,MAAM;QAClC,UAAU,EAAE,IAAI,CAAC,UAAU;KAC5B,CAAC,CAAC;IACH,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,UAAU;QAAE,IAAI,CAAC,IAAI,CAAC;YAChD,IAAI,EAAE,kBAAkB;YACxB,OAAO,EAAE,QAAQ,CAAC,OAAO;YACzB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,WAAW,EAAE,QAAQ,CAAC,WAAW;SAClC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"eval-lifecycle-events.js","sourceRoot":"","sources":["../../../src/evals/eval-lifecycle-events.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,qBAAqB,CAAC,IAAmB,EAAE,IAAyB,EAAE,iBAAyB;IAC7G,IAAI,CAAC,IAAI,CAAC;QACR,IAAI,EAAE,mBAAmB;QACzB,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,iBAAiB;QAC3C,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,MAAM;QAClC,UAAU,EAAE,IAAI,CAAC,UAAU;KAC5B,CAAC,CAAC;IACH,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,UAAU;QAAE,IAAI,CAAC,IAAI,CAAC;YAChD,IAAI,EAAE,kBAAkB;YACxB,OAAO,EAAE,QAAQ,CAAC,OAAO;YACzB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,WAAW,EAAE,QAAQ,CAAC,WAAW;SAClC,CAAC,CAAC;IACH,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,UAAU;QAAE,IAAI,QAAQ,CAAC,UAAU;YAAE,IAAI,CAAC,IAAI,CAAC;gBACzE,IAAI,EAAE,6BAA6B;gBACnC,OAAO,EAAE,QAAQ,CAAC,OAAO;gBACzB,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;gBAC1B,OAAO,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;gBAC7B,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,MAAM;gBAClC,qBAAqB,EAAE,QAAQ,CAAC,UAAU,CAAC,qBAAqB;gBAChE,iBAAiB,EAAE,QAAQ,CAAC,UAAU,CAAC,iBAAiB;gBACxD,eAAe,EAAE,QAAQ,CAAC,UAAU,CAAC,eAAe;gBACpD,qBAAqB,EAAE,QAAQ,CAAC,UAAU,CAAC,qBAAqB;aACjE,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,51 @@
1
+ import path from "node:path";
2
+ import { SCHEMA_VERSION, atomicWriteJSON, readJSON } from "../foundation/index.js";
3
+ import { writeEvalProgress } from "./progress.js";
4
+ /** Persist the reproducible, artifact-independent part of an eval before setup work begins. */
5
+ export async function writeEvalPlanningCheckpoint(evalDirectory, plan, progress) {
6
+ await Promise.all([
7
+ atomicWriteJSON(path.join(evalDirectory, "logical-plan.json"), plan),
8
+ writeEvalProgress(evalDirectory, progress),
9
+ ]);
10
+ }
11
+ export function materializeEvalPlan(logical, modelCapture, artifactFields) {
12
+ const { kind: _kind, model_capture: _modelCapture, ...base } = logical;
13
+ return {
14
+ ...base,
15
+ ...(modelCapture ? { model_capture: modelCapture } : {}),
16
+ ...artifactFields,
17
+ };
18
+ }
19
+ /** Read only the restart inputs that cannot be reconstructed from request.json. */
20
+ export async function readEvalLogicalPlan(evalDirectory, evalId, request) {
21
+ const value = await readJSON(path.join(evalDirectory, "logical-plan.json"), null);
22
+ if (value === null)
23
+ return null;
24
+ if (!value || typeof value !== "object" || Array.isArray(value))
25
+ throw new TypeError("eval logical plan must be an object");
26
+ const plan = value;
27
+ if (plan.schema_version !== SCHEMA_VERSION || plan.kind !== "eval-logical-plan" || plan.eval_id !== evalId
28
+ || plan.dataset !== request.dataset || plan.benchmark_id !== request.benchmark_id
29
+ || plan.benchmark_revision !== request.benchmark_revision) {
30
+ throw new TypeError("eval logical plan identity is invalid");
31
+ }
32
+ if (plan.model_capture !== undefined)
33
+ parseModelCapturePlan(plan.model_capture);
34
+ return plan;
35
+ }
36
+ export function logicalPlanModelCapture(plan) {
37
+ return plan?.model_capture === undefined ? undefined : parseModelCapturePlan(plan.model_capture);
38
+ }
39
+ function parseModelCapturePlan(value) {
40
+ if (!value || typeof value !== "object" || Array.isArray(value))
41
+ throw new TypeError("eval logical model capture plan is invalid");
42
+ const plan = value;
43
+ const modes = new Set(["off", "native", "proxy", "hybrid"]);
44
+ if (!modes.has(String(plan.requested_mode)) || !modes.has(String(plan.effective_mode)) || typeof plan.required !== "boolean"
45
+ || plan.topology !== undefined && plan.topology !== "host-side" && plan.topology !== "in-sandbox"
46
+ || plan.degraded_reason !== undefined && typeof plan.degraded_reason !== "string") {
47
+ throw new TypeError("eval logical model capture plan is invalid");
48
+ }
49
+ return plan;
50
+ }
51
+ //# sourceMappingURL=eval-logical-plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eval-logical-plan.js","sourceRoot":"","sources":["../../../src/evals/eval-logical-plan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,81 @@
1
+ import { SCHEMA_VERSION } from "../foundation/index.js";
2
+ import { preparedArtifactPlanFields } from "./eval-artifact-planning.js";
3
+ import { infrastructureFailureTrials } from "./infrastructure-retry.js";
4
+ import { invalidTrialSlots } from "./rerun-slots.js";
5
+ import { localSourceBackendFailure, summarizeTrialRefs, transportSummary } from "./result-helpers.js";
6
+ export function buildCompletedEvalResult(input) {
7
+ const trialRefs = input.progress.trials;
8
+ const localSourceFailure = input.localTransport
9
+ ? input.backendRuns.some(({ run }) => localSourceBackendFailure(run.rawResult))
10
+ || input.infrastructureRetryRuns.some(({ run }) => localSourceBackendFailure(run.rawResult))
11
+ : false;
12
+ const expectedBackendRuns = input.plannedTaskExecution ? input.executionWorkItems : input.request.attempts;
13
+ const backendsSucceeded = input.backendRuns.every(({ run }) => run.backend.process_exit_code === 0 && run.rawResult !== null)
14
+ && (input.plannedTaskExecution ? trialRefs.length === input.plannedTrials : input.backendRuns.length === expectedBackendRuns);
15
+ const invalidTrials = input.localTaskIds === null
16
+ ? trialRefs.filter((trial) => trial.observation_status !== "valid").map((trial) => ({ task_id: trial.task_id, attempt: trial.attempt }))
17
+ : invalidTrialSlots(input.localTaskIds, input.request.attempts, input.progress);
18
+ const infrastructureFailures = infrastructureFailureTrials(trialRefs);
19
+ const infrastructureFailureSlots = infrastructureFailures.map((trial) => ({ task_id: trial.task_id, attempt: trial.attempt }));
20
+ const verifierRetriesExhausted = input.request.infrastructure_retries > 0
21
+ && infrastructureFailures.some((trial) => trial.invalid_reason === "verifier_infrastructure_failure");
22
+ const infrastructureErrorCode = verifierRetriesExhausted
23
+ || (input.request.infrastructure_retries > 0 && input.infrastructureRetryRuns.length > 0)
24
+ ? "eval_infrastructure_retries_exhausted"
25
+ : "eval_has_infrastructure_failures";
26
+ const succeeded = !input.cancelled && !localSourceFailure && backendsSucceeded && invalidTrials.length === 0;
27
+ const singleBackend = input.backendRuns.length === 1 ? input.backendRuns[0].run : undefined;
28
+ return {
29
+ schema_version: SCHEMA_VERSION,
30
+ eval_id: input.evalId,
31
+ status: input.cancelled ? "cancelled" : succeeded ? "succeeded" : "failed",
32
+ exit_code: input.cancelled ? 9 : succeeded ? 0 : 13,
33
+ ...(singleBackend ? { backend: singleBackend.backend, backend_summary: singleBackend.summary } : {}),
34
+ ...(input.plannedTaskExecution ? {
35
+ backend_work_items: input.backendRuns.map(({ attempt, workId, tasks, leaseId, run }) => ({
36
+ work_id: workId, lease_id: leaseId, attempt, tasks, backend: run.backend, backend_summary: run.summary,
37
+ })),
38
+ } : input.request.attempts > 1 ? {
39
+ backend_runs: input.backendRuns.map(({ attempt, run }) => ({ attempt, backend: run.backend, backend_summary: run.summary })),
40
+ } : {}),
41
+ infrastructure_retry_policy: {
42
+ max_retries: input.request.infrastructure_retries,
43
+ backoff_ms: input.request.infrastructure_retry_backoff_ms,
44
+ verifier_execution: "same_trial_verifier_only",
45
+ candidate_rerun_on_verifier_failure: false,
46
+ },
47
+ ...(input.infrastructureRetryRuns.length > 0 ? {
48
+ infrastructure_retry_runs: input.infrastructureRetryRuns.map(({ attempt, retry, tasks, triggers, refs, run, leaseId, workId }) => ({
49
+ execution_kind: "physical-infrastructure-retry", ...(leaseId ? { lease_id: leaseId } : {}),
50
+ ...(workId ? { work_id: workId } : {}), attempt, retry, tasks, trigger_trials: triggers,
51
+ trials: refs, backend: run.backend, backend_summary: run.summary,
52
+ })),
53
+ } : {}),
54
+ candidate: input.candidate,
55
+ dataset: input.request.dataset,
56
+ benchmark_id: input.request.benchmark_id,
57
+ benchmark_revision: input.request.benchmark_revision,
58
+ generation: input.progress.generation,
59
+ trials: trialRefs,
60
+ summary: summarizeTrialRefs(trialRefs),
61
+ ...(input.schedulerSummary ? { scheduler_summary: input.schedulerSummary } : {}),
62
+ ...preparedArtifactPlanFields(input.preparedAssignments),
63
+ ...(input.localTransport ? { local_source_transport: transportSummary(input.localTransport) } : {}),
64
+ ...(succeeded ? {} : {
65
+ error: {
66
+ code: input.cancelled ? "cancelled" : localSourceFailure ? "local_source_materialize_failed"
67
+ : !backendsSucceeded ? "harbor_failed" : infrastructureFailures.length > 0
68
+ ? infrastructureErrorCode : "eval_has_invalid_tasks",
69
+ message: input.cancelled ? "eval was cancelled"
70
+ : localSourceFailure ? "Harbor rejected the transported local Git source before candidate execution"
71
+ : !backendsSucceeded ? `Harbor work items completed ${input.backendRuns.length}/${expectedBackendRuns}`
72
+ : infrastructureFailures.length > 0
73
+ ? `${infrastructureErrorCode === "eval_infrastructure_retries_exhausted" ? "infrastructure retries exhausted" : "verifier infrastructure failure"}: ${infrastructureFailureSlots.map(trial => `${trial.task_id}#${trial.attempt}`).join(", ")}`
74
+ : `eval has invalid or missing trials: ${invalidTrials.map(trial => `${trial.task_id}#${trial.attempt}`).join(", ")}`,
75
+ },
76
+ }),
77
+ started_at: input.startedAt.toISOString(),
78
+ completed_at: new Date().toISOString(),
79
+ };
80
+ }
81
+ //# sourceMappingURL=eval-result-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eval-result-builder.js","sourceRoot":"","sources":["../../../src/evals/eval-result-builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,191 @@
1
+ import path from "node:path";
2
+ import { setTimeout as delay } from "node:timers/promises";
3
+ import { atomicWriteJSON, ensureDir, readJSON, sha256JSON, withFileLock } from "../foundation/index.js";
4
+ import { HitchError } from "../foundation/index.js";
5
+ const localFlights = new Map();
6
+ /** Persisted lineage singleflight. Only the caller that creates `submitting`
7
+ * may invoke the materializer; later rounds validate and return `ready`. */
8
+ export async function ensureEvolutionBaseline(options) {
9
+ validateInputs(options);
10
+ const file = baselinePath(options.root, options.evolutionId);
11
+ const local = localFlights.get(file);
12
+ if (local)
13
+ return local;
14
+ const operation = ensureInternal(options, file);
15
+ localFlights.set(file, operation);
16
+ try {
17
+ return await operation;
18
+ }
19
+ finally {
20
+ if (localFlights.get(file) === operation)
21
+ localFlights.delete(file);
22
+ }
23
+ }
24
+ export function evolutionBaselineFingerprint(value) {
25
+ if (!value || typeof value !== "object" || Array.isArray(value) || Object.keys(value).length === 0) {
26
+ throw new TypeError("evolution baseline fingerprint input is invalid");
27
+ }
28
+ return sha256JSON(value);
29
+ }
30
+ export async function readEvolutionBaseline(root, evolutionId) {
31
+ const value = await readJSON(baselinePath(root, evolutionId), null);
32
+ return value === null ? null : parseEvolutionBaseline(value, evolutionId);
33
+ }
34
+ export function parseEvolutionBaseline(value, expectedEvolutionId) {
35
+ if (!value || typeof value !== "object" || Array.isArray(value))
36
+ throw new TypeError("evolution baseline must be an object");
37
+ const record = value;
38
+ const fields = ["schema_version", "evolution_id", "baseline_fingerprint", "state", "seed_eval_id", "heldout_eval_id", "seed_result_digest", "heldout_result_digest", "created_at", "updated_at"];
39
+ if (Object.keys(record).some((key) => !fields.includes(key)) || record.schema_version !== "1"
40
+ || typeof record.evolution_id !== "string" || !record.evolution_id
41
+ || expectedEvolutionId !== undefined && record.evolution_id !== expectedEvolutionId
42
+ || typeof record.baseline_fingerprint !== "string" || !/^sha256:[a-f0-9]{64}$/.test(record.baseline_fingerprint)
43
+ || !["submitting", "running", "ready", "failed"].includes(record.state)
44
+ || typeof record.created_at !== "string" || !Number.isFinite(Date.parse(record.created_at))
45
+ || typeof record.updated_at !== "string" || !Number.isFinite(Date.parse(record.updated_at)))
46
+ throw new TypeError("evolution baseline identity is invalid");
47
+ const optional = ["seed_eval_id", "heldout_eval_id"];
48
+ for (const name of optional)
49
+ if (record[name] !== undefined && (typeof record[name] !== "string" || !/^eval_[a-f0-9]{32}$/.test(record[name]))) {
50
+ throw new TypeError(`evolution baseline ${name} is invalid`);
51
+ }
52
+ for (const name of ["seed_result_digest", "heldout_result_digest"])
53
+ if (record[name] !== undefined
54
+ && (typeof record[name] !== "string" || !/^sha256:[a-f0-9]{64}$/.test(record[name])))
55
+ throw new TypeError(`evolution baseline ${name} is invalid`);
56
+ if (record.state === "running" && (!record.seed_eval_id || !record.heldout_eval_id))
57
+ throw new TypeError("running evolution baseline eval identities are missing");
58
+ if (record.state === "ready" && (!record.seed_eval_id || !record.heldout_eval_id || !record.seed_result_digest || !record.heldout_result_digest)) {
59
+ throw new TypeError("ready evolution baseline references are incomplete");
60
+ }
61
+ return record;
62
+ }
63
+ async function ensureInternal(options, file) {
64
+ const ownership = await claim(options, file);
65
+ if (!ownership.owner)
66
+ return waitForOwner(options, file, ownership.baseline);
67
+ try {
68
+ const materialized = await options.materialize({
69
+ markRunning: (seedEvalId, heldoutEvalId) => updateOwned(options, file, (current) => ({
70
+ ...assertRunningIdentity(current, seedEvalId, heldoutEvalId), state: "running",
71
+ })).then(() => undefined),
72
+ });
73
+ const ready = await updateOwned(options, file, (current) => {
74
+ if (current.seed_eval_id && current.seed_eval_id !== materialized.seed_eval_id
75
+ || current.heldout_eval_id && current.heldout_eval_id !== materialized.heldout_eval_id) {
76
+ throw new TypeError("evolution baseline eval identity changed during materialization");
77
+ }
78
+ return {
79
+ ...current, state: "ready", seed_eval_id: checkedEvalId(materialized.seed_eval_id), heldout_eval_id: checkedEvalId(materialized.heldout_eval_id),
80
+ seed_result_digest: checkedDigest(materialized.seed_result_digest), heldout_result_digest: checkedDigest(materialized.heldout_result_digest),
81
+ };
82
+ });
83
+ await options.validateReady?.(ready);
84
+ return ready;
85
+ }
86
+ catch (error) {
87
+ await updateOwned(options, file, (current) => ({ ...current, state: "failed" })).catch(() => undefined);
88
+ throw error;
89
+ }
90
+ }
91
+ async function claim(options, file) {
92
+ await ensureDir(path.dirname(file));
93
+ return withBaselineLock(options, async () => {
94
+ const existing = await readEvolutionBaseline(options.root, options.evolutionId);
95
+ if (existing) {
96
+ assertFingerprint(existing, options.fingerprint);
97
+ if (existing.state === "failed")
98
+ throw baselineError("evolution baseline materialization previously failed", "evolution_baseline_failed");
99
+ if (existing.state === "ready")
100
+ await options.validateReady?.(existing);
101
+ return { owner: false, baseline: existing };
102
+ }
103
+ const now = new Date().toISOString();
104
+ const baseline = parseEvolutionBaseline({
105
+ schema_version: "1", evolution_id: options.evolutionId, baseline_fingerprint: options.fingerprint,
106
+ state: "submitting", created_at: now, updated_at: now,
107
+ }, options.evolutionId);
108
+ await atomicWriteJSON(file, baseline);
109
+ return { owner: true, baseline };
110
+ });
111
+ }
112
+ async function waitForOwner(options, file, initial) {
113
+ if (initial.state === "ready")
114
+ return initial;
115
+ const deadline = Date.now() + (options.maxWaitMs ?? 24 * 60 * 60 * 1_000);
116
+ const poll = options.pollIntervalMs ?? 250;
117
+ for (;;) {
118
+ if (options.signal?.aborted)
119
+ throw options.signal.reason;
120
+ if (Date.now() >= deadline)
121
+ throw baselineError("evolution baseline materialization is still in progress", "evolution_baseline_in_progress");
122
+ await delay(Math.min(poll, Math.max(1, deadline - Date.now())), undefined, options.signal ? { signal: options.signal } : undefined);
123
+ const current = await readEvolutionBaseline(options.root, options.evolutionId);
124
+ if (!current)
125
+ throw baselineError("evolution baseline record disappeared", "evolution_baseline_state_conflict");
126
+ assertFingerprint(current, options.fingerprint);
127
+ if (current.state === "failed")
128
+ throw baselineError("evolution baseline materialization failed", "evolution_baseline_failed");
129
+ if (current.state === "ready") {
130
+ await options.validateReady?.(current);
131
+ return current;
132
+ }
133
+ }
134
+ }
135
+ async function updateOwned(options, file, update) {
136
+ return withBaselineLock(options, async () => {
137
+ const current = await readEvolutionBaseline(options.root, options.evolutionId);
138
+ if (!current)
139
+ throw baselineError("evolution baseline ownership was lost", "evolution_baseline_state_conflict");
140
+ assertFingerprint(current, options.fingerprint);
141
+ if (current.state === "ready" || current.state === "failed")
142
+ throw baselineError("evolution baseline is already terminal", "evolution_baseline_state_conflict");
143
+ const next = parseEvolutionBaseline({ ...update(current), updated_at: new Date().toISOString() }, options.evolutionId);
144
+ await atomicWriteJSON(file, next);
145
+ return next;
146
+ });
147
+ }
148
+ function withBaselineLock(options, operation) {
149
+ const key = sha256JSON({ evolution_id: options.evolutionId }).slice("sha256:".length);
150
+ return withFileLock(path.join(options.root, "locks", "evolution-baseline"), key, operation, {
151
+ timeoutCode: "evolution_baseline_locked", timeoutExitCode: 12,
152
+ });
153
+ }
154
+ function validateInputs(options) {
155
+ if (!options.root || !options.evolutionId || !/^sha256:[a-f0-9]{64}$/.test(options.fingerprint))
156
+ throw new TypeError("evolution baseline request is invalid");
157
+ if (options.pollIntervalMs !== undefined && (!Number.isSafeInteger(options.pollIntervalMs) || options.pollIntervalMs < 1))
158
+ throw new TypeError("evolution baseline poll interval is invalid");
159
+ if (options.maxWaitMs !== undefined && (!Number.isSafeInteger(options.maxWaitMs) || options.maxWaitMs < 1))
160
+ throw new TypeError("evolution baseline wait is invalid");
161
+ }
162
+ function baselinePath(root, evolutionId) {
163
+ const id = sha256JSON({ evolution_id: evolutionId }).slice("sha256:".length);
164
+ return path.join(root, "evolutions", id, "baseline.json");
165
+ }
166
+ function assertFingerprint(record, fingerprint) {
167
+ if (record.baseline_fingerprint !== fingerprint)
168
+ throw baselineError("evolution baseline fingerprint changed", "evolution_baseline_fingerprint_mismatch");
169
+ }
170
+ function checkedEvalId(value) {
171
+ if (!/^eval_[a-f0-9]{32}$/.test(value))
172
+ throw new TypeError("evolution baseline eval id is invalid");
173
+ return value;
174
+ }
175
+ function checkedDigest(value) {
176
+ if (!/^sha256:[a-f0-9]{64}$/.test(value))
177
+ throw new TypeError("evolution baseline result digest is invalid");
178
+ return value;
179
+ }
180
+ function assertRunningIdentity(current, seedEvalId, heldoutEvalId) {
181
+ const seed = checkedEvalId(seedEvalId);
182
+ const heldout = checkedEvalId(heldoutEvalId);
183
+ if (current.seed_eval_id && current.seed_eval_id !== seed || current.heldout_eval_id && current.heldout_eval_id !== heldout) {
184
+ throw new TypeError("evolution baseline eval identity changed while running");
185
+ }
186
+ return { ...current, seed_eval_id: seed, heldout_eval_id: heldout };
187
+ }
188
+ function baselineError(message, code) {
189
+ return new HitchError(message, { code, exitCode: 12 });
190
+ }
191
+ //# sourceMappingURL=evolution-baseline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evolution-baseline.js","sourceRoot":"","sources":["../../../src/evals/evolution-baseline.ts"],"names":[],"mappings":"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"}
@@ -25,6 +25,10 @@ export function buildEvalExecutionPlan(options) {
25
25
  required: false,
26
26
  });
27
27
  const tasks = options.tasks === null ? null : canonicalTasks(options.tasks);
28
+ if (options.taskScheduling && (tasks === null || options.workItemMode !== "task-slots")) {
29
+ throw new TypeError("task scheduling hints require task-slot work items with known membership");
30
+ }
31
+ const taskScheduling = tasks === null ? undefined : parseTaskScheduling(options.taskScheduling, tasks);
28
32
  const artifactAssignments = parseArtifactAssignments(options.candidate.artifactAssignments, tasks, options.candidate.artifactId);
29
33
  const taskResources = tasks === null ? undefined : parseTaskResourceRequirements(options.taskResources, tasks);
30
34
  const environmentImages = tasks === null ? [] : parseEnvironmentImageUses(options.environmentImages ?? [], tasks, "execution plan environment images");
@@ -45,7 +49,7 @@ export function buildEvalExecutionPlan(options) {
45
49
  const workItems = tasks === null
46
50
  ? [opaqueWorkItem(options.evalId, options.maxParallelism, resources, provider, artifactAssignments[0])]
47
51
  : options.workItemMode === "task-slots"
48
- ? buildTaskWorkItems(options.evalId, slots, resources, provider, taskResources, environmentImages, artifactAssignments)
52
+ ? buildTaskWorkItems(options.evalId, slots, resources, provider, taskResources, environmentImages, artifactAssignments, taskScheduling)
49
53
  : buildAttemptWorkItems(options.evalId, tasks, slots, options.request.attempts, options.maxParallelism, resources, provider, taskResources, environmentImages, artifactAssignments);
50
54
  return parseEvalExecutionPlan({
51
55
  schema_version: "1",
@@ -206,7 +210,7 @@ function buildAttemptWorkItems(evalId, tasks, slots, attempts, maxParallelism, r
206
210
  }
207
211
  return items;
208
212
  }
209
- function buildTaskWorkItems(evalId, slots, resources, provider, taskResources, environmentImages = [], artifactAssignments = []) {
213
+ function buildTaskWorkItems(evalId, slots, resources, provider, taskResources, environmentImages = [], artifactAssignments = [], taskScheduling) {
210
214
  return slots.map((slot) => {
211
215
  const imageRefs = imagesForTasks(environmentImages, [slot.task_id]);
212
216
  const assignment = artifactAssignments.find((entry) => entry.taskIds.includes(slot.task_id));
@@ -224,6 +228,7 @@ function buildTaskWorkItems(evalId, slots, resources, provider, taskResources, e
224
228
  reservation: reservationForTasks([slot.task_id], 1, resources, taskResources),
225
229
  provider,
226
230
  ...(imageRefs.length > 0 ? { image_refs: imageRefs } : {}),
231
+ ...(taskScheduling?.[slot.task_id] ? { scheduling: taskScheduling[slot.task_id] } : {}),
227
232
  ...artifactPin,
228
233
  };
229
234
  });
@@ -275,7 +280,7 @@ function parseWorkItem(value, evalId, provider, maxParallelism, index) {
275
280
  assertOnlyKeys(value, [
276
281
  "schema_version", "work_id", "eval_id", "backend", "logical_attempt", "task_ids", "slots",
277
282
  "opaque_membership", "requested_parallelism", "reservation", "provider",
278
- "image_refs", "artifact_id", "runtime_contract",
283
+ "image_refs", "artifact_id", "runtime_contract", "scheduling",
279
284
  ], `eval execution plan work item ${index}`);
280
285
  if (value.schema_version !== "1" || typeof value.work_id !== "string" || !/^work_[a-f0-9]{32}$/.test(value.work_id)
281
286
  || value.eval_id !== evalId || value.backend !== "harbor"
@@ -292,6 +297,7 @@ function parseWorkItem(value, evalId, provider, maxParallelism, index) {
292
297
  const imageRefs = parseEnvironmentImageUses(value.image_refs ?? [], value.task_ids, `eval execution plan work item ${index} image refs`);
293
298
  const artifactId = value.artifact_id === undefined ? undefined : isSha256(value.artifact_id) ? value.artifact_id : (() => { throw new TypeError(`eval execution plan work item ${index} artifact id is invalid`); })();
294
299
  const runtimeContract = value.runtime_contract === undefined ? undefined : parseRuntimeContract(value.runtime_contract, `eval execution plan work item ${index}`);
300
+ const scheduling = value.scheduling === undefined ? undefined : parseSchedulingHint(value.scheduling, `eval execution plan work item ${index}`);
295
301
  if ((artifactId === undefined) !== (runtimeContract === undefined))
296
302
  throw new TypeError(`eval execution plan work item ${index} artifact contract is incomplete`);
297
303
  return {
@@ -300,8 +306,38 @@ function parseWorkItem(value, evalId, provider, maxParallelism, index) {
300
306
  ...(imageRefs.length > 0 ? { image_refs: imageRefs } : {}),
301
307
  ...(artifactId ? { artifact_id: artifactId } : {}),
302
308
  ...(runtimeContract ? { runtime_contract: runtimeContract } : {}),
309
+ ...(scheduling ? { scheduling } : {}),
303
310
  };
304
311
  }
312
+ function parseSchedulingHint(value, label) {
313
+ if (!isRecord(value))
314
+ throw new TypeError(`${label} scheduling hint is invalid`);
315
+ assertOnlyKeys(value, ["policy", "estimated_duration_ms", "remaining_path_ms", "estimate_source", "estimate_sample_count"], `${label} scheduling hint`);
316
+ const sources = new Set(["evolution-baseline", "history-p75", "task-budget", "default"]);
317
+ if (value.policy !== "critical-path-lpt-v1"
318
+ || !Number.isSafeInteger(value.estimated_duration_ms) || value.estimated_duration_ms < 1
319
+ || !Number.isSafeInteger(value.remaining_path_ms) || value.remaining_path_ms < value.estimated_duration_ms
320
+ || !sources.has(value.estimate_source)
321
+ || !Number.isSafeInteger(value.estimate_sample_count) || value.estimate_sample_count < 0) {
322
+ throw new TypeError(`${label} scheduling hint is invalid`);
323
+ }
324
+ if (value.estimate_source === "default" || value.estimate_source === "task-budget") {
325
+ if (value.estimate_sample_count !== 0)
326
+ throw new TypeError(`${label} scheduling hint sample count is invalid`);
327
+ }
328
+ else if (value.estimate_sample_count < 1)
329
+ throw new TypeError(`${label} scheduling hint sample count is invalid`);
330
+ return value;
331
+ }
332
+ function parseTaskScheduling(value, tasks) {
333
+ if (value === undefined)
334
+ return undefined;
335
+ const keys = Object.keys(value).sort(compareBytes);
336
+ if (keys.length !== tasks.length || keys.some((task, index) => task !== tasks[index])) {
337
+ throw new TypeError("task scheduling hints must cover every planned task exactly once");
338
+ }
339
+ return Object.fromEntries(keys.map((task) => [task, parseSchedulingHint(value[task], `task ${task}`)]));
340
+ }
305
341
  function assertPlanGraph(membership, slots, workItems, resources, taskResources) {
306
342
  if (new Set(slots.map((slot) => slot.slot_id)).size !== slots.length || new Set(workItems.map((item) => item.work_id)).size !== workItems.length) {
307
343
  throw new TypeError("eval execution plan identities are duplicated");