@openpond/evals 0.11.21 → 0.12.1

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 (311) hide show
  1. package/README.md +12 -0
  2. package/dist/artifact-verification.js +2 -0
  3. package/dist/connected-evidence/codex-command-observations.js +81 -0
  4. package/dist/connected-evidence/contracts.js +13 -0
  5. package/dist/connected-evidence/git-file-contracts.js +16 -0
  6. package/dist/connected-evidence/git-file-proof.js +86 -0
  7. package/dist/connected-evidence/git-starting-state.js +81 -0
  8. package/dist/connected-evidence/git.js +2 -0
  9. package/dist/connected-evidence/imports.js +2 -1
  10. package/dist/connected-evidence/index.js +1 -0
  11. package/dist/connected-evidence/normalize.js +1 -0
  12. package/dist/connected-evidence/sources/claude-branches.js +34 -1
  13. package/dist/connected-evidence/sources/claude-code.js +1 -1
  14. package/dist/connected-evidence/sources/codex-metadata.js +33 -0
  15. package/dist/connected-evidence/sources/codex.js +16 -2
  16. package/dist/graders.js +10 -4
  17. package/dist/javascript-verifier.js +1 -0
  18. package/dist/native-conversations/codex-window-inventory.js +6 -7
  19. package/dist/native-conversations/collector-acquisition.js +17 -6
  20. package/dist/native-conversations/collector-source-cache.js +1 -1
  21. package/dist/native-conversations/collector-store.js +27 -2
  22. package/dist/native-conversations/collector.js +4 -3
  23. package/dist/native-conversations/git-assets.js +61 -0
  24. package/dist/native-conversations/history.js +7 -0
  25. package/dist/native-conversations/index.js +2 -0
  26. package/dist/native-conversations/selection.js +57 -0
  27. package/dist/native-conversations/supervisor.js +2 -0
  28. package/dist/prepared-process-isolation.js +131 -0
  29. package/dist/rewards.js +17 -5
  30. package/dist/tasksets.js +7 -0
  31. package/dist/types/artifact-verification.d.ts.map +1 -1
  32. package/dist/types/benchmarks.d.ts +22 -22
  33. package/dist/types/benchmarks.d.ts.map +1 -1
  34. package/dist/types/builtin-benchmarks/harness-refiner.d.ts +40 -35
  35. package/dist/types/builtin-benchmarks/harness-refiner.d.ts.map +1 -1
  36. package/dist/types/compatibility.d.ts.map +1 -1
  37. package/dist/types/conformance.d.ts +98 -88
  38. package/dist/types/conformance.d.ts.map +1 -1
  39. package/dist/types/connected-evidence/codex-command-observations.d.ts +15 -0
  40. package/dist/types/connected-evidence/codex-command-observations.d.ts.map +1 -0
  41. package/dist/types/connected-evidence/collector-coverage-contracts.d.ts +6 -6
  42. package/dist/types/connected-evidence/collector-coverage-contracts.d.ts.map +1 -1
  43. package/dist/types/connected-evidence/contracts.d.ts +80 -58
  44. package/dist/types/connected-evidence/contracts.d.ts.map +1 -1
  45. package/dist/types/connected-evidence/git-file-contracts.d.ts +18 -0
  46. package/dist/types/connected-evidence/git-file-contracts.d.ts.map +1 -0
  47. package/dist/types/connected-evidence/git-file-proof.d.ts +13 -0
  48. package/dist/types/connected-evidence/git-file-proof.d.ts.map +1 -0
  49. package/dist/types/connected-evidence/git-starting-state.d.ts +28 -0
  50. package/dist/types/connected-evidence/git-starting-state.d.ts.map +1 -0
  51. package/dist/types/connected-evidence/git.d.ts +3 -0
  52. package/dist/types/connected-evidence/git.d.ts.map +1 -0
  53. package/dist/types/connected-evidence/imports.d.ts.map +1 -1
  54. package/dist/types/connected-evidence/index.d.ts +1 -0
  55. package/dist/types/connected-evidence/index.d.ts.map +1 -1
  56. package/dist/types/connected-evidence/normalize.d.ts +1 -0
  57. package/dist/types/connected-evidence/normalize.d.ts.map +1 -1
  58. package/dist/types/connected-evidence/python-correctness.d.ts +38 -38
  59. package/dist/types/connected-evidence/python-correctness.d.ts.map +1 -1
  60. package/dist/types/connected-evidence/sources/claude-branches.d.ts +1 -0
  61. package/dist/types/connected-evidence/sources/claude-branches.d.ts.map +1 -1
  62. package/dist/types/connected-evidence/sources/claude-code.d.ts +25 -15
  63. package/dist/types/connected-evidence/sources/claude-code.d.ts.map +1 -1
  64. package/dist/types/connected-evidence/sources/codex-authorization.d.ts.map +1 -1
  65. package/dist/types/connected-evidence/sources/codex-metadata.d.ts +10 -0
  66. package/dist/types/connected-evidence/sources/codex-metadata.d.ts.map +1 -0
  67. package/dist/types/connected-evidence/sources/codex.d.ts +25 -15
  68. package/dist/types/connected-evidence/sources/codex.d.ts.map +1 -1
  69. package/dist/types/connected-evidence/sources/grok-build.d.ts +25 -15
  70. package/dist/types/connected-evidence/sources/grok-build.d.ts.map +1 -1
  71. package/dist/types/connected-evidence/sources/history.d.ts +50 -30
  72. package/dist/types/connected-evidence/sources/history.d.ts.map +1 -1
  73. package/dist/types/connected-evidence/sources/opencode.d.ts +25 -15
  74. package/dist/types/connected-evidence/sources/opencode.d.ts.map +1 -1
  75. package/dist/types/connected-evidence/sources/pi.d.ts +25 -15
  76. package/dist/types/connected-evidence/sources/pi.d.ts.map +1 -1
  77. package/dist/types/connected-evidence/sources/usage.d.ts.map +1 -1
  78. package/dist/types/connected-evidence/usage-summary.d.ts.map +1 -1
  79. package/dist/types/deterministic-graders.d.ts.map +1 -1
  80. package/dist/types/environment-execution-services-contract.d.ts +19 -19
  81. package/dist/types/environment-execution-services-contract.d.ts.map +1 -1
  82. package/dist/types/environment-execution-services.d.ts.map +1 -1
  83. package/dist/types/evidence/authoring.d.ts.map +1 -1
  84. package/dist/types/evidence/conformance.d.ts +98 -98
  85. package/dist/types/evidence/conformance.d.ts.map +1 -1
  86. package/dist/types/evidence/contracts.d.ts +183 -183
  87. package/dist/types/evidence/contracts.d.ts.map +1 -1
  88. package/dist/types/evidence/eligibility.d.ts +160 -160
  89. package/dist/types/evidence/eligibility.d.ts.map +1 -1
  90. package/dist/types/evidence/index.d.ts.map +1 -1
  91. package/dist/types/execution-contracts.d.ts +118 -110
  92. package/dist/types/execution-contracts.d.ts.map +1 -1
  93. package/dist/types/execution-receipts.d.ts.map +1 -1
  94. package/dist/types/experiments.d.ts +96 -96
  95. package/dist/types/experiments.d.ts.map +1 -1
  96. package/dist/types/graders.d.ts +38 -35
  97. package/dist/types/graders.d.ts.map +1 -1
  98. package/dist/types/harness-experiment-source.d.ts.map +1 -1
  99. package/dist/types/harness.d.ts.map +1 -1
  100. package/dist/types/human-review/comparison.d.ts +189 -189
  101. package/dist/types/human-review/comparison.d.ts.map +1 -1
  102. package/dist/types/human-review/contracts.d.ts +178 -178
  103. package/dist/types/human-review/contracts.d.ts.map +1 -1
  104. package/dist/types/human-review/execution.d.ts +53 -53
  105. package/dist/types/human-review/execution.d.ts.map +1 -1
  106. package/dist/types/human-review/handoff.d.ts +43 -43
  107. package/dist/types/human-review/handoff.d.ts.map +1 -1
  108. package/dist/types/human-review/index.d.ts.map +1 -1
  109. package/dist/types/human-review/local-publication.d.ts +4 -4
  110. package/dist/types/human-review/local-publication.d.ts.map +1 -1
  111. package/dist/types/human-review/repository.d.ts.map +1 -1
  112. package/dist/types/human-review/results.d.ts +8 -8
  113. package/dist/types/human-review/results.d.ts.map +1 -1
  114. package/dist/types/human-review/service.d.ts +292 -292
  115. package/dist/types/human-review/service.d.ts.map +1 -1
  116. package/dist/types/human-review/task-proposals.d.ts +2 -2
  117. package/dist/types/human-review/task-proposals.d.ts.map +1 -1
  118. package/dist/types/index.d.ts.map +1 -1
  119. package/dist/types/javascript-environment-attempt.d.ts.map +1 -1
  120. package/dist/types/javascript-environment-contract.d.ts +39 -39
  121. package/dist/types/javascript-environment-contract.d.ts.map +1 -1
  122. package/dist/types/javascript-environment-node.d.ts.map +1 -1
  123. package/dist/types/javascript-environment.d.ts +14 -14
  124. package/dist/types/javascript-environment.d.ts.map +1 -1
  125. package/dist/types/javascript-isolate-node.d.ts.map +1 -1
  126. package/dist/types/javascript-isolate-process-entry.d.ts.map +1 -1
  127. package/dist/types/javascript-isolate-process.d.ts.map +1 -1
  128. package/dist/types/javascript-isolate.d.ts.map +1 -1
  129. package/dist/types/javascript-verifier-contract.d.ts.map +1 -1
  130. package/dist/types/javascript-verifier-node.d.ts.map +1 -1
  131. package/dist/types/javascript-verifier-worker.d.ts.map +1 -1
  132. package/dist/types/javascript-verifier.d.ts +1 -0
  133. package/dist/types/javascript-verifier.d.ts.map +1 -1
  134. package/dist/types/learned-preference.d.ts +10 -10
  135. package/dist/types/learned-preference.d.ts.map +1 -1
  136. package/dist/types/learning/acceptance-group.d.ts +44 -44
  137. package/dist/types/learning/acceptance-group.d.ts.map +1 -1
  138. package/dist/types/learning/acceptance-plan.d.ts +8 -8
  139. package/dist/types/learning/acceptance-plan.d.ts.map +1 -1
  140. package/dist/types/learning/admission.d.ts +38 -36
  141. package/dist/types/learning/admission.d.ts.map +1 -1
  142. package/dist/types/learning/assets.d.ts +2 -2
  143. package/dist/types/learning/assets.d.ts.map +1 -1
  144. package/dist/types/learning/authoring-service.d.ts +11 -9
  145. package/dist/types/learning/authoring-service.d.ts.map +1 -1
  146. package/dist/types/learning/authoring.d.ts +46 -38
  147. package/dist/types/learning/authoring.d.ts.map +1 -1
  148. package/dist/types/learning/batch-service.d.ts +75 -68
  149. package/dist/types/learning/batch-service.d.ts.map +1 -1
  150. package/dist/types/learning/budgeted-reward-fixtures.d.ts.map +1 -1
  151. package/dist/types/learning/contracts.d.ts +314 -290
  152. package/dist/types/learning/contracts.d.ts.map +1 -1
  153. package/dist/types/learning/errors.d.ts.map +1 -1
  154. package/dist/types/learning/grade-judge-budget.d.ts.map +1 -1
  155. package/dist/types/learning/grade-worker.d.ts.map +1 -1
  156. package/dist/types/learning/index.d.ts.map +1 -1
  157. package/dist/types/learning/intake-contracts.d.ts +10 -10
  158. package/dist/types/learning/intake-contracts.d.ts.map +1 -1
  159. package/dist/types/learning/intake-csv.d.ts.map +1 -1
  160. package/dist/types/learning/intake-history.d.ts.map +1 -1
  161. package/dist/types/learning/intake-service.d.ts.map +1 -1
  162. package/dist/types/learning/intake-text.d.ts.map +1 -1
  163. package/dist/types/learning/intake.d.ts.map +1 -1
  164. package/dist/types/learning/iteration-budget.d.ts.map +1 -1
  165. package/dist/types/learning/iteration-candidate-decision.d.ts +16 -16
  166. package/dist/types/learning/iteration-candidate-decision.d.ts.map +1 -1
  167. package/dist/types/learning/iteration-dispatch-commands.d.ts.map +1 -1
  168. package/dist/types/learning/iteration-dispatch-contracts.d.ts +4 -4
  169. package/dist/types/learning/iteration-dispatch-contracts.d.ts.map +1 -1
  170. package/dist/types/learning/iteration-dispatch-worker.d.ts.map +1 -1
  171. package/dist/types/learning/iteration-eligibility.d.ts +1 -1
  172. package/dist/types/learning/iteration-eligibility.d.ts.map +1 -1
  173. package/dist/types/learning/iteration-reservation-cancellation.d.ts.map +1 -1
  174. package/dist/types/learning/iteration-reservation-contracts.d.ts.map +1 -1
  175. package/dist/types/learning/iteration-reservation-service.d.ts.map +1 -1
  176. package/dist/types/learning/iteration-training-parent.d.ts.map +1 -1
  177. package/dist/types/learning/judge-budget.d.ts +1 -1
  178. package/dist/types/learning/judge-budget.d.ts.map +1 -1
  179. package/dist/types/learning/model-judge.d.ts.map +1 -1
  180. package/dist/types/learning/nightly-schedule.d.ts.map +1 -1
  181. package/dist/types/learning/operations.d.ts +312 -298
  182. package/dist/types/learning/operations.d.ts.map +1 -1
  183. package/dist/types/learning/policy-inspection.d.ts.map +1 -1
  184. package/dist/types/learning/rating-reward-fixture.d.ts.map +1 -1
  185. package/dist/types/learning/repository.d.ts +197 -180
  186. package/dist/types/learning/repository.d.ts.map +1 -1
  187. package/dist/types/learning/reward-authoring.d.ts.map +1 -1
  188. package/dist/types/learning/reward-calibration-closure.d.ts +252 -244
  189. package/dist/types/learning/reward-calibration-closure.d.ts.map +1 -1
  190. package/dist/types/learning/reward-calibration.d.ts +62 -62
  191. package/dist/types/learning/reward-calibration.d.ts.map +1 -1
  192. package/dist/types/learning/reward-check-budget.d.ts.map +1 -1
  193. package/dist/types/learning/reward-check-service.d.ts.map +1 -1
  194. package/dist/types/learning/reward-check-worker.d.ts.map +1 -1
  195. package/dist/types/learning/reward-checks.d.ts +30 -28
  196. package/dist/types/learning/reward-checks.d.ts.map +1 -1
  197. package/dist/types/learning/reward-fixture-executor.d.ts.map +1 -1
  198. package/dist/types/learning/schedule-contracts.d.ts +3 -3
  199. package/dist/types/learning/schedule-contracts.d.ts.map +1 -1
  200. package/dist/types/learning/schedule-service.d.ts +2 -2
  201. package/dist/types/learning/schedule-service.d.ts.map +1 -1
  202. package/dist/types/learning/schedule-worker.d.ts.map +1 -1
  203. package/dist/types/learning/service.d.ts +3 -3
  204. package/dist/types/learning/service.d.ts.map +1 -1
  205. package/dist/types/learning/task-queue-inspection.d.ts.map +1 -1
  206. package/dist/types/learning/training-handoff.d.ts +9 -9
  207. package/dist/types/learning/training-handoff.d.ts.map +1 -1
  208. package/dist/types/learning/transport.d.ts +2203 -2179
  209. package/dist/types/learning/transport.d.ts.map +1 -1
  210. package/dist/types/metric-policy.d.ts +6 -6
  211. package/dist/types/metric-policy.d.ts.map +1 -1
  212. package/dist/types/metrics-node.d.ts.map +1 -1
  213. package/dist/types/metrics.d.ts.map +1 -1
  214. package/dist/types/model-improvement-qualification.d.ts +17 -17
  215. package/dist/types/model-improvement-qualification.d.ts.map +1 -1
  216. package/dist/types/native-conversations/appimage-runtime.d.ts.map +1 -1
  217. package/dist/types/native-conversations/codex-window-inventory.d.ts.map +1 -1
  218. package/dist/types/native-conversations/collector-acquisition.d.ts.map +1 -1
  219. package/dist/types/native-conversations/collector-branches.d.ts.map +1 -1
  220. package/dist/types/native-conversations/collector-calendar-gate.d.ts.map +1 -1
  221. package/dist/types/native-conversations/collector-contracts.d.ts +3 -0
  222. package/dist/types/native-conversations/collector-contracts.d.ts.map +1 -1
  223. package/dist/types/native-conversations/collector-coverage.d.ts +2 -2
  224. package/dist/types/native-conversations/collector-coverage.d.ts.map +1 -1
  225. package/dist/types/native-conversations/collector-cron.d.ts.map +1 -1
  226. package/dist/types/native-conversations/collector-destinations.d.ts.map +1 -1
  227. package/dist/types/native-conversations/collector-errors.d.ts.map +1 -1
  228. package/dist/types/native-conversations/collector-progress.d.ts.map +1 -1
  229. package/dist/types/native-conversations/collector-schedule.d.ts.map +1 -1
  230. package/dist/types/native-conversations/collector-service-files.d.ts.map +1 -1
  231. package/dist/types/native-conversations/collector-snapshots.d.ts.map +1 -1
  232. package/dist/types/native-conversations/collector-source-cache.d.ts +2 -2
  233. package/dist/types/native-conversations/collector-source-cache.d.ts.map +1 -1
  234. package/dist/types/native-conversations/collector-store.d.ts.map +1 -1
  235. package/dist/types/native-conversations/collector-sync-requests.d.ts.map +1 -1
  236. package/dist/types/native-conversations/collector.d.ts.map +1 -1
  237. package/dist/types/native-conversations/contracts.d.ts.map +1 -1
  238. package/dist/types/native-conversations/database.d.ts.map +1 -1
  239. package/dist/types/native-conversations/discovery.d.ts.map +1 -1
  240. package/dist/types/native-conversations/git-assets.d.ts +32 -0
  241. package/dist/types/native-conversations/git-assets.d.ts.map +1 -0
  242. package/dist/types/native-conversations/history.d.ts +1 -0
  243. package/dist/types/native-conversations/history.d.ts.map +1 -1
  244. package/dist/types/native-conversations/index.d.ts +2 -0
  245. package/dist/types/native-conversations/index.d.ts.map +1 -1
  246. package/dist/types/native-conversations/location.d.ts.map +1 -1
  247. package/dist/types/native-conversations/openclaw-cold-archive.d.ts.map +1 -1
  248. package/dist/types/native-conversations/openclaw-database.d.ts.map +1 -1
  249. package/dist/types/native-conversations/readiness.d.ts.map +1 -1
  250. package/dist/types/native-conversations/selection.d.ts +32 -0
  251. package/dist/types/native-conversations/selection.d.ts.map +1 -0
  252. package/dist/types/native-conversations/source-locations.d.ts.map +1 -1
  253. package/dist/types/native-conversations/supervisor.d.ts.map +1 -1
  254. package/dist/types/native-conversations/titles.d.ts.map +1 -1
  255. package/dist/types/native-harness-experiment-attempt.d.ts.map +1 -1
  256. package/dist/types/preferences.d.ts +22 -22
  257. package/dist/types/preferences.d.ts.map +1 -1
  258. package/dist/types/prepared-process-isolation.d.ts +5 -0
  259. package/dist/types/prepared-process-isolation.d.ts.map +1 -0
  260. package/dist/types/profile-evaluation-comparisons.d.ts +18 -18
  261. package/dist/types/profile-evaluation-comparisons.d.ts.map +1 -1
  262. package/dist/types/profile-evaluation-execution.d.ts.map +1 -1
  263. package/dist/types/profile-evaluation-reports.d.ts +2 -2
  264. package/dist/types/profile-evaluation-reports.d.ts.map +1 -1
  265. package/dist/types/profile-evaluation-suites.d.ts.map +1 -1
  266. package/dist/types/profile-evaluation-target.d.ts.map +1 -1
  267. package/dist/types/profile-evaluations.d.ts +15 -15
  268. package/dist/types/profile-evaluations.d.ts.map +1 -1
  269. package/dist/types/profile-external-evaluation.d.ts +84 -84
  270. package/dist/types/profile-external-evaluation.d.ts.map +1 -1
  271. package/dist/types/profile-source-candidate.d.ts.map +1 -1
  272. package/dist/types/review-conformance.d.ts +58 -58
  273. package/dist/types/review-conformance.d.ts.map +1 -1
  274. package/dist/types/rewards.d.ts +110 -101
  275. package/dist/types/rewards.d.ts.map +1 -1
  276. package/dist/types/rollouts.d.ts +16 -16
  277. package/dist/types/rollouts.d.ts.map +1 -1
  278. package/dist/types/runs.d.ts +22 -22
  279. package/dist/types/runs.d.ts.map +1 -1
  280. package/dist/types/sql-execution-contract.d.ts +3 -3
  281. package/dist/types/sql-execution-contract.d.ts.map +1 -1
  282. package/dist/types/sql-execution-engine.d.ts.map +1 -1
  283. package/dist/types/sql-execution-node.d.ts.map +1 -1
  284. package/dist/types/sql-execution-process-entry.d.ts.map +1 -1
  285. package/dist/types/task-schema-validation.d.ts.map +1 -1
  286. package/dist/types/task-schema.d.ts.map +1 -1
  287. package/dist/types/task-value-validator.d.ts.map +1 -1
  288. package/dist/types/taskset-run-contract.d.ts +26 -26
  289. package/dist/types/taskset-run-contract.d.ts.map +1 -1
  290. package/dist/types/tasksets.d.ts +89 -69
  291. package/dist/types/tasksets.d.ts.map +1 -1
  292. package/dist/types/telemetry/index.d.ts.map +1 -1
  293. package/dist/types/telemetry-analysis.d.ts +6 -6
  294. package/dist/types/telemetry-analysis.d.ts.map +1 -1
  295. package/dist/types/telemetry-bundle.d.ts +42 -42
  296. package/dist/types/telemetry-bundle.d.ts.map +1 -1
  297. package/dist/types/telemetry-catalog.d.ts +67 -67
  298. package/dist/types/telemetry-catalog.d.ts.map +1 -1
  299. package/dist/types/telemetry.d.ts +44 -44
  300. package/dist/types/telemetry.d.ts.map +1 -1
  301. package/package.json +6 -1
  302. package/schemas/learning/v1/binding.schema.json +8 -0
  303. package/schemas/learning/v1/command-request.schema.json +12 -0
  304. package/schemas/learning/v1/decision.schema.json +5 -1
  305. package/schemas/learning/v1/definition.schema.json +4 -0
  306. package/schemas/learning/v1/draft.schema.json +8 -0
  307. package/schemas/learning/v1/evidence.schema.json +4 -0
  308. package/schemas/learning/v1/example-submission.schema.json +4 -0
  309. package/schemas/learning/v1/grade.schema.json +5 -1
  310. package/schemas/learning/v1/package.schema.json +117 -93
  311. package/schemas/learning/v1/reward_check.schema.json +2 -1
