@citeark/agent 0.3.20

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 (347) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +128 -0
  3. package/data/dataset-source-registry.v1.json +300 -0
  4. package/dist/arkgraph/boot.js +6 -0
  5. package/dist/arkgraph/index.html +1 -0
  6. package/dist/arkgraph/viewer.css +1 -0
  7. package/dist/arkgraph/viewer.en.css +1 -0
  8. package/dist/arkgraph/viewer.en.js +49 -0
  9. package/dist/arkgraph/viewer.en.js.LEGAL.txt +56 -0
  10. package/dist/arkgraph/viewer.js +49 -0
  11. package/dist/arkgraph/viewer.js.LEGAL.txt +56 -0
  12. package/docker/claude-code/Dockerfile +97 -0
  13. package/docker/claude-code/codex-pro-relay.mjs +466 -0
  14. package/docker/claude-code/runtime-contract-check.mjs +79 -0
  15. package/docs/arkgraph-reading.md +79 -0
  16. package/docs/configuration.md +100 -0
  17. package/docs/integration.md +92 -0
  18. package/docs/maturity-plan.md +27 -0
  19. package/docs/npm-release.md +44 -0
  20. package/docs/paper-reading.md +40 -0
  21. package/docs/research-plan-granularity.md +27 -0
  22. package/docs/terminal.md +49 -0
  23. package/examples/toy-evaluation/compile-task.json +27 -0
  24. package/examples/toy-evaluation/paper.md +5 -0
  25. package/examples/toy-evaluation/repository/README.md +9 -0
  26. package/examples/toy-evaluation/repository/checkpoint.json +4 -0
  27. package/examples/toy-evaluation/repository/evaluate.py +17 -0
  28. package/examples/toy-evaluation/task.json +81 -0
  29. package/package.json +59 -0
  30. package/prompts/compile-research.md +58 -0
  31. package/prompts/execute-contract.md +72 -0
  32. package/prompts/execute-workspace-simple.md +51 -0
  33. package/prompts/execute-workspace.md +34 -0
  34. package/prompts/prepare-reproduction.md +82 -0
  35. package/prompts/repair-research.md +45 -0
  36. package/protocol/CAP.md +129 -0
  37. package/protocol/LICENSE +12 -0
  38. package/protocol/MAPPINGS.md +72 -0
  39. package/protocol/README.md +38 -0
  40. package/protocol/conformance-v2.0-alpha.1.json +36 -0
  41. package/protocol/examples/arkgraph/checkpoint-evaluation.json +309 -0
  42. package/protocol/examples/arkgraph/fixtures.mjs +49 -0
  43. package/protocol/examples/arkgraph/paper-free.json +291 -0
  44. package/protocol/examples/arkgraph/partial-failure.json +344 -0
  45. package/protocol/examples/arkgraph/training-evaluation.json +443 -0
  46. package/protocol/profiles/agent-trace.md +16 -0
  47. package/protocol/profiles/computational-run.md +16 -0
  48. package/protocol/profiles/core.md +15 -0
  49. package/protocol/profiles/public-bundle.md +18 -0
  50. package/protocol/profiles/reproduction.md +29 -0
  51. package/protocol/profiles/research-compilation.md +44 -0
  52. package/protocol/profiles/research-plan.md +39 -0
  53. package/protocol/profiles/restricted-evidence.md +15 -0
  54. package/runtime/bootstrap-autodl-runtime.sh +314 -0
  55. package/runtime/create-runtime-venv.sh +41 -0
  56. package/runtime/install-local-cpu-runtime.sh +23 -0
  57. package/runtime/install-scientific-runtime.sh +153 -0
  58. package/runtime/mineru/parse.py +62 -0
  59. package/runtime/mineru/requirements.txt +4 -0
  60. package/runtime/requirements-baseline.txt +38 -0
  61. package/schemas/cap/v2/activity.schema.json +47 -0
  62. package/schemas/cap/v2/agent.schema.json +32 -0
  63. package/schemas/cap/v2/assertion.schema.json +110 -0
  64. package/schemas/cap/v2/descriptor.schema.json +243 -0
  65. package/schemas/cap/v2/entity.schema.json +64 -0
  66. package/schemas/cap/v2/manifest.schema.json +67 -0
  67. package/schemas/cap/v2/relation.schema.json +82 -0
  68. package/schemas/compute-catalog.schema.json +63 -0
  69. package/schemas/compute-decision.schema.json +27 -0
  70. package/schemas/execution-contract.schema.json +1024 -0
  71. package/schemas/research-card.schema.json +30 -0
  72. package/schemas/research-inventory-draft.schema.json +366 -0
  73. package/schemas/research.schema.json +1044 -0
  74. package/schemas/result.schema.json +173 -0
  75. package/schemas/verification-policy.schema.json +47 -0
  76. package/schemas/verified-conclusion.schema.json +58 -0
  77. package/schemas/workspace-summary.schema.json +24 -0
  78. package/scripts/build-arkgraph-view.mjs +12 -0
  79. package/scripts/check-execution-feasibility.mjs +24 -0
  80. package/scripts/check-syntax.mjs +15 -0
  81. package/scripts/deterministic-asset-preparation.py +438 -0
  82. package/scripts/package-cap.mjs +23 -0
  83. package/scripts/package-local-agent.mjs +23 -0
  84. package/scripts/preview-arkgraph.mjs +25 -0
  85. package/scripts/replay-research-compiler-candidate.mjs +134 -0
  86. package/scripts/review-compiler-sources.mjs +44 -0
  87. package/scripts/run-asset-preparation.sh +17 -0
  88. package/scripts/run-research-plan.mjs +98 -0
  89. package/scripts/validate-asset-preparation.py +290 -0
  90. package/scripts/verify-local-runtime.mjs +57 -0
  91. package/scripts/verify-npm-package.mjs +57 -0
  92. package/src/adapters/paper2agent.mjs +107 -0
  93. package/src/assets/cache.mjs +159 -0
  94. package/src/assets/compute.mjs +98 -0
  95. package/src/assets/executor.mjs +145 -0
  96. package/src/assets/lifecycle.mjs +213 -0
  97. package/src/assets/manifest.mjs +242 -0
  98. package/src/assets/opportunistic-preparation.mjs +81 -0
  99. package/src/assets/plan.mjs +411 -0
  100. package/src/assets/prompts.mjs +29 -0
  101. package/src/assets/public-asset-probe.mjs +525 -0
  102. package/src/assets/qualification.mjs +119 -0
  103. package/src/assets/readiness.mjs +130 -0
  104. package/src/assets/reproduction-admission.mjs +355 -0
  105. package/src/assets/requirements.mjs +152 -0
  106. package/src/assets/source-grounding.mjs +341 -0
  107. package/src/assets/source-policy.mjs +118 -0
  108. package/src/autodl/client.mjs +260 -0
  109. package/src/autodl/ssh.mjs +380 -0
  110. package/src/autodl/tools.mjs +129 -0
  111. package/src/cap/redaction.mjs +38 -0
  112. package/src/cap/v2/archive.mjs +152 -0
  113. package/src/cap/v2/attestation.mjs +204 -0
  114. package/src/cap/v2/canonical-json.mjs +114 -0
  115. package/src/cap/v2/compilation-artifact.mjs +240 -0
  116. package/src/cap/v2/core.mjs +282 -0
  117. package/src/cap/v2/measurement-assessment-records.mjs +23 -0
  118. package/src/cap/v2/pipeline-artifact.mjs +922 -0
  119. package/src/cap/v2/read.mjs +41 -0
  120. package/src/cap/v2/reassessment-artifact.mjs +383 -0
  121. package/src/cap/v2/research-artifact.mjs +231 -0
  122. package/src/cap/v2/research-map-records.mjs +46 -0
  123. package/src/cap/v2/research-object-records.mjs +163 -0
  124. package/src/cap/v2/research-records.mjs +187 -0
  125. package/src/cap/v2/verify.mjs +642 -0
  126. package/src/cli.mjs +1146 -0
  127. package/src/compute/autodl-pro-compiler.mjs +347 -0
  128. package/src/compute/autodl-pro-executor.mjs +459 -0
  129. package/src/compute/autodl-pro-job.mjs +843 -0
  130. package/src/compute/autodl-pro-network.mjs +295 -0
  131. package/src/compute/autodl-pro-remote.mjs +810 -0
  132. package/src/compute/autodl-pro-staging.mjs +117 -0
  133. package/src/compute/campaign.mjs +110 -0
  134. package/src/compute/catalog.mjs +123 -0
  135. package/src/compute/checkpoint-protocol.mjs +154 -0
  136. package/src/compute/codex-account-lock.mjs +111 -0
  137. package/src/compute/codex-account-session.mjs +107 -0
  138. package/src/compute/compiler-profile.mjs +38 -0
  139. package/src/compute/compiler-router.mjs +23 -0
  140. package/src/compute/coordinator-recovery.mjs +210 -0
  141. package/src/compute/executor-router.mjs +29 -0
  142. package/src/compute/gcp-batch-compiler.mjs +685 -0
  143. package/src/compute/gcp-batch-executor.mjs +1215 -0
  144. package/src/compute/gcp-batch-failure.mjs +92 -0
  145. package/src/compute/gcp-batch-job.mjs +527 -0
  146. package/src/compute/gcp-batch-lifecycle.mjs +81 -0
  147. package/src/compute/gcp-checkpoint-worker.mjs +1633 -0
  148. package/src/compute/local-codex-compiler.mjs +52 -0
  149. package/src/compute/measurement-hardware.mjs +128 -0
  150. package/src/compute/remote-attempt.mjs +226 -0
  151. package/src/compute/requirements.mjs +124 -0
  152. package/src/compute/research-phases.mjs +48 -0
  153. package/src/compute/scheduler.mjs +452 -0
  154. package/src/compute/shared-workloads.mjs +26 -0
  155. package/src/compute/stage-archive.mjs +79 -0
  156. package/src/contracts/campaign-contract.mjs +52 -0
  157. package/src/contracts/execution-contract.mjs +819 -0
  158. package/src/contracts/execution-mode.mjs +19 -0
  159. package/src/contracts/execution-timeouts.mjs +45 -0
  160. package/src/contracts/execution-workload.mjs +68 -0
  161. package/src/contracts/preflight-schema.mjs +25 -0
  162. package/src/contracts/public-contract.mjs +63 -0
  163. package/src/contracts/subject-tags.mjs +31 -0
  164. package/src/dashboard/data.mjs +898 -0
  165. package/src/dashboard/server.mjs +79 -0
  166. package/src/dashboard/static/dashboard.css +366 -0
  167. package/src/dashboard/static/dashboard.js +560 -0
  168. package/src/dashboard/static/index.html +85 -0
  169. package/src/deployment/community-policy.mjs +9 -0
  170. package/src/deployment/environment.mjs +112 -0
  171. package/src/deployment/guided.mjs +98 -0
  172. package/src/deployment/handoff.mjs +102 -0
  173. package/src/deployment/local-contract.mjs +31 -0
  174. package/src/deployment/local.mjs +100 -0
  175. package/src/deployment/prepare.mjs +46 -0
  176. package/src/deployment/recipe.mjs +108 -0
  177. package/src/deployment/supplement.mjs +51 -0
  178. package/src/deployment/terminal.mjs +43 -0
  179. package/src/diagnosis/renderer.mjs +75 -0
  180. package/src/diagnosis/target-failure.mjs +46 -0
  181. package/src/evidence/parser-registry.mjs +54 -0
  182. package/src/evidence/parsers/fasttext-classification.mjs +82 -0
  183. package/src/evidence/parsers/json-scalar.mjs +96 -0
  184. package/src/evidence/parsers/simcse-senteval.mjs +104 -0
  185. package/src/evidence/parsers/starspace-classification.mjs +78 -0
  186. package/src/evidence/registry.mjs +147 -0
  187. package/src/execution/runner-audit.mjs +473 -0
  188. package/src/gcp/auth.mjs +106 -0
  189. package/src/gcp/batch-client.mjs +120 -0
  190. package/src/gcp/resource-discovery.mjs +177 -0
  191. package/src/gcp/rest.mjs +82 -0
  192. package/src/gcp/secret-manager.mjs +34 -0
  193. package/src/gcp/signed-url.mjs +133 -0
  194. package/src/gcp/storage.mjs +220 -0
  195. package/src/graph/command.mjs +41 -0
  196. package/src/graph/execution.mjs +97 -0
  197. package/src/graph/model.mjs +37 -0
  198. package/src/graph/presentation.mjs +110 -0
  199. package/src/graph/query.mjs +159 -0
  200. package/src/graph/research-relations.mjs +69 -0
  201. package/src/graph/source-page.mjs +12 -0
  202. package/src/graph/source-preview.mjs +34 -0
  203. package/src/graph/validate.mjs +76 -0
  204. package/src/job.mjs +496 -0
  205. package/src/network/autodl-routing-proxy.mjs +462 -0
  206. package/src/network/egress-proxy.mjs +158 -0
  207. package/src/observability/event-contract.mjs +230 -0
  208. package/src/observability/pipeline-monitor.mjs +166 -0
  209. package/src/pipeline/orchestrator.mjs +1281 -0
  210. package/src/pipeline/recovery-error.mjs +11 -0
  211. package/src/pipeline/replay.mjs +304 -0
  212. package/src/pipeline/shared-execution.mjs +115 -0
  213. package/src/pipeline/stage-checkpoint.mjs +86 -0
  214. package/src/pipeline/stage-recovery.mjs +101 -0
  215. package/src/pipeline/targets.mjs +110 -0
  216. package/src/process.mjs +143 -0
  217. package/src/protocol.mjs +312 -0
  218. package/src/provider/codex-account.mjs +44 -0
  219. package/src/provider/codex-completion.mjs +49 -0
  220. package/src/provider/completion.mjs +292 -0
  221. package/src/provider/model-client.mjs +44 -0
  222. package/src/provider/model-route.mjs +29 -0
  223. package/src/provider/openrouter-readiness.mjs +189 -0
  224. package/src/provider/reader-bridge.mjs +35 -0
  225. package/src/provider/relay.mjs +263 -0
  226. package/src/provider/runtime-auth.mjs +40 -0
  227. package/src/public/cap.d.mts +90 -0
  228. package/src/public/cap.mjs +12 -0
  229. package/src/public/contracts.d.mts +2 -0
  230. package/src/public/host.mjs +171 -0
  231. package/src/public/operations.d.mts +11 -0
  232. package/src/public/presentation.d.mts +4 -0
  233. package/src/records/views.mjs +26 -0
  234. package/src/remote/command.mjs +178 -0
  235. package/src/remote/ssh.mjs +59 -0
  236. package/src/repository-origin.mjs +81 -0
  237. package/src/reproduction/evidence-feedback.mjs +96 -0
  238. package/src/reproduction/incomplete-initialization.mjs +25 -0
  239. package/src/reproduction/lifecycle.mjs +253 -0
  240. package/src/reproduction/plan.mjs +132 -0
  241. package/src/reproduction/prompts.mjs +70 -0
  242. package/src/reproduction/runner.mjs +188 -0
  243. package/src/reproduction/summary.mjs +130 -0
  244. package/src/reproduction/workspace-mode.mjs +7 -0
  245. package/src/research/automatic-admission.mjs +156 -0
  246. package/src/research/compiler-coverage.mjs +85 -0
  247. package/src/research/compiler-failure.mjs +24 -0
  248. package/src/research/compiler-normalization-guards.mjs +112 -0
  249. package/src/research/compiler-repair.mjs +3 -0
  250. package/src/research/compiler.mjs +853 -0
  251. package/src/research/continuation-selection.mjs +26 -0
  252. package/src/research/execution-graph-context.mjs +43 -0
  253. package/src/research/experiment-importance.mjs +15 -0
  254. package/src/research/inventory-handoff.mjs +104 -0
  255. package/src/research/inventory-revisions.mjs +32 -0
  256. package/src/research/mineru-local.mjs +73 -0
  257. package/src/research/paper-command.mjs +19 -0
  258. package/src/research/paper-markdown.mjs +180 -0
  259. package/src/research/paper-source-map.mjs +69 -0
  260. package/src/research/planning-policy.mjs +88 -0
  261. package/src/research/reference-materials.mjs +11 -0
  262. package/src/research/reproduction-scope.mjs +30 -0
  263. package/src/research/research-map.mjs +94 -0
  264. package/src/research/research-objects.mjs +88 -0
  265. package/src/research/source-discovery.mjs +646 -0
  266. package/src/research/source-observations.mjs +75 -0
  267. package/src/research/source-review-cli-mcp.mjs +26 -0
  268. package/src/research/source-review-input.mjs +209 -0
  269. package/src/research/source-review-local-codex.mjs +36 -0
  270. package/src/research/source-review-model.mjs +70 -0
  271. package/src/research/source-review.mjs +173 -0
  272. package/src/research/structure.mjs +3163 -0
  273. package/src/research-card/renderer.mjs +277 -0
  274. package/src/research-card/verified-conclusion.mjs +143 -0
  275. package/src/results/output-registry.mjs +183 -0
  276. package/src/runtime/claude-code.mjs +52 -0
  277. package/src/runtime/codex-capacity-retry.mjs +87 -0
  278. package/src/runtime/codex.mjs +64 -0
  279. package/src/runtime/config.mjs +157 -0
  280. package/src/runtime/final-output.mjs +40 -0
  281. package/src/runtime/index.mjs +21 -0
  282. package/src/runtime/local-codex.mjs +74 -0
  283. package/src/runtime/opencode.mjs +95 -0
  284. package/src/runtime/prompt.mjs +13 -0
  285. package/src/sandbox/docker.mjs +363 -0
  286. package/src/settings/command.mjs +297 -0
  287. package/src/settings/store.mjs +119 -0
  288. package/src/telemetry/pricing.mjs +68 -0
  289. package/src/telemetry/usage.mjs +265 -0
  290. package/src/terminal/events.mjs +97 -0
  291. package/src/terminal/input.mjs +40 -0
  292. package/src/terminal/plain.mjs +40 -0
  293. package/src/terminal/remote-stream.mjs +22 -0
  294. package/src/terminal/screen.mjs +214 -0
  295. package/src/terminal/transcript.mjs +69 -0
  296. package/src/util.mjs +107 -0
  297. package/src/verification/ai-assessor.mjs +534 -0
  298. package/src/verification/claim-evaluator.mjs +242 -0
  299. package/src/verification/evidence-context.mjs +165 -0
  300. package/src/verification/evidence-reader.mjs +95 -0
  301. package/src/verification/integrity.mjs +570 -0
  302. package/src/verification/tolerance.mjs +32 -0
  303. package/src/workloads/cpu-research-preparation.mjs +56 -0
  304. package/src/workloads/definition.mjs +74 -0
  305. package/src/workloads/phase-aware-reproduction.mjs +46 -0
  306. package/src/workloads/reproduction.mjs +85 -0
  307. package/src/workspace/command.mjs +242 -0
  308. package/src/workspace/control.mjs +49 -0
  309. package/src/workspace/entry.mjs +28 -0
  310. package/src/workspace/input.mjs +93 -0
  311. package/src/workspace/interactive.mjs +94 -0
  312. package/src/workspace/jobs.mjs +418 -0
  313. package/src/workspace/session.mjs +97 -0
  314. package/src/workspace/worker.mjs +137 -0
  315. package/ui/arkgraph/ambient-motion.mjs +10 -0
  316. package/ui/arkgraph/app.jsx +153 -0
  317. package/ui/arkgraph/boot.js +6 -0
  318. package/ui/arkgraph/camera-motion.mjs +20 -0
  319. package/ui/arkgraph/context-reveal.mjs +39 -0
  320. package/ui/arkgraph/details.css +3 -0
  321. package/ui/arkgraph/entry.jsx +28 -0
  322. package/ui/arkgraph/experiment-curves.mjs +17 -0
  323. package/ui/arkgraph/experiment-selection.mjs +15 -0
  324. package/ui/arkgraph/experiment-style.css +26 -0
  325. package/ui/arkgraph/experiment-ui.jsx +32 -0
  326. package/ui/arkgraph/frame.html +1 -0
  327. package/ui/arkgraph/graph-gestures.mjs +62 -0
  328. package/ui/arkgraph/label-layout.mjs +57 -0
  329. package/ui/arkgraph/locales/en.json +229 -0
  330. package/ui/arkgraph/locales/source-types.json +15 -0
  331. package/ui/arkgraph/localization-build.mjs +27 -0
  332. package/ui/arkgraph/material-build.mjs +23 -0
  333. package/ui/arkgraph/material-colors.mjs +39 -0
  334. package/ui/arkgraph/material-style.css +15 -0
  335. package/ui/arkgraph/open-graph.jsx +326 -0
  336. package/ui/arkgraph/outline.jsx +49 -0
  337. package/ui/arkgraph/package-lock.json +888 -0
  338. package/ui/arkgraph/package.json +17 -0
  339. package/ui/arkgraph/reading-layout.mjs +130 -0
  340. package/ui/arkgraph/reading-presentation.mjs +73 -0
  341. package/ui/arkgraph/record-detail.css +51 -0
  342. package/ui/arkgraph/record-details.jsx +29 -0
  343. package/ui/arkgraph/research-types.mjs +31 -0
  344. package/ui/arkgraph/selection-mark.jsx +6 -0
  345. package/ui/arkgraph/soft-spine.mjs +26 -0
  346. package/ui/arkgraph/steering-style.css +187 -0
  347. package/ui/arkgraph/style.css +272 -0