@@ -12,7 +12,7 @@ export class CollectorSourceCache {
12
12
  }
13
13
  selection(connection, until, revision) {
14
14
  return contentHash([connection.source, connection.projectId, connection.teamId,
15
- connection.apiBaseUrl, connection.account ?? null, connection.since, until, revision]);
15
+ connection.apiBaseUrl, connection.account ?? null, connection.since, connection.selectedSessionKeys ?? null, until, revision]);
16
16
  }
17
17
  read(connection, until, sessionKey, revision) {
18
18
  const row = this.store.database.prepare("SELECT value FROM source_read_cache WHERE connection_id=? AND session_key=? AND selection_hash=?").get(connection.id, sessionKey, this.selection(connection, until, revision));
@@ -61,6 +61,20 @@ export class CollectorStore {
61
61
  this.database.exec("COMMIT");
62
62
  return;
63
63
  }
64
+ if (prior && JSON.stringify(prior.selectedSessionKeys) !== JSON.stringify(connection.selectedSessionKeys)) {
65
+ const owner = JSON.parse(this.setting("owner") || "{}");
66
+ if (owner.pid) {
67
+ let alive = true;
68
+ try {
69
+ process.kill(owner.pid, 0);
70
+ }
71
+ catch (error) {
72
+ alive = error.code !== "ESRCH";
73
+ }
74
+ if (alive)
75
+ throw new Error("Cancel or finish the running import before changing its conversation selection.");
76
+ }
77
+ }
64
78
  const identityChanged = !!prior &&
65
79
  (prior.source.instanceId !== connection.source.instanceId ||
66
80
  prior.projectId !== connection.projectId ||
@@ -69,7 +83,8 @@ export class CollectorStore {
69
83
  prior.account !== connection.account);
70
84
  if (identityChanged)
71
85
  connection = { ...connection, destinations: undefined };
72
- if (prior && (identityChanged || prior.since !== connection.since)) {
86
+ if (prior && (identityChanged || prior.since !== connection.since ||
87
+ JSON.stringify(prior.selectedSessionKeys) !== JSON.stringify(connection.selectedSessionKeys))) {
73
88
  this.database.prepare("DELETE FROM settings WHERE key=?").run(`coverage:${connection.id}`);
74
89
  this.database.prepare("DELETE FROM coverage_sessions WHERE connection_id=?").run(connection.id);
75
90
  // Scope changes fence queued evidence too: do not upload a wider old
@@ -81,7 +96,16 @@ export class CollectorStore {
81
96
  this.database.prepare("DELETE FROM settings WHERE key=?").run(`syncAcknowledged:${connection.id}`);
82
97
  connection = { ...connection, completedSyncRevision: 0 };
83
98
  this.error(connection.id, null);
84
- for (const table of ["source_scans", "checkpoints", "pending"])
99
+ if (!identityChanged && prior.since === connection.since) {
100
+ // Preserve acknowledged boundaries when adding conversations, but
101
+ // reacquire every queued boundary whose snapshot is being discarded.
102
+ this.database.prepare(`DELETE FROM checkpoints WHERE connection_id=? AND EXISTS (
103
+ SELECT 1 FROM pending p, json_each(p.payload,'$.boundaryIds') b
104
+ WHERE p.connection_id=checkpoints.connection_id
105
+ AND json_extract(p.payload,'$.sessionKey')=checkpoints.session_key
106
+ AND b.value=checkpoints.boundary_id)`).run(connection.id);
107
+ }
108
+ for (const table of identityChanged || prior.since !== connection.since ? ["source_scans", "checkpoints", "pending"] : ["source_scans", "pending"])
85
109
  this.database
86
110
  .prepare(`DELETE FROM ${table} WHERE connection_id=?`)
87
111
  .run(connection.id);
@@ -270,6 +294,7 @@ export class CollectorStore {
270
294
  .get(String(row.id))?.bytes ?? 0),
271
295
  lastAdmissionAt: this.setting(`lastAdmission:${row.id}`),
272
296
  since: config.since,
297
+ selectedConversations: config.selectedSessionKeys?.length ?? null,
273
298
  schedule,
274
299
  nextRunAt: schedule && config.state === "active" ? nextScheduledSync(schedule) : null,
275
300
  lastSuccessfulSyncAt: this.setting(`lastSuccess:${row.id}`),
@@ -36,7 +36,7 @@ export async function runCollector(input) {
36
36
  }
37
37
  }
38
38
  const now = new Date();
39
- selected = store.connections().filter(connection => connection.state !== "disconnected" &&
39
+ selected = store.connections().filter(connection => connection.state !== "disconnected" && connection.selectedSessionKeys?.length !== 0 &&
40
40
  (!input.connectionIds || input.connectionIds.includes(connection.id)) &&
41
41
  (input.trigger !== "scheduled" || (connection.state === "active" && scheduledSyncDue(store.schedule(connection.id), store.setting(`scheduledMinute:${connection.id}`), now))));
42
42
  if (input.trigger === "scheduled")
@@ -173,13 +173,14 @@ export async function runCollector(input) {
173
173
  for (let pass = 0; pass < 3; pass++) {
174
174
  await check();
175
175
  const revision = connection.revision, requested = connection.requestedSyncRevision ?? 0;
176
+ const selection = JSON.stringify(connection.selectedSessionKeys);
176
177
  phase = "source";
177
178
  new CollectorSourceCache(store).seed(connection, until, store.coverage.manifest(connection.id));
178
179
  store.coverage.begin(connection, `${nonce}-${pass}`, run.startedAt, until);
179
180
  const checkAcquisition = async () => {
180
181
  await check();
181
182
  phase = "source";
182
- if (connection.revision !== revision)
183
+ if (connection.revision !== revision || JSON.stringify(connection.selectedSessionKeys) !== selection)
183
184
  throw new CollectorScopeChangedError("Source settings changed during acquisition.");
184
185
  };
185
186
  try {
@@ -193,7 +194,7 @@ export async function runCollector(input) {
193
194
  }
194
195
  errors.set(connection.id, "source", null);
195
196
  await drain();
196
- await input.transport.publishCoverage(connection, store.coverage.finish(connection.id, true), signal);
197
+ await input.transport.publishCoverage(connection, store.coverage.finish(connection.id, connection.selectedSessionKeys === undefined), signal);
197
198
  connection = retained(connection);
198
199
  if (connection.revision !== revision) {
199
200
  if (pass === 2)
@@ -0,0 +1,61 @@
1
+ import { execFile } from "node:child_process";
2
+ import { realpath } from "node:fs/promises";
3
+ import { isAbsolute } from "node:path";
4
+ import { promisify } from "node:util";
5
+ import { ConnectedRepositoryContextSchema } from "../connected-evidence/contracts.js";
6
+ import { ConnectedGitFileProofSchema, verifyConnectedGitFileProof } from "../connected-evidence/git-file-proof.js";
7
+ const execute = promisify(execFile);
8
+ /** Capture only recorded Git objects. A missing historical object is an explicit
9
+ * gap; this operation never reads the current worktree or fetches another repo. */
10
+ export async function captureNativeGitAssetProofs(input) {
11
+ const context = ConnectedRepositoryContextSchema.parse(input.repositoryContext);
12
+ if (!isAbsolute(input.repositoryPath) || !input.paths.length || input.paths.length > 100
13
+ || new Set(input.paths).size !== input.paths.length)
14
+ throw new Error("native_git_asset_selection_invalid");
15
+ // Validate selections before invoking Git, including paths prohibited by the
16
+ // source asset policy. The remaining fields are filled from immutable objects.
17
+ for (const path of input.paths)
18
+ ConnectedGitFileProofSchema.shape.path.parse(path);
19
+ const repository = await realpath(input.repositoryPath);
20
+ const read = async (args, maxBuffer = 2 * 1024 * 1024) => {
21
+ input.signal?.throwIfAborted();
22
+ const result = await execute("git", ["-C", repository, ...args], {
23
+ encoding: "buffer", timeout: 15_000, maxBuffer, signal: input.signal,
24
+ });
25
+ return result.stdout;
26
+ };
27
+ const objectId = async (ref) => {
28
+ const hash = (await read(["rev-parse", "--verify", ref], 1_024)).toString("ascii").trim();
29
+ if (!new RegExp(`^[a-f0-9]{${context.commitHash.length}}$`).test(hash))
30
+ throw new Error("native_git_object_identity_invalid");
31
+ return hash;
32
+ };
33
+ const commit = await read(["cat-file", "commit", context.commitHash], 256 * 1024);
34
+ const cache = new Map();
35
+ let totalBytes = 0;
36
+ const proofs = [];
37
+ for (const path of input.paths) {
38
+ const directories = ["", ...path.split("/").slice(0, -1).map((_, index, parts) => parts.slice(0, index + 1).join("/"))];
39
+ const trees = [];
40
+ for (const directory of directories) {
41
+ const ref = directory ? `${context.commitHash}:${directory}` : `${context.commitHash}^{tree}`;
42
+ let tree = cache.get(ref);
43
+ if (!tree) {
44
+ const hash = await objectId(ref);
45
+ tree = { hash, base64: (await read(["cat-file", "tree", hash])).toString("base64") };
46
+ cache.set(ref, tree);
47
+ }
48
+ trees.push(tree);
49
+ }
50
+ const blob = await objectId(`${context.commitHash}:${path}`);
51
+ const proof = ConnectedGitFileProofSchema.parse({ schemaVersion: "openpond.connectedGitFileProof.v1", path,
52
+ commit: { hash: context.commitHash, base64: commit.toString("base64") }, trees,
53
+ contentsBase64: (await read(["cat-file", "blob", blob])).toString("base64") });
54
+ const verified = verifyConnectedGitFileProof(context, proof);
55
+ totalBytes += Buffer.byteLength(JSON.stringify(proof));
56
+ if (totalBytes > 16 * 1024 * 1024)
57
+ throw new Error("native_git_asset_capture_limit");
58
+ proofs.push({ proof, verified });
59
+ }
60
+ return proofs;
61
+ }
@@ -293,6 +293,13 @@ export async function readSession(source, session, input = {}) {
293
293
  const graph = claudeGraph(connectedJsonLines(file));
294
294
  if (graph.sessionId !== session.nativeSessionId)
295
295
  throw new Error("Native session changed identity.");
296
+ if (input.latestBranch) {
297
+ if (input.branchLeafId || input.expectedBranchRevision || input.branchAnchor)
298
+ throw new Error("Choose either the latest conversation or an explicit branch.");
299
+ // Desktop inspection follows the native conversation. Imports keep their
300
+ // existing explicit branch authority and never enable this option.
301
+ files = [{ ...file, text: graph.select(graph.latestLeafId()).chain.map(row => JSON.stringify(row)).join("\n") + "\n" }];
302
+ }
296
303
  if (input.branchAnchor) {
297
304
  if (input.branchLeafId || input.expectedBranchRevision)
298
305
  throw new Error("Choose either a frozen branch snapshot or a followed branch anchor.");
@@ -2,6 +2,7 @@
2
2
  export * from "./contracts.js";
3
3
  export * from "./discovery.js";
4
4
  export * from "./history.js";
5
+ export * from "./selection.js";
5
6
  export * from "./collector-contracts.js";
6
7
  export * from "./collector-store.js";
7
8
  export * from "./collector.js";
@@ -10,3 +11,4 @@ export * from "./location.js";
10
11
  export * from "./collector-branches.js";
11
12
  export * from "./collector-destinations.js";
12
13
  export * from "./collector-schedule.js";
14
+ export { captureNativeGitAssetProofs } from "./git-assets.js";
@@ -0,0 +1,57 @@
1
+ import { contentHash } from "@openpond/harness";
2
+ import { z } from "zod";
3
+ import { listSessions } from "./history.js";
4
+ export const NativeUploadSelectionSchema = z.object({
5
+ sourceInstanceId: z.string().min(1).max(500),
6
+ sessionKeys: z.array(z.string().regex(/^[a-f0-9]{64}$/)).min(1).max(10_000),
7
+ }).strict().refine(value => new Set(value.sessionKeys).size === value.sessionKeys.length, "Conversation selection contains duplicates.");
8
+ /** Includes the source path so duplicate native IDs cannot select a sibling file. */
9
+ export function nativeSessionSelectionKey(session) {
10
+ return contentHash(JSON.stringify([session.path, session.nativeSessionId]));
11
+ }
12
+ export async function nativeUploadInventory(source) {
13
+ if (!source.available || !source.capabilities.history)
14
+ throw new Error("The selected conversation source is unavailable.");
15
+ const items = [];
16
+ let cursor;
17
+ const seen = new Set();
18
+ do {
19
+ const page = await listSessions(source, { cursor, limit: 100 });
20
+ items.push(...page.items);
21
+ if (items.length > 10_000)
22
+ throw new Error("Choose a source with no more than 10,000 conversations.");
23
+ cursor = page.nextCursor ?? undefined;
24
+ if (cursor && seen.has(cursor))
25
+ throw new Error("Conversation listing did not advance. Refresh the source.");
26
+ if (cursor)
27
+ seen.add(cursor);
28
+ } while (cursor);
29
+ return items;
30
+ }
31
+ export async function validateNativeUploadSelection(source, raw) {
32
+ const selection = NativeUploadSelectionSchema.parse(raw);
33
+ if (selection.sourceInstanceId !== source.instanceId)
34
+ throw new Error("Conversation selection belongs to another source installation.");
35
+ const available = new Set((await nativeUploadInventory(source)).map(nativeSessionSelectionKey));
36
+ if (selection.sessionKeys.some(key => !available.has(key)))
37
+ throw new Error("A selected conversation is no longer available. Refresh and select it again.");
38
+ return selection;
39
+ }
40
+ export function nativeUploadConversationPage(connection, inventory, input) {
41
+ const query = (input.query ?? "").trim().toLocaleLowerCase(), range = input.range ?? "all", offset = input.offset ?? 0;
42
+ if (query.length > 500 || !["day", "week", "all"].includes(range) || !Number.isInteger(offset) || offset < 0 || offset > 10_000)
43
+ throw new Error("Invalid conversation search or page.");
44
+ const since = range === "all" ? 0 : Date.now() - (range === "day" ? 1 : 7) * 86400000;
45
+ const items = inventory.filter(item => Date.parse(item.updatedAt) >= since &&
46
+ (!query || [item.title, item.cwd, item.nativeSessionId].some(text => text?.toLocaleLowerCase().includes(query))))
47
+ .sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
48
+ const approved = connection.selectedSessionKeys ? new Set(connection.selectedSessionKeys) : null;
49
+ return {
50
+ total: items.length, nextOffset: offset + 50 < items.length ? offset + 50 : null,
51
+ items: items.slice(offset, offset + 50).map(item => ({
52
+ key: nativeSessionSelectionKey(item), title: item.title, cwd: item.cwd,
53
+ nativeSessionId: item.nativeSessionId, updatedAt: item.updatedAt, issue: item.issue ?? null,
54
+ approved: approved === null || approved.has(nativeSessionSelectionKey(item)),
55
+ })),
56
+ };
57
+ }
@@ -164,6 +164,8 @@ export async function setCollectorSchedule(input, connectionId, schedule) {
164
164
  const connection = store.connections().find(item => item.id === connectionId);
165
165
  if (!connection || (schedule && connection.state === "disconnected"))
166
166
  throw new Error("Select a connected source before scheduling imports.");
167
+ if (schedule && connection.selectedSessionKeys?.length === 0)
168
+ throw new Error("Choose conversations to upload before enabling continual imports.");
167
169
  const owner = store.setting("scheduleOwner");
168
170
  if (owner) {
169
171
  const { pid } = JSON.parse(owner);
@@ -0,0 +1,131 @@
1
+ /** Staged by the private verifier owner. Untrusted policy programs run with no
2
+ * capabilities as a different UID, outside the sealed private verifier tree.
3
+ * The parent must assess returned behavior; an exit code is never correctness. */
4
+ export const PREPARED_PROCESS_ISOLATION_SOURCE = String.raw `
5
+ import fs from "node:fs/promises";
6
+ import os from "node:os";
7
+ import path from "node:path";
8
+ import { fileURLToPath } from "node:url";
9
+ import { randomInt } from "node:crypto";
10
+
11
+ const MAX_BYTES = 15 * 1024 * 1024, MAX_OUTPUT = 1024 * 1024;
12
+ const usedUsers = new Set();
13
+ const safePath = value => typeof value === "string" && value.length > 0 && value.length <= 2000
14
+ && !value.startsWith("/") && !/[\\\x00-\x1f\x7f]/.test(value)
15
+ && value.split("/").every(part => part && part !== "." && part !== ".." && !part.startsWith(".env"));
16
+
17
+ /** files contain only public original/policy bytes and a public invocation
18
+ * adapter. Never stage independent assertions, expected answers or checkers. */
19
+ export async function runPolicyProgram(input) {
20
+ const privateRoot = path.dirname(fileURLToPath(import.meta.url));
21
+ if (process.getuid?.() !== 0 || !path.basename(privateRoot).startsWith(".openpond-reward-verifier-"))
22
+ throw new Error("policy_process_isolation_runtime_unavailable");
23
+ if (!Array.isArray(input.files) || input.files.length < 1 || input.files.length > 100
24
+ || !safePath(input.entrypoint) || !input.files.some(file => file.path === input.entrypoint)
25
+ || !Number.isSafeInteger(input.timeoutMs) || input.timeoutMs < 1 || input.timeoutMs > 60000
26
+ || !Array.isArray(input.args ?? []) || (input.args ?? []).length > 100
27
+ || (input.args ?? []).some(arg => typeof arg !== "string" || arg.length > 2000 || arg.includes("\0")))
28
+ throw new Error("policy_process_isolation_input_invalid");
29
+ let total = 0;
30
+ const paths = new Set();
31
+ const files = input.files.map(file => {
32
+ if (!safePath(file.path) || paths.has(file.path) || typeof file.base64 !== "string")
33
+ throw new Error("policy_process_isolation_file_invalid");
34
+ paths.add(file.path);
35
+ const bytes = Buffer.from(file.base64, "base64");
36
+ if (bytes.toString("base64") !== file.base64) throw new Error("policy_process_isolation_file_invalid");
37
+ total += bytes.length;
38
+ if (total > MAX_BYTES) throw new Error("policy_process_isolation_file_limit");
39
+ return { path: file.path, bytes };
40
+ });
41
+ // Directory access seals request JSON, checker modules, helper source and
42
+ // private artifacts before any untrusted program can be spawned.
43
+ await fs.chmod(privateRoot, 0o700);
44
+ const stat = await fs.stat(privateRoot);
45
+ if (stat.uid !== 0 || (stat.mode & 0o777) !== 0o700) throw new Error("policy_process_private_tree_not_sealed");
46
+ for (const executable of ["/usr/bin/setsid", "/usr/bin/setpriv", "/usr/local/bin/bun"])
47
+ await fs.access(executable, 1);
48
+ const directory = await fs.mkdtemp(path.join(os.tmpdir(), "openpond-policy-"));
49
+ let user;
50
+ do { user = randomInt(1000000, 2000000); } while (usedUsers.has(user));
51
+ usedUsers.add(user);
52
+ let child, timer, timedOut = false;
53
+ const kill = () => {
54
+ if (!child) return;
55
+ try { process.kill(-child.pid, "SIGKILL"); } catch {}
56
+ try { child.kill("SIGKILL"); } catch {}
57
+ };
58
+ try {
59
+ await fs.chmod(directory, 0o700);
60
+ await fs.chown(directory, user, user);
61
+ for (const file of files) {
62
+ const target = path.join(directory, file.path);
63
+ const parent = path.dirname(target);
64
+ await fs.mkdir(parent, { recursive: true, mode: 0o700 });
65
+ let current = parent;
66
+ while (current !== directory) {
67
+ await fs.chmod(current, 0o700); await fs.chown(current, user, user);
68
+ current = path.dirname(current);
69
+ }
70
+ await fs.writeFile(target, file.bytes, { mode: 0o600, flag: "wx" });
71
+ await fs.chown(target, user, user);
72
+ }
73
+ child = Bun.spawn(["/usr/bin/setsid", "/usr/bin/setpriv", "--reuid=" + user, "--regid=" + user, "--clear-groups",
74
+ "--no-new-privs", "--bounding-set=-all", "--inh-caps=-all", "--ambient-caps=-all",
75
+ "/usr/local/bin/bun", path.join(directory, input.entrypoint), ...(input.args ?? [])], {
76
+ cwd: directory, env: { PATH: "/usr/local/bin:/usr/bin:/bin", TMPDIR: directory }, stdout: "pipe", stderr: "pipe", stdin: "ignore",
77
+ });
78
+ timer = setTimeout(() => { timedOut = true; kill(); }, input.timeoutMs);
79
+ const read = async stream => {
80
+ const reader = stream.getReader(), chunks = [];
81
+ let bytes = 0;
82
+ try {
83
+ while (true) {
84
+ const item = await reader.read(); if (item.done) break;
85
+ bytes += item.value.byteLength;
86
+ if (bytes > MAX_OUTPUT) { kill(); throw new Error("policy_process_output_limit"); }
87
+ chunks.push(item.value);
88
+ }
89
+ return new TextDecoder("utf8", { fatal: true }).decode(Buffer.concat(chunks));
90
+ } finally { await reader.cancel(); reader.releaseLock(); }
91
+ };
92
+ const [stdout, stderr, exitCode] = await Promise.all([read(child.stdout), read(child.stderr), child.exited]);
93
+ return { stdout, stderr, exitCode, timedOut, isolation: { uid: user, gid: user, privateTreeSealed: true } };
94
+ } finally {
95
+ if (timer) clearTimeout(timer);
96
+ kill();
97
+ // A policy child can call setsid and escape its initial process group.
98
+ // Drain every process with this invocation's unique real UID before the
99
+ // next call; namespaces cannot grant a different outside UID or privilege.
100
+ try { await drainPolicyProcesses(user); }
101
+ finally { await fs.rm(directory, { recursive: true, force: true }); }
102
+ }
103
+ }
104
+
105
+ async function drainPolicyProcesses(user) {
106
+ const deadline = Date.now() + 2000;
107
+ let empty = 0;
108
+ while (Date.now() < deadline) {
109
+ const entries = (await fs.readdir("/proc")).filter(value => /^\d+$/.test(value));
110
+ if (entries.length > 10000) throw new Error("policy_process_inventory_limit");
111
+ let owned = 0;
112
+ for (const entry of entries) {
113
+ let status;
114
+ try { status = await fs.readFile("/proc/" + entry + "/status", "utf8"); }
115
+ catch (error) { if (["ENOENT", "ESRCH"].includes(error.code)) continue; throw error; }
116
+ const ids = /^Uid:\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/m.exec(status);
117
+ if (ids && ids.slice(1).some(value => Number(value) === user)) {
118
+ // Zombies cannot fork, inspect a subsequent invocation or hold files.
119
+ if (/^State:\s+Z/m.test(status)) continue;
120
+ owned++;
121
+ try { process.kill(Number(entry), "SIGKILL"); }
122
+ catch (error) { if (error.code !== "ESRCH") throw error; }
123
+ }
124
+ }
125
+ empty = owned === 0 ? empty + 1 : 0;
126
+ if (empty >= 2) return;
127
+ await new Promise(resolve => setTimeout(resolve, 20));
128
+ }
129
+ throw new Error("policy_process_cleanup_unconfirmed");
130
+ }
131
+ `;
package/dist/rewards.js CHANGED
@@ -4,7 +4,7 @@ import { ImmutableAssetRefSchema, ImmutableReleaseRefSchema, ReleaseHashSchema,
4
4
  import { gradeEvidence, GraderEvidenceSchema } from "./graders.js";
5
5
  import { CustomVerifierGraderSpecSchema, DeterministicGraderSpecSchema, GraderSpecSchema, HumanGraderSpecSchema, ModelJudgeGraderSpecSchema } from "./tasksets.js";
6
6
  import { assertBoundedTaskJson, validateTaskSchema } from "./task-schema.js";
7
- const bindingFields = { id: true, version: true, weight: true, hardGate: true, rewardEligible: true, privileged: true };
7
+ const bindingFields = { taskIds: true, id: true, version: true, weight: true, hardGate: true, rewardEligible: true, privileged: true };
8
8
  export const FeedbackKeySchema = z.string().regex(/^[a-z][a-z0-9_]{0,79}$/);
9
9
  export function feedbackKeyForReward(reward) {
10
10
  return reward.feedbackKey ?? `reward_${contentHash(reward.id).slice(0, 24)}`;
@@ -49,6 +49,7 @@ export const RewardNormalizationSchema = z.discriminatedUnion("kind", [
49
49
  ]);
50
50
  export const RewardBindingSourceSchema = z.object({
51
51
  graderId: ReleaseIdSchema,
52
+ taskIds: z.array(ReleaseIdSchema).min(1).max(10_000).refine(ids => new Set(ids).size === ids.length, "Task scope must be unique.").optional(),
52
53
  reward: RewardReleaseRefSchema,
53
54
  role: z.enum(["training", "evaluation"]),
54
55
  normalization: RewardNormalizationSchema,
@@ -87,7 +88,7 @@ export const BoundRewardResultSchema = z.object({
87
88
  graderId: ReleaseIdSchema,
88
89
  reward: RewardReleaseRefSchema,
89
90
  role: z.enum(["training", "evaluation"]),
90
- status: z.enum(["scored", "pending", "unavailable", "failed"]),
91
+ status: z.enum(["scored", "pending", "unavailable", "failed", "not_applicable"]),
91
92
  rawScore: z.number().finite().nullable(),
92
93
  normalizedScore: z.number().min(0).max(1).nullable(),
93
94
  passed: z.boolean().nullable(),
@@ -99,6 +100,7 @@ export const RewardCompositionContentSchema = z.object({
99
100
  schemaVersion: z.literal("openpond.rewardComposition.v1"),
100
101
  binding: RewardReleaseRefSchema,
101
102
  taskHash: ReleaseHashSchema,
103
+ taskId: ReleaseIdSchema.optional(),
102
104
  outputHash: ReleaseHashSchema,
103
105
  results: z.array(BoundRewardResultSchema).max(100),
104
106
  training: z.object({ status: z.enum(["scored", "pending", "unscorable", "not_configured"]), score: z.number().min(0).max(1).nullable(), passed: z.boolean().nullable() }).strict(),
@@ -149,6 +151,10 @@ export async function executeRewardBinding(input) {
149
151
  for (const { source, reward } of resolved) {
150
152
  input.signal?.throwIfAborted();
151
153
  const result = { graderId: source.graderId, reward: source.reward, role: source.role, status: "unavailable", rawScore: null, normalizedScore: null, passed: null, evidenceHashes: [], message: null };
154
+ if (source.taskIds && !source.taskIds.includes(input.task.id)) {
155
+ results.push({ ...result, status: "not_applicable" });
156
+ continue;
157
+ }
152
158
  try {
153
159
  if (reward.implementation.kind === "human") {
154
160
  result.status = "pending";
@@ -183,11 +189,13 @@ export async function executeRewardBinding(input) {
183
189
  }
184
190
  results.push(BoundRewardResultSchema.parse(result));
185
191
  }
186
- return composeBoundRewards({ binding: input.binding, taskHash: contentHash(input.task), outputHash: contentHash(input.evidence), results });
192
+ return composeBoundRewards({ binding: input.binding, ...(input.binding.sources.some(source => source.taskIds) ? { taskId: input.task.id } : {}), taskHash: contentHash(input.task), outputHash: contentHash(input.evidence), results });
187
193
  }
188
194
  export function composeBoundRewards(input) {
189
195
  const binding = RewardBindingSchema.parse(input.binding);
190
196
  assertRewardHash(binding);
197
+ if (binding.sources.some(source => source.taskIds) && !input.taskId)
198
+ throw new LearningDomainError("reward_task_scope_missing");
191
199
  const results = input.results.map((result) => BoundRewardResultSchema.parse(result));
192
200
  if (results.length !== binding.sources.length || new Set(results.map((result) => result.graderId)).size !== results.length)
193
201
  throw new LearningDomainError("reward_result_set_incomplete");
@@ -195,6 +203,9 @@ export function composeBoundRewards(input) {
195
203
  const result = results.find((candidate) => candidate.graderId === source.graderId);
196
204
  if (!result || contentHash(result.reward) !== contentHash(source.reward) || result.role !== source.role)
197
205
  throw new LearningDomainError("reward_result_binding_mismatch");
206
+ const applicable = !source.taskIds || source.taskIds.includes(input.taskId);
207
+ if (applicable === (result.status === "not_applicable") || !applicable && (result.graderEvidence || result.evidenceHashes.length || result.message !== null))
208
+ throw new LearningDomainError("reward_result_task_scope_mismatch");
198
209
  if (result.graderEvidence) {
199
210
  const { contentHash: evidenceHash, ...body } = result.graderEvidence;
200
211
  if (contentHash(body) !== evidenceHash || !result.evidenceHashes.includes(evidenceHash)
@@ -219,6 +230,7 @@ export function composeBoundRewards(input) {
219
230
  schemaVersion: "openpond.rewardComposition.v1",
220
231
  binding: { id: binding.id, revision: binding.revision, contentHash: binding.contentHash },
221
232
  taskHash: input.taskHash,
233
+ ...(input.taskId ? { taskId: input.taskId } : {}),
222
234
  outputHash: input.outputHash,
223
235
  results,
224
236
  training: aggregate("training"),
@@ -226,7 +238,7 @@ export function composeBoundRewards(input) {
226
238
  });
227
239
  return RewardCompositionSchema.parse({ ...content, contentHash: contentHash(content) });
228
240
  function aggregate(role) {
229
- const selected = binding.sources.filter((source) => source.role === role).map((source) => ({ source, result: results.find((candidate) => candidate.graderId === source.graderId) }));
241
+ const selected = binding.sources.filter((source) => source.role === role && (!source.taskIds || source.taskIds.includes(input.taskId))).map((source) => ({ source, result: results.find((candidate) => candidate.graderId === source.graderId) }));
230
242
  if (!selected.length)
231
243
  return { status: "not_configured", score: null, passed: null };
232
244
  if (selected.some(({ source, result }) => source.required && result.status !== "scored" && result.status !== "pending"))
@@ -250,5 +262,5 @@ function withoutRewardHash(value) { const { contentHash: _hash, ...content } = v
250
262
  function compileSource(source, reward) {
251
263
  if (reward.implementation.kind === "learned_model")
252
264
  throw new LearningDomainError("learned_reward_requires_model_execution_adapter");
253
- return GraderSpecSchema.parse({ ...reward.implementation, id: source.graderId, version: String(reward.revision), weight: source.weight, hardGate: source.hardGate, rewardEligible: source.role === "training", privileged: source.privileged });
265
+ return GraderSpecSchema.parse({ ...reward.implementation, ...(source.taskIds ? { taskIds: source.taskIds } : {}), id: source.graderId, version: String(reward.revision), weight: source.weight, hardGate: source.hardGate, rewardEligible: source.role === "training", privileged: source.privileged });
254
266
  }
package/dist/tasksets.js CHANGED
@@ -7,6 +7,7 @@ export const RequiredOutputContractSchema = z.object({
7
7
  path: z.string().trim().min(1).max(2_000).refine(safeRelativePath),
8
8
  mediaType: z.string().trim().min(1).max(200),
9
9
  schemaRef: ImmutableAssetRefSchema.nullable().default(null),
10
+ submissionMode: z.literal("structured_json").optional(),
10
11
  maxBytes: z.number().int().positive().max(250_000_000).nullable().default(null),
11
12
  metadata: MetadataSchema,
12
13
  }).strict();
@@ -28,6 +29,7 @@ export const EnvironmentContractSchema = z.object({
28
29
  }).strict();
29
30
  const GraderBaseSchema = z.object({
30
31
  id: ReleaseIdSchema,
32
+ taskIds: z.array(ReleaseIdSchema).min(1).max(10_000).refine(ids => new Set(ids).size === ids.length, "Grader task IDs must be unique.").optional(),
31
33
  version: z.string().trim().min(1).max(100),
32
34
  weight: z.number().nonnegative().max(1_000).default(1),
33
35
  hardGate: z.boolean().default(false),
@@ -120,6 +122,11 @@ export function validateTasksetRelease(input) {
120
122
  path: "environmentRelease",
121
123
  });
122
124
  }
125
+ const taskIds = new Set(taskset.tasks.map(task => task.id));
126
+ for (const grader of taskset.graders)
127
+ if (grader.taskIds?.some(id => !taskIds.has(id))) {
128
+ issues.push({ code: "grader_task_missing", severity: "error", message: `Grader ${grader.id} refers to a task outside this release.`, path: "graders" });
129
+ }
123
130
  const clusterSplits = new Map();
124
131
  for (const task of taskset.tasks) {
125
132
  if (taskset.metrics?.aggregation === "weighted_mean" && !Object.hasOwn(taskset.metrics.taskWeights, task.id)) {
@@ -1 +1 @@
1
- {"version":3,"file":"artifact-verification.d.ts","sourceRoot":"","sources":["../../../../src/artifact-verification.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,OAAO,EAGL,KAAK,gBAAgB,EAGrB,KAAK,sBAAsB,EAC5B,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAE5D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACtC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,MAAM,EAAE,WAAW,GAAG,QAAQ,CAAC;IAC/B,WAAW,CAAC,EAAE,eAAe,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACpD,YAAY,CAAC,EAAE,eAAe,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACrD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,QAAQ,GAAG,WAAW,GAAG,aAAa,GAAG,IAAI,CAAC;IAC7D,YAAY,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAChD,eAAe,EAAE,sBAAsB,EAAE,CAAC;IAC1C,kBAAkB,EAAE,iBAAiB,EAAE,CAAC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,GAAG,gBAAgB,CAwEnB;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,eAAe,EAAE,sBAAsB,EAAE,CAAC;IAC1C,QAAQ,EAAE,gBAAgB,CAAC;CAC5B,GAAG,sBAAsB,EAAE,CAqC3B"}
1
+ {"version":3,"file":"artifact-verification.d.ts","sourceRoot":"","sources":["../../src/artifact-verification.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,OAAO,EAGL,KAAK,gBAAgB,EAGrB,KAAK,sBAAsB,EAC5B,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAE5D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACtC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,MAAM,EAAE,WAAW,GAAG,QAAQ,CAAC;IAC/B,WAAW,CAAC,EAAE,eAAe,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACpD,YAAY,CAAC,EAAE,eAAe,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACrD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,QAAQ,GAAG,WAAW,GAAG,aAAa,GAAG,IAAI,CAAC;IAC7D,YAAY,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAChD,eAAe,EAAE,sBAAsB,EAAE,CAAC;IAC1C,kBAAkB,EAAE,iBAAiB,EAAE,CAAC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,GAAG,gBAAgB,CAwEnB;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,eAAe,EAAE,sBAAsB,EAAE,CAAC;IAC1C,QAAQ,EAAE,gBAAgB,CAAC;CAC5B,GAAG,sBAAsB,EAAE,CAqC3B"}
@@ -2,10 +2,10 @@ import { z } from "zod";
2
2
  import { type AttemptReceipt, type EvaluationResult } from "./runs.js";
3
3
  export { harnessRefinerBenchmarkAssets, harnessRefinerBenchmarkRelease, } from "./builtin-benchmarks/harness-refiner.js";
4
4
  export declare const BenchmarkMetricSchema: z.ZodEnum<{
5
+ cost_usd: "cost_usd";
5
6
  foreground_tokens: "foreground_tokens";
6
- success_rate: "success_rate";
7
7
  latency_ms: "latency_ms";
8
- cost_usd: "cost_usd";
8
+ success_rate: "success_rate";
9
9
  }>;
10
10
  export declare const BenchmarkRunPhaseSchema: z.ZodEnum<{
11
11
  baseline: "baseline";
@@ -13,10 +13,10 @@ export declare const BenchmarkRunPhaseSchema: z.ZodEnum<{
13
13
  }>;
14
14
  export declare const BenchmarkProtocolSchema: z.ZodObject<{
15
15
  split: z.ZodEnum<{
16
+ frozen_eval: "frozen_eval";
17
+ test: "test";
16
18
  train: "train";
17
19
  validation: "validation";
18
- test: "test";
19
- frozen_eval: "frozen_eval";
20
20
  }>;
21
21
  taskIds: z.ZodArray<z.ZodString>;
22
22
  seeds: z.ZodArray<z.ZodString>;
@@ -36,27 +36,27 @@ export declare const BenchmarkDefinitionSchema: z.ZodObject<{
36
36
  contentHash: z.ZodString;
37
37
  }, z.core.$strict>;
38
38
  adaptationSplit: z.ZodEnum<{
39
+ frozen_eval: "frozen_eval";
40
+ test: "test";
39
41
  train: "train";
40
42
  validation: "validation";
41
- test: "test";
42
- frozen_eval: "frozen_eval";
43
43
  }>;
44
44
  evaluationSplit: z.ZodEnum<{
45
+ frozen_eval: "frozen_eval";
46
+ test: "test";
45
47
  train: "train";
46
48
  validation: "validation";
47
- test: "test";
48
- frozen_eval: "frozen_eval";
49
49
  }>;
50
50
  primaryMetric: z.ZodEnum<{
51
+ cost_usd: "cost_usd";
51
52
  foreground_tokens: "foreground_tokens";
52
- success_rate: "success_rate";
53
53
  latency_ms: "latency_ms";
54
- cost_usd: "cost_usd";
54
+ success_rate: "success_rate";
55
55
  }>;
56
56
  qualityGate: z.ZodEnum<{
57
- none: "none";
58
- non_regression: "non_regression";
59
57
  all_pass: "all_pass";
58
+ non_regression: "non_regression";
59
+ none: "none";
60
60
  }>;
61
61
  caseCounts: z.ZodObject<{
62
62
  adaptation: z.ZodNumber;
@@ -80,10 +80,10 @@ export declare const BenchmarkRunRequestSchema: z.ZodObject<{
80
80
  }, z.core.$strict>;
81
81
  reasoningEffort: z.ZodNullable<z.ZodString>;
82
82
  split: z.ZodEnum<{
83
+ frozen_eval: "frozen_eval";
84
+ test: "test";
83
85
  train: "train";
84
86
  validation: "validation";
85
- test: "test";
86
- frozen_eval: "frozen_eval";
87
87
  }>;
88
88
  seeds: z.ZodArray<z.ZodString>;
89
89
  repetitions: z.ZodNumber;
@@ -119,10 +119,10 @@ export declare const BenchmarkRunSummaryContentSchema: z.ZodObject<{
119
119
  reasoningEffort: z.ZodNullable<z.ZodString>;
120
120
  protocol: z.ZodObject<{
121
121
  split: z.ZodEnum<{
122
+ frozen_eval: "frozen_eval";
123
+ test: "test";
122
124
  train: "train";
123
125
  validation: "validation";
124
- test: "test";
125
- frozen_eval: "frozen_eval";
126
126
  }>;
127
127
  taskIds: z.ZodArray<z.ZodString>;
128
128
  seeds: z.ZodArray<z.ZodString>;
@@ -175,10 +175,10 @@ export declare const BenchmarkRunSummarySchema: z.ZodObject<{
175
175
  reasoningEffort: z.ZodNullable<z.ZodString>;
176
176
  protocol: z.ZodObject<{
177
177
  split: z.ZodEnum<{
178
+ frozen_eval: "frozen_eval";
179
+ test: "test";
178
180
  train: "train";
179
181
  validation: "validation";
180
- test: "test";
181
- frozen_eval: "frozen_eval";
182
182
  }>;
183
183
  taskIds: z.ZodArray<z.ZodString>;
184
184
  seeds: z.ZodArray<z.ZodString>;
@@ -218,10 +218,10 @@ export declare const BenchmarkComparisonContentSchema: z.ZodObject<{
218
218
  contentHash: z.ZodString;
219
219
  }, z.core.$strict>;
220
220
  primaryMetric: z.ZodEnum<{
221
+ cost_usd: "cost_usd";
221
222
  foreground_tokens: "foreground_tokens";
222
- success_rate: "success_rate";
223
223
  latency_ms: "latency_ms";
224
- cost_usd: "cost_usd";
224
+ success_rate: "success_rate";
225
225
  }>;
226
226
  qualityPassed: z.ZodBoolean;
227
227
  baselinePassRate: z.ZodNumber;
@@ -248,10 +248,10 @@ export declare const BenchmarkComparisonSchema: z.ZodObject<{
248
248
  contentHash: z.ZodString;
249
249
  }, z.core.$strict>;
250
250
  primaryMetric: z.ZodEnum<{
251
+ cost_usd: "cost_usd";
251
252
  foreground_tokens: "foreground_tokens";
252
- success_rate: "success_rate";
253
253
  latency_ms: "latency_ms";
254
- cost_usd: "cost_usd";
254
+ success_rate: "success_rate";
255
255
  }>;
256
256
  qualityPassed: z.ZodBoolean;
257
257
  baselinePassRate: z.ZodNumber;