@@ -0,0 +1,11 @@
1
+ /** A deterministic recovery-state mismatch needs repair, not a new paid run. */
2
+ export class RecoveryStateError extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "RecoveryStateError";
6
+ this.failureCategory = "recovery";
7
+ this.failureCode = "target.recovery_state_invalid";
8
+ this.retryable = false;
9
+ this.retryStrategy = "none";
10
+ }
11
+ }
@@ -0,0 +1,304 @@
1
+ import { buildExecutionHandoff } from "../deployment/handoff.mjs";
2
+ import { prepareExecutionRecipe } from "../deployment/recipe.mjs";
3
+ import path from "node:path";
4
+ import { mkdir, mkdtemp, rename } from "node:fs/promises";
5
+ import { relocateStageValue } from "./stage-checkpoint.mjs";
6
+
7
+ import {
8
+ loadExecutionContract,
9
+ loadVerificationPolicy,
10
+ } from "../contracts/execution-contract.mjs";
11
+ import { assemblePipelineCap } from "../cap/v2/pipeline-artifact.mjs";
12
+ import { parseContractEvidence } from "../evidence/registry.mjs";
13
+ import { buildRunnerAudit } from "../execution/runner-audit.mjs";
14
+ import { loadResearchStructure } from "../research/structure.mjs";
15
+ import { CiteArkError, readJson, pathExists, sha256File, sha256Value } from "../util.mjs";
16
+ import { validateResultFile } from "../protocol.mjs";
17
+ import { SCIENTIFIC_ASSESSMENT_RUBRIC_VERSION } from "../verification/ai-assessor.mjs";
18
+ import { evaluateClaim } from "../verification/claim-evaluator.mjs";
19
+ import { checkExecutionIntegrity } from "../verification/integrity.mjs";
20
+ import { renderResearchCard } from "../research-card/renderer.mjs";
21
+ import { buildVerifiedConclusion } from "../research-card/verified-conclusion.mjs";
22
+ import { renderAgentDiagnosis } from "../diagnosis/renderer.mjs";
23
+ import { buildOutputRegistry } from "../results/output-registry.mjs";
24
+ import { resolveResearchPlan, planEvidencePaths } from "../reproduction/plan.mjs";
25
+ import { buildAssessmentEvidenceContext } from "../verification/evidence-context.mjs";
26
+
27
+ export async function replayRunToCap({
28
+ researchPath,
29
+ contractPath,
30
+ executionContractPath,
31
+ policyPath,
32
+ runDirectory,
33
+ capDirectory,
34
+ signingKeyPath,
35
+ sourceReproductionDigest,
36
+ processingBinding,
37
+ researchArtifactDigest,
38
+ getPipelineSummary,
39
+ scientificAssessor,
40
+ handoffCompletion,
41
+ onAssessment = async () => {},
42
+ onStageChange = async () => {},
43
+ stageCheckpoint = async (_stage, operation) => operation(),
44
+ }) {
45
+ if (
46
+ typeof researchArtifactDigest !== "string" ||
47
+ !/^sha256:[0-9a-f]{64}$/.test(researchArtifactDigest)
48
+ ) {
49
+ throw new CiteArkError(
50
+ "CAP replay requires the verified Research Plan CAP digest",
51
+ );
52
+ }
53
+ const [research, originalContract, executionContract, run] = await Promise.all([
54
+ loadResearchStructure(researchPath),
55
+ loadExecutionContract(contractPath),
56
+ executionContractPath
57
+ ? loadExecutionContract(executionContractPath)
58
+ : Promise.resolve(null),
59
+ readJson(path.join(runDirectory, "run.json")),
60
+ ]);
61
+ const sourceContract = executionContract ?? originalContract;
62
+ const resolvedExecutionContract = await resolveResearchPlan(
63
+ sourceContract,
64
+ path.join(runDirectory, "output"),
65
+ );
66
+ const member = sourceContract.campaign?.members.find(item =>
67
+ item.contract.contractDigest === originalContract.contractDigest);
68
+ if (sourceContract.campaign && !member) throw new CiteArkError("共享执行没有在启动前绑定当前目标契约");
69
+ // Separate experiment views keep overlapping measurement IDs distinct in the
70
+ // registry while explicitly retaining the one physical execution identity.
71
+ const publicationRun = member ? { ...run, sharedExecutionRunId: run.runId,
72
+ runId: `${run.runId}-${sha256Value(originalContract.research.experimentId).slice(0, 12)}` } : run;
73
+ const projectedMeasurements = member ? resolvedExecutionContract.measurements.flatMap(measurement => {
74
+ const id = Object.keys(member.measurementMap).find(key => member.measurementMap[key] === measurement.measurementId);
75
+ return id ? [{ ...measurement, measurementId: id }] : [];
76
+ }) : null;
77
+ const contract = member ? {
78
+ ...originalContract, measurements: projectedMeasurements,
79
+ executionPlan: resolvedExecutionContract.executionPlan,
80
+ } : executionContract
81
+ ? {
82
+ ...originalContract,
83
+ protocol: resolvedExecutionContract.protocol,
84
+ measurements: resolvedExecutionContract.measurements,
85
+ research: {
86
+ ...originalContract.research,
87
+ measurementIds: resolvedExecutionContract.research.measurementIds,
88
+ claimMeasurementIds: resolvedExecutionContract.research.claimMeasurementIds,
89
+ uncoveredMeasurementIds:
90
+ resolvedExecutionContract.research.uncoveredMeasurementIds,
91
+ claimCoverage: resolvedExecutionContract.research.claimCoverage,
92
+ },
93
+ executionPlan: resolvedExecutionContract.executionPlan,
94
+ }
95
+ : resolvedExecutionContract;
96
+ const resultValidation = await validateResultFile(
97
+ path.join(runDirectory, "output", "result.json"),
98
+ sourceContract,
99
+ path.join(runDirectory, "output"),
100
+ );
101
+ if (resultValidation.issues.length) {
102
+ throw new CiteArkError(
103
+ `CAP replay rejected an invalid Execution Result 1.0:\n- ${resultValidation.issues.join("\n- ")}`,
104
+ );
105
+ }
106
+ const result = resultValidation.result;
107
+ if (contract.executionPlan) {
108
+ for (const filename of await planEvidencePaths(path.join(runDirectory, "output"))) {
109
+ if (!result.evidence.some((item) => item.path === filename)) result.evidence.push({
110
+ path: filename, description: "Agent research plan snapshot; scientific validity and execution timing require independent audit",
111
+ });
112
+ }
113
+ }
114
+ const runnerAudit = await buildRunnerAudit({
115
+ runDirectory,
116
+ runtime: run.runtime ?? contract.agent?.runtime ?? "unknown",
117
+ sandbox: run.sandbox ?? "unknown",
118
+ });
119
+ const claim = research.claims.find((item) => item.versionId === contract.research.claimVersionId)
120
+ ?? research.claims.find((item) => item.id === contract.research.claimId);
121
+ const evidenceContext = await buildAssessmentEvidenceContext({ runDirectory, contract, claim, runnerAudit,
122
+ paperDigest: processingBinding?.sourceDigest });
123
+ // Reuse downstream results only for the same captured inputs. A parser or
124
+ // evidence repair invalidates post-processing, never scientific execution.
125
+ const capturedPaths = [...new Set([
126
+ "run.json", "output/result.json", "execution/trace.jsonl",
127
+ "execution/workspace-before.json", "execution/workspace-after.json", "execution/workspace-changes.json",
128
+ ...result.evidence.map((item) => `output/${item.path}`),
129
+ ...(result.outputs ?? []).filter((item) => item.path).map((item) => `output/${item.path}`),
130
+ ])].sort();
131
+ const captured = await Promise.all(capturedPaths.map(async (relative) => {
132
+ const filename = path.join(runDirectory, relative);
133
+ return [relative, await pathExists(filename) ? await sha256File(filename) : null];
134
+ }));
135
+ const revision = sha256Value({ plan: contract.executionPlan?.digest ?? contract.contractDigest,
136
+ captured, evidenceContext: evidenceContext.digest, rubric: SCIENTIFIC_ASSESSMENT_RUBRIC_VERSION });
137
+ const checkpoint = (stage, operation, stageRevision = revision) => stageCheckpoint(stage, operation, stageRevision);
138
+ const policy = await loadVerificationPolicy(policyPath, originalContract);
139
+ const sharedExecution = executionContract
140
+ ? {
141
+ sourceContractDigest: sourceContract.contractDigest,
142
+ projectedContractDigest: originalContract.contractDigest,
143
+ experimentVersionId: sourceContract.research.experimentVersionId,
144
+ sourceMeasurementIds: sourceContract.research.measurementIds,
145
+ projectedMeasurementIds: originalContract.research.measurementIds,
146
+ ...(member ? { campaignTargetContractDigest: member.contract.contractDigest,
147
+ experimentVersionId: member.contract.research.experimentVersionId,
148
+ sourceMeasurementIds: Object.keys(member.measurementMap) } : {}),
149
+ }
150
+ : null;
151
+ const outputDirectory = path.join(runDirectory, "output");
152
+ const [metrics, outputs] = await checkpoint(
153
+ "evidence_parsing",
154
+ async () => {
155
+ await onStageChange({ stage: "evidence_parsing", status: "started" });
156
+ const parsed = await Promise.all([
157
+ parseContractEvidence({
158
+ contract,
159
+ outputDirectory,
160
+ parsedAt: run.finishedAt,
161
+ result,
162
+ }),
163
+ buildOutputRegistry({
164
+ result,
165
+ outputDirectory,
166
+ runId: run.runId,
167
+ contractDigest: contract.contractDigest,
168
+ capturedAt: run.finishedAt,
169
+ }),
170
+ ]);
171
+ await onStageChange({ stage: "evidence_parsing", status: "completed" });
172
+ return parsed;
173
+ },
174
+ );
175
+ const { integrity, assessment, diagnosis } = await checkpoint(
176
+ "verification",
177
+ async () => {
178
+ await onStageChange({ stage: "verification", status: "started" });
179
+ const integrity = await checkExecutionIntegrity({
180
+ research,
181
+ contract,
182
+ runDirectory,
183
+ result,
184
+ metrics,
185
+ outputs,
186
+ runnerAudit,
187
+ sharedExecution,
188
+ });
189
+ const assessment = await evaluateClaim({
190
+ contract,
191
+ policy,
192
+ metrics,
193
+ outputs,
194
+ integrity,
195
+ result,
196
+ claim,
197
+ scientificAssessor,
198
+ runnerAudit,
199
+ evidenceContext,
200
+ assessedAt: run.finishedAt,
201
+ });
202
+ await onAssessment(assessment);
203
+ const diagnosis = renderAgentDiagnosis({
204
+ contract,
205
+ result,
206
+ assessment,
207
+ integrity,
208
+ });
209
+ await onStageChange({ stage: "verification", status: "completed" });
210
+ return { integrity, assessment, diagnosis };
211
+ },
212
+ );
213
+ const { verifiedConclusion, researchCard } = await checkpoint(
214
+ "research_card",
215
+ async () => {
216
+ await onStageChange({ stage: "research_card", status: "started" });
217
+ const verifiedConclusion = buildVerifiedConclusion({
218
+ research,
219
+ verifications: [{ contract, assessment, metrics, integrity }],
220
+ generatedAt: assessment.assessedAt ?? run.finishedAt,
221
+ });
222
+ const researchCard = await renderResearchCard({
223
+ research,
224
+ contract,
225
+ run,
226
+ result,
227
+ metrics,
228
+ outputs,
229
+ integrity,
230
+ assessment,
231
+ runnerAudit,
232
+ verifiedConclusion,
233
+ computeDecision: run.computeDecision ?? null,
234
+ });
235
+ await onStageChange({ stage: "research_card", status: "completed" });
236
+ return { verifiedConclusion, researchCard };
237
+ },
238
+ );
239
+ const deploymentHandoff = await checkpoint("execution_handoff", async () => {
240
+ await onStageChange({ stage: "execution_handoff", status: "started" });
241
+ const recipe = ['succeeded', 'partial'].includes(result.execution?.status)
242
+ ? await prepareExecutionRecipe({ runDirectory, evidenceContext, runnerAudit, run, result,
243
+ contract: sourceContract, complete: handoffCompletion }) : null;
244
+ const handoff = await buildExecutionHandoff({ runDirectory, research,
245
+ contract: sourceContract, targetContract: originalContract, policy, researchArtifactDigest, run, result, recipe });
246
+ await onStageChange({ stage: "execution_handoff", status: handoff ? "completed" : "skipped" });
247
+ return handoff;
248
+ }, `sha256:${sha256Value({ revision, handoffVersion: 1 })}`);
249
+ const cap = await checkpoint("packaging", async () => {
250
+ await onStageChange({ stage: "packaging", status: "started" });
251
+ const pipelineSummary =
252
+ typeof getPipelineSummary === "function"
253
+ ? await getPipelineSummary()
254
+ : null;
255
+ await mkdir(path.dirname(capDirectory), { recursive: true });
256
+ const staging = await mkdtemp(`${capDirectory}.building-`);
257
+ const cap = await assemblePipelineCap({
258
+ directory: staging,
259
+ deploymentHandoff,
260
+ sourceReproductionDigest,
261
+ research,
262
+ contract,
263
+ policy,
264
+ runDirectory,
265
+ run: publicationRun,
266
+ executionContract: member ? sourceContract : undefined,
267
+ result,
268
+ metrics,
269
+ outputs,
270
+ integrity,
271
+ assessment,
272
+ verifiedConclusion,
273
+ pipelineSummary,
274
+ researchCard,
275
+ runnerAudit,
276
+ evidenceContext,
277
+ diagnosis,
278
+ signingKeyPath,
279
+ processingBinding,
280
+ researchArtifactDigest,
281
+ });
282
+ // A failed packaging attempt never poisons the next attempt with a partially
283
+ // populated destination. Preserve any prior package when replacing it.
284
+ if (await pathExists(capDirectory)) await rename(capDirectory, `${staging}.previous`);
285
+ await rename(staging, capDirectory);
286
+ await onStageChange({ stage: "packaging", status: "completed" });
287
+ return relocateStageValue(cap, staging, capDirectory);
288
+ }, sha256Value({ revision, deploymentHandoff, sourceReproductionDigest, processingBinding: processingBinding ?? null, researchArtifactDigest: researchArtifactDigest ?? null }));
289
+ return {
290
+ research,
291
+ contract,
292
+ run: publicationRun,
293
+ result,
294
+ metrics,
295
+ outputs,
296
+ integrity,
297
+ assessment,
298
+ diagnosis,
299
+ verifiedConclusion,
300
+ researchCard,
301
+ runnerAudit,
302
+ cap,
303
+ };
304
+ }
@@ -0,0 +1,115 @@
1
+ import { mkdir, cp } from "node:fs/promises";
2
+ import path from "node:path";
3
+
4
+ import { capDirectoryContentDigest, packCap } from "../cap/v2/archive.mjs";
5
+ import { createExecutionContract, loadExecutionContract, loadVerificationPolicy } from "../contracts/execution-contract.mjs";
6
+ import { campaignTargetDirectory } from "../contracts/campaign-contract.mjs";
7
+ import { mergeAgentUsage } from "../telemetry/usage.mjs";
8
+ import { sha256Value } from "../util.mjs";
9
+ import { replayRunToCap } from "./replay.mjs";
10
+
11
+ /**
12
+ * Produce a claim-specific contract, assessment and CAP from an experiment
13
+ * that has already executed under the same comprehensive shared scope.
14
+ * Scientific commands are never started here.
15
+ */
16
+ export async function projectSharedExecutionClaim({
17
+ sourcePipeline,
18
+ researchPath,
19
+ claimId,
20
+ experimentId,
21
+ executionClaimIds,
22
+ workDirectory,
23
+ tolerance,
24
+ signingKeyPath,
25
+ processingBinding,
26
+ researchArtifactDigest,
27
+ scientificAssessor,
28
+ }) {
29
+ const root = path.resolve(workDirectory);
30
+ const directories = {
31
+ root,
32
+ protocol: path.join(root, "protocol"),
33
+ private: path.join(root, "private"),
34
+ cap: path.join(root, "cap"),
35
+ };
36
+ await Promise.all(Object.values(directories).map((directory) =>
37
+ mkdir(directory, { recursive: true })));
38
+ const contractPath = path.join(directories.protocol, "execution-contract.json");
39
+ const policyPath = path.join(directories.private, "verification-policy.json");
40
+ let contract, policy;
41
+ if (sourcePipeline.contract.campaign) {
42
+ const original = campaignTargetDirectory(sourcePipeline.directories.protocol, { claimId, experimentId });
43
+ await cp(path.join(original, "contract.json"), contractPath);
44
+ await cp(path.join(original, "policy.json"), policyPath);
45
+ contract = await loadExecutionContract(contractPath);
46
+ policy = await loadVerificationPolicy(policyPath, contract);
47
+ } else ({ contract, policy } = await createExecutionContract({
48
+ researchPath,
49
+ claimId,
50
+ experimentId,
51
+ executionClaimIds,
52
+ outputPath: contractPath,
53
+ policyPath,
54
+ tolerance,
55
+ }));
56
+ const executionContractPath = path.join(
57
+ sourcePipeline.directories.protocol,
58
+ "execution-contract.json",
59
+ );
60
+ let assessmentUsage = null;
61
+ const replay = await replayRunToCap({
62
+ researchPath,
63
+ contractPath,
64
+ executionContractPath,
65
+ policyPath,
66
+ runDirectory: sourcePipeline.reproduction.bundle.directories.run,
67
+ capDirectory: directories.cap,
68
+ signingKeyPath,
69
+ processingBinding,
70
+ researchArtifactDigest,
71
+ scientificAssessor,
72
+ onAssessment: async assessment => { assessmentUsage = assessment?.usage ?? null; },
73
+ getPipelineSummary: async () => ({
74
+ schemaVersion: "1.0",
75
+ kind: "citeark.pipeline-summary",
76
+ pipelineId: sourcePipeline.state.pipelineId,
77
+ status: "completed",
78
+ phase: "shared-claim-projection",
79
+ createdAt: sourcePipeline.state.createdAt,
80
+ updatedAt: new Date().toISOString(),
81
+ stages: structuredClone(sourcePipeline.state.stages),
82
+ usage: mergeAgentUsage(assessmentUsage),
83
+ usageScope: "claim-projection",
84
+ agent: structuredClone(sourcePipeline.state.agent ?? {}),
85
+ computeDecision: structuredClone(sourcePipeline.computeDecision ?? {}),
86
+ sharedExecution: {
87
+ sourceContractDigest: sourcePipeline.contract.contractDigest,
88
+ projectedContractDigest: contract.contractDigest,
89
+ experimentId,
90
+ },
91
+ }),
92
+ });
93
+ const contentDigest = await capDirectoryContentDigest(directories.cap);
94
+ const archive = await packCap({
95
+ directory: directories.cap,
96
+ outputPath: path.join(
97
+ root,
98
+ `shared-${sha256Value({ claimId, experimentId }).slice(0, 16)}-${contentDigest.slice(7)}.cap`,
99
+ ),
100
+ reuseExisting: true,
101
+ });
102
+ return {
103
+ ...sourcePipeline,
104
+ directories,
105
+ archive,
106
+ contract,
107
+ policy,
108
+ replay,
109
+ sharedExecution: {
110
+ sourceContractDigest: sourcePipeline.contract.contractDigest,
111
+ claimId,
112
+ experimentId,
113
+ },
114
+ };
115
+ }
@@ -0,0 +1,86 @@
1
+ import { RecoveryStateError } from "./recovery-error.mjs";
2
+ import { mkdir } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { pathExists, readJson, sha256Value, writeJson } from "../util.mjs";
5
+
6
+ // This is coordinator-private state, never an Agent input or a public CAP.
7
+ // A stage becomes reusable only after its output and the matching identity
8
+ // have been durably saved. A failed upload stops downstream work.
9
+ export function createStageCheckpoint({
10
+ directory,
11
+ identity,
12
+ persist = async () => {},
13
+ progress = () => {},
14
+ enabled = true,
15
+ }) {
16
+ const root = path.resolve(directory);
17
+ const identityDigest = `sha256:${sha256Value(identity)}`;
18
+ return async (stage, operation, revision = null) => {
19
+ if (!enabled) return operation();
20
+ if (!/^[a-z][a-z0-9_]*$/.test(stage))
21
+ throw new Error("Invalid recovery stage");
22
+ const suffix = revision ? `-${sha256Value(revision)}` : "";
23
+ const filename = path.join(root, "stage-results", `${stage}${suffix}.json`);
24
+ if (await pathExists(filename)) {
25
+ const saved = await readJson(filename);
26
+ if (saved.identityDigest !== identityDigest || saved.stage !== stage) {
27
+ throw new RecoveryStateError(`Recovery input identity changed at ${stage}`);
28
+ }
29
+ progress(`复用已完成阶段:${stage}`);
30
+ return relocateStageValue(saved.value, saved.root, root);
31
+ }
32
+ const value = await operation();
33
+ const durableValue = checkpointValue(value);
34
+ await mkdir(path.dirname(filename), { recursive: true });
35
+ await writeJson(filename, {
36
+ schemaVersion: "1.0",
37
+ stage,
38
+ root,
39
+ identityDigest,
40
+ value: durableValue,
41
+ });
42
+ await persist({ stage, status: "completed" });
43
+ return value;
44
+ };
45
+ }
46
+
47
+ export function relocateStageValue(value, previousRoot, root) {
48
+ if (typeof value === "string") {
49
+ return value === previousRoot
50
+ ? root
51
+ : value.startsWith(`${previousRoot}/`)
52
+ ? root + value.slice(previousRoot.length)
53
+ : value;
54
+ }
55
+ if (Array.isArray(value))
56
+ return value.map((item) => relocateStageValue(item, previousRoot, root));
57
+ if (value && typeof value === "object")
58
+ return Object.fromEntries(
59
+ Object.entries(value).map(([key, item]) => [
60
+ key,
61
+ relocateStageValue(item, previousRoot, root),
62
+ ]),
63
+ );
64
+ return value;
65
+ }
66
+
67
+ function checkpointValue(value) {
68
+ // Runtime credentials are reconstructed by the new worker. Do not serialize
69
+ // a runtime/provider client or the budget capability from a bundle.
70
+ return JSON.parse(
71
+ JSON.stringify(value ?? null, (key, item) => {
72
+ if (
73
+ new Set([
74
+ "runtimeAgent",
75
+ "paperBudget",
76
+ "apiKey",
77
+ "apiToken",
78
+ "accessToken",
79
+ "signingKeyPath",
80
+ ]).has(key)
81
+ )
82
+ return undefined;
83
+ return item;
84
+ }),
85
+ );
86
+ }
@@ -0,0 +1,101 @@
1
+ // Deferred optional preparation is complete for recovery purposes: the final
2
+ // reproduction Agent owns the fallback and must not be routed back into cache
3
+ // preparation when a later stage fails.
4
+ const TERMINAL_STAGE_STATUSES = new Set(["completed", "deferred", "skipped"]);
5
+
6
+ /**
7
+ * Derive the smallest safe restart boundary from durable pipeline state.
8
+ *
9
+ * This contract deliberately treats the scientific reproduction Agent as one
10
+ * autonomous stage. It may restore that Agent's complete workspace/session, or
11
+ * reuse its already validated result, but never decomposes the Agent's internal
12
+ * reasoning loop into controller-owned micro steps.
13
+ */
14
+ export function pipelineStageResumePlan(state) {
15
+ const stages = normalizeStages(state?.stages);
16
+ if (!stages.length) return null;
17
+
18
+ const failedIndex = stages.findIndex((stage) => stage.status === "failed");
19
+ const runningIndex = stages.findIndex((stage) => stage.status === "running");
20
+ const phaseIndex = stages.findIndex((stage) => stage.id === state?.phase);
21
+ const candidates = [
22
+ firstIncompleteIndex(stages),
23
+ failedIndex,
24
+ runningIndex,
25
+ phaseIndex,
26
+ ].filter((index) => index >= 0);
27
+ const resumeIndex = candidates.length ? Math.min(...candidates) : -1;
28
+ if (resumeIndex < 0) return null;
29
+
30
+ const reproductionIndex = stages.findIndex((stage) => stage.id === "reproduction");
31
+ const reproductionCompleted = reproductionIndex >= 0
32
+ && stages[reproductionIndex].status === "completed";
33
+ const completedStages = stages
34
+ .slice(0, resumeIndex)
35
+ .filter((stage) => TERMINAL_STAGE_STATUSES.has(stage.status))
36
+ .map((stage) => stage.id);
37
+ const resumeStage = stages[resumeIndex].id;
38
+ const agentResumeMode = reproductionCompleted && resumeIndex > reproductionIndex
39
+ ? "reuse_completed_result"
40
+ : resumeStage === "reproduction"
41
+ ? "continue_autonomous_agent"
42
+ : "rerun_stage";
43
+
44
+ return {
45
+ schemaVersion: "1.0",
46
+ resumeStage,
47
+ lastCompletedStage: completedStages.at(-1) ?? null,
48
+ completedStages,
49
+ invalidatedStages: stages.slice(resumeIndex).map((stage) => stage.id),
50
+ agentResumeMode,
51
+ autonomyBoundary: "whole-agent-workload",
52
+ };
53
+ }
54
+
55
+ export function createPipelineRecoveryEnvelope({ state, reproduction, checkpoint } = {}) {
56
+ const resume = pipelineStageResumePlan(state);
57
+ if (!resume) return null;
58
+ const cloud = reproduction?.bundle?.state?.cloudExecution;
59
+ const selected = checkpoint ?? latestCloudCheckpoint(cloud?.jobs);
60
+ if (!selected) return { ...resume, checkpoint: null };
61
+ const reason = selected.checkpoint?.reason ?? selected.reason ?? null;
62
+ return {
63
+ ...resume,
64
+ // The durable coordinator result decides the boundary. An older remote
65
+ // checkpoint cannot turn a publication retry back into scientific work.
66
+ checkpoint: {
67
+ bucket: cloud?.stagingBucket ?? selected.bucket,
68
+ checkpointPrefix: selected.checkpointPrefix,
69
+ checkpointStatus: selected.checkpointStatus,
70
+ sequence: selected.checkpoint?.sequence ?? selected.sequence,
71
+ kind: selected.checkpoint?.kind ?? selected.kind,
72
+ reason,
73
+ createdAt: selected.checkpoint?.createdAt ?? selected.createdAt,
74
+ },
75
+ };
76
+ }
77
+
78
+ function latestCloudCheckpoint(jobs) {
79
+ if (!Array.isArray(jobs)) return null;
80
+ return [...jobs].reverse().find((candidate) =>
81
+ typeof candidate?.checkpointPrefix === "string"
82
+ && typeof candidate?.checkpoint?.sequence === "string",
83
+ ) ?? null;
84
+ }
85
+
86
+ function normalizeStages(value) {
87
+ if (!Array.isArray(value)) return [];
88
+ return value
89
+ .filter((stage) =>
90
+ stage
91
+ && typeof stage === "object"
92
+ && typeof stage.id === "string"
93
+ && typeof stage.status === "string",
94
+ )
95
+ .map((stage) => ({ id: stage.id, status: stage.status }));
96
+ }
97
+
98
+ function firstIncompleteIndex(stages) {
99
+ const index = stages.findIndex((stage) => !TERMINAL_STAGE_STATUSES.has(stage.status));
100
+ return index >= 0 ? index : -1;
101
+ }