@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,130 @@
1
+ import path from "node:path";
2
+ import { lstat, readFile, readdir, realpath } from "node:fs/promises";
3
+ import { extractRunnerCommandRecords } from "../execution/runner-audit.mjs";
4
+ import { parseContractEvidence } from "../evidence/registry.mjs";
5
+ import { isRecord, pathExists, readJson, safeRelativePath, writeJson } from "../util.mjs";
6
+ import { planEvidencePaths } from "./plan.mjs";
7
+ import { measurementInterpretation } from "./evidence-feedback.mjs";
8
+
9
+ /** Build operational metadata from captured records; never create observations.
10
+ * The Agent summary and plan remain declarations. Independent integrity and
11
+ * scientific assessment still determine whether the captured evidence is valid.
12
+ */
13
+ export async function materializeWorkspaceSummary(submission, contract, outputDirectory) {
14
+ const issues = [];
15
+ if (submission.schemaVersion !== "2.0") issues.push("workspace summary.schemaVersion must be 2.0");
16
+ if (!["completed", "partial", "failed"].includes(submission.status)) issues.push("workspace summary.status must be completed, partial or failed");
17
+ if (typeof submission.summary !== "string" || !submission.summary.trim()) issues.push("workspace summary.summary is required");
18
+ if (submission.limitations !== undefined && (!Array.isArray(submission.limitations)
19
+ || submission.limitations.some((item) => typeof item !== "string"))) issues.push("workspace summary.limitations must be strings");
20
+ if (submission.evidence !== undefined && !Array.isArray(submission.evidence)) issues.push("workspace summary.evidence must be an array");
21
+ if (issues.length) return { result: null, issues };
22
+
23
+ const evidence = new Map();
24
+ const missing = [];
25
+ const add = async (filename, description, explicit = false) => {
26
+ if (!safeRelativePath(filename)) {
27
+ issues.push(`Unsafe evidence path: ${String(filename)}`);
28
+ return;
29
+ }
30
+ if (filename === "result.json") return;
31
+ const target = path.join(outputDirectory, filename);
32
+ const stat = await lstat(target).catch((error) => {
33
+ if (error.code === "ENOENT") return null;
34
+ throw error;
35
+ });
36
+ if (!stat) { if (explicit) missing.push(filename); return; }
37
+ const [root, resolved] = await Promise.all([realpath(outputDirectory), realpath(target)]);
38
+ if (!stat.isFile() || !resolved.startsWith(`${root}${path.sep}`)) {
39
+ issues.push(`Evidence is not a regular workspace file: ${filename}`);
40
+ return;
41
+ }
42
+ evidence.set(filename, { path: filename, description: description || `Preserved workspace evidence: ${filename}` });
43
+ };
44
+ for (const measurement of contract.measurements) {
45
+ await add(measurement.parser.evidencePath, `Raw parser input for ${measurement.measurementId}`);
46
+ }
47
+ for (const item of submission.evidence ?? []) {
48
+ if (!isRecord(item)) { issues.push("Each additional evidence item must specify path"); continue; }
49
+ await add(item.path, item.description, true);
50
+ }
51
+ for (const filename of await planEvidencePaths(outputDirectory)) await add(filename, "Research plan declaration retained for independent assessment");
52
+ for (const filename of ["progress.md", "experiment-records.jsonl"]) await add(filename);
53
+ const logDirectory = path.join(outputDirectory, "experiment-logs");
54
+ if (await pathExists(logDirectory)) {
55
+ for (const name of await readdir(logDirectory)) {
56
+ if (/^[a-f0-9-]{36}\.(?:stdout|stderr)\.log$/.test(name)) {
57
+ await add(`experiment-logs/${name}`, "Raw experiment command output captured by the execution helper");
58
+ }
59
+ }
60
+ }
61
+ // A summary need not enumerate every raw history. Preserve generated tables
62
+ // before the scientific machine disappears, independently of parser bindings.
63
+ async function retainRaw(directory = "") {
64
+ for (const entry of await readdir(path.join(outputDirectory, directory), { withFileTypes: true })) {
65
+ const relative = directory ? `${directory}/${entry.name}` : entry.name;
66
+ if (/(?:^|\/)(?:\.env[^/]*|auth\.json|credentials\.json|secrets\.json)$/i.test(relative)) continue;
67
+ if (entry.isDirectory()) await retainRaw(relative);
68
+ else if (entry.isFile() && relative !== "result.json" && /\.(?:json|jsonl|ndjson|csv|tsv|txt|log|parquet|arrow)$/i.test(relative))
69
+ await add(relative, "Original scientific table or history retained independently of the summary");
70
+ }
71
+ }
72
+ await retainRaw();
73
+ if (issues.length) return { result: null, issues };
74
+
75
+ const executionDirectory = path.resolve(outputDirectory, "../execution");
76
+ const runPath = path.resolve(outputDirectory, "../run.json");
77
+ const run = await pathExists(runPath) ? await readJson(runPath) : {};
78
+ const tracePath = path.join(executionDirectory, "trace.jsonl");
79
+ const trace = await pathExists(tracePath) ? await readFile(tracePath, "utf8") : "";
80
+ const commands = [...new Set(extractRunnerCommandRecords(trace, { runtime: run.runtime ?? contract.agent?.runtime })
81
+ .map((record) => record.command?.text).filter((command) => typeof command === "string" && command.trim()))];
82
+ const changesPath = path.join(executionDirectory, "workspace-changes.json");
83
+ const changes = await pathExists(changesPath) ? await readJson(changesPath) : {};
84
+ const codeChanges = [...new Set([...(changes.added ?? []), ...(changes.modified ?? []), ...(changes.deleted ?? [])]
85
+ .map((item) => item.path).filter(safeRelativePath))].map((filename) => ({
86
+ path: filename,
87
+ classification: "scientific",
88
+ reason: "Runner-observed workspace change; independent assessment determines its scientific effect.",
89
+ }));
90
+ // Availability is determined by parsing real bytes. Missing/bad bindings are
91
+ // disclosed as partial evidence, not a reason to restart expensive compute.
92
+ const parsed = await parseContractEvidence({ contract, outputDirectory,
93
+ result: { execution: { status: "partial" }, evidence: [...evidence.values()] },
94
+ });
95
+ const unavailable = parsed.measurements.filter((item) => item.availability.status !== "available");
96
+ const unresolvedInterpretations = contract.measurements.filter((item) => measurementInterpretation(item).status === "unresolved");
97
+ const limitations = [...(submission.limitations ?? [])];
98
+ if (unresolvedInterpretations.length) limitations.push(`Unresolved metric interpretation: ${unresolvedInterpretations.map((item) => `${item.measurementId}: ${measurementInterpretation(item).reason}`).join("; ")}`);
99
+ if (missing.length) limitations.push(`Listed evidence was absent: ${missing.join(", ")}.`);
100
+ if (unavailable.length) limitations.push(`Unresolved measurements: ${unavailable.map((item) => `${item.measurementId}: ${item.availability.reason}`).join("; ")}`);
101
+ if (!commands.length) limitations.push("The runner did not capture an execution command; completion is not established.");
102
+ const status = submission.status === "failed" ? "failed"
103
+ : submission.status === "partial" || missing.length || unavailable.length || unresolvedInterpretations.length || !commands.length ? "partial" : "succeeded";
104
+ const result = {
105
+ schemaVersion: "1.0",
106
+ execution: {
107
+ status,
108
+ summary: submission.summary,
109
+ failure: status === "succeeded" ? null : {
110
+ category: unavailable.length ? "metric_unavailable" : "execution_error",
111
+ stage: "measurement",
112
+ retryable: false,
113
+ reason: [submission.summary, ...limitations].join("\n"),
114
+ },
115
+ },
116
+ experiment: { commands, entrypoint: contract.protocol?.entrypoint ?? null, checkpoint: null },
117
+ codeChanges,
118
+ evidence: [...evidence.values()],
119
+ outputs: [],
120
+ limitations,
121
+ diagnosis: submission.summary,
122
+ };
123
+ // Keep the exact Agent submission in output/result.json. This coordinator
124
+ // projection is reconstructible and never takes its place as raw evidence.
125
+ await writeJson(path.join(executionDirectory, "workspace-result.json"), {
126
+ source: "platform-workspace-summary", contractDigest: contract.contractDigest,
127
+ executionPlanDigest: contract.executionPlan?.digest, result,
128
+ });
129
+ return { result, issues: [], parsed };
130
+ }
@@ -0,0 +1,7 @@
1
+ export function hasResearchWorkspace(contract) {
2
+ return [1, 2].includes(contract?.workspacePlan?.version);
3
+ }
4
+
5
+ export function usesWorkspaceSummary(contract) {
6
+ return contract?.workspacePlan?.version === 2;
7
+ }
@@ -0,0 +1,156 @@
1
+ export const AUTOMATIC_RECONSTRUCTION_FIDELITIES = Object.freeze([
2
+ "exact",
3
+ "faithful",
4
+ "approximate",
5
+ ]);
6
+
7
+ const AUTOMATIC_FIDELITIES = new Set(AUTOMATIC_RECONSTRUCTION_FIDELITIES);
8
+ const REQUIRED_PREFLIGHT_CHECKS = Object.freeze([
9
+ "runtime",
10
+ "dependencies",
11
+ "entrypoint",
12
+ "parser",
13
+ "smoke_test",
14
+ ]);
15
+
16
+ /**
17
+ * Automatic reproduction accepts honest independent reconstructions as well
18
+ * as exact and faithful protocols. Fidelity describes comparability; it does
19
+ * not decide whether useful evidence may be collected. Directional proxy work
20
+ * still requires an explicit researcher selection because it does not test the
21
+ * paper-bound measurement itself.
22
+ */
23
+ export function automaticExperimentAdmission(experiment) {
24
+ const reasons = [];
25
+ if (!experiment?.measurements?.length) {
26
+ reasons.push({ code: "admission.numeric_targets_unresolved",
27
+ message: "计划保留了观察比较方法,但没有可验证的数值目标;定性判定规则尚未闭合" });
28
+ }
29
+ const agentPlanned = experiment?.protocol?.executionMode === "agent_planned";
30
+ const hasDevicePerformance = (experiment?.measurements ?? [])
31
+ .some((measurement) => measurement?.quantityKind === "device_performance");
32
+ const benchmark = experiment?.protocol?.benchmark;
33
+ const fidelity = experiment?.reconstructionFidelity
34
+ ?? (experiment?.implementationOrigin === "official" ? "faithful" : "approximate");
35
+ if (!AUTOMATIC_FIDELITIES.has(fidelity)) {
36
+ reasons.push({
37
+ code: "admission.proxy_requires_selection",
38
+ message: `${fidelity} 实验只提供替代性方向证据,需要研究者显式选择`,
39
+ });
40
+ }
41
+
42
+ if (benchmark?.comparisonIntent === "cross_hardware") {
43
+ reasons.push({
44
+ code: "admission.cross_hardware_requires_selection",
45
+ message: "跨硬件实验只能回答独立的可移植性问题,不能自动作为论文报告性能数值的复现目标",
46
+ });
47
+ }
48
+ if ((hasDevicePerformance || benchmark) && benchmark?.hardwareBinding === "unknown") {
49
+ reasons.push({
50
+ code: "admission.hardware_binding_unresolved",
51
+ message: "论文性能测量的硬件绑定尚未确定,不能在解析该条件前自动启动实验",
52
+ });
53
+ }
54
+
55
+ const preflight = experiment?.protocol?.preflight;
56
+ if (!preflight || (!agentPlanned && preflight.source !== "declared")) {
57
+ reasons.push({
58
+ code: "admission.preflight_not_declared",
59
+ message: agentPlanned
60
+ ? "自动复现必须具有结构化预检目标"
61
+ : "固定入口自动复现必须具有编译期声明的结构化预检",
62
+ });
63
+ }
64
+
65
+ const checks = new Set(
66
+ Array.isArray(preflight?.checks)
67
+ ? preflight.checks.map((check) => check?.kind).filter(Boolean)
68
+ : [],
69
+ );
70
+ for (const kind of REQUIRED_PREFLIGHT_CHECKS) {
71
+ if (!checks.has(kind)) {
72
+ reasons.push({
73
+ code: `admission.preflight_check_missing.${kind}`,
74
+ message: `自动预检缺少 ${kind} 检查`,
75
+ });
76
+ }
77
+ }
78
+
79
+ const assets = Array.isArray(preflight?.assets) ? preflight.assets : [];
80
+ const requiredAssets = assets.filter((asset) => asset?.required === true);
81
+ if (requiredAssets.some((asset) => asset?.kind === "dataset") && !checks.has("dataset_loader")) {
82
+ reasons.push({
83
+ code: "admission.dataset_loader_missing",
84
+ message: "必需数据集没有真实 loader 预检",
85
+ });
86
+ }
87
+ // Asset availability and locator quality are runtime observations, not an
88
+ // automatic-run verdict. The complete reproduction Agent may inspect the
89
+ // fixed paper/repository, find an allowed public transport, or report a
90
+ // concrete evidence-backed limitation. Static admission only decides
91
+ // whether the scientific plan is strict and structurally executable.
92
+
93
+ return {
94
+ schemaVersion: "0.1",
95
+ experimentId: experiment?.id ?? null,
96
+ fidelity,
97
+ automatic: reasons.length === 0,
98
+ reasons: uniqueReasons(reasons),
99
+ publicAssetsToProbe: requiredAssets
100
+ .filter((asset) => asset?.availability === "public_unverified")
101
+ .filter((asset) => (asset?.scientificRole ?? "execution_required") === "execution_required")
102
+ .map((asset) => ({
103
+ id: asset.id,
104
+ kind: asset.kind,
105
+ identity: asset.identity,
106
+ sourceUrls: Array.isArray(asset.sourceUrls) ? [...asset.sourceUrls] : [],
107
+ registryDatasetId: asset.registryDatasetId,
108
+ scientificRole: asset.scientificRole ?? "execution_required",
109
+ acquisition: asset.acquisition ?? { mode: "auto" },
110
+ sourceEvidence: Array.isArray(asset.sourceEvidence) ? [...asset.sourceEvidence] : [],
111
+ })),
112
+ };
113
+ }
114
+
115
+ export function automaticClaimCoverage(claim, experiments) {
116
+ const requiredIds = new Set(
117
+ (Array.isArray(claim?.reportedMeasurements) ? claim.reportedMeasurements : [])
118
+ .map((measurement) => measurement?.id)
119
+ .filter(Boolean),
120
+ );
121
+ const bound = (Array.isArray(experiments) ? experiments : []).filter((experiment) =>
122
+ Array.isArray(experiment?.claimIds)
123
+ && experiment.claimIds.includes(claim?.id)
124
+ && automaticExperimentAdmission(experiment).automatic,
125
+ );
126
+ const coveredIds = new Set();
127
+ for (const experiment of bound) {
128
+ for (const measurement of experiment.measurements ?? []) {
129
+ if (requiredIds.has(measurement?.reportedMeasurementId)) {
130
+ coveredIds.add(measurement.reportedMeasurementId);
131
+ }
132
+ }
133
+ }
134
+ return {
135
+ bound,
136
+ coveredIds,
137
+ missingIds: [...requiredIds].filter((measurementId) => !coveredIds.has(measurementId)),
138
+ };
139
+ }
140
+
141
+ export function automaticAdmissionByExperiment(research) {
142
+ return new Map(
143
+ (Array.isArray(research?.experiments) ? research.experiments : [])
144
+ .map((experiment) => [experiment.id, automaticExperimentAdmission(experiment)]),
145
+ );
146
+ }
147
+
148
+ function uniqueReasons(reasons) {
149
+ const seen = new Set();
150
+ return reasons.filter((reason) => {
151
+ const key = `${reason.code}\u0000${reason.assetId ?? ""}`;
152
+ if (seen.has(key)) return false;
153
+ seen.add(key);
154
+ return true;
155
+ });
156
+ }
@@ -0,0 +1,85 @@
1
+ import { reproductionScopeIssues } from "./reproduction-scope.mjs";
2
+ import { automaticClaimCoverage } from "./automatic-admission.mjs";
3
+ import { continuationRepairTargets } from "./continuation-selection.mjs";
4
+
5
+ const BLOCKER_KINDS = new Set(["scientific_input", "access", "resources", "budget", "decision_rule"]);
6
+ const nonempty = (value) => typeof value === "string" && value.trim().length > 0;
7
+
8
+ /** A planning obligation, not a claim of scientific support or feasibility. */
9
+ export function reviewCompilerCoverage(research, context = {}, previousInventory = []) {
10
+ const claims = Array.isArray(research?.claims) ? research.claims : [];
11
+ const targets = context.repairBaselineResearch ? continuationRepairTargets(context.continuation) : [];
12
+ const targetIds = new Set(targets.map((target) => target.experimentId));
13
+ const selected = targets.length ? new Set(targets.flatMap((target) =>
14
+ (context.repairBaselineResearch.experiments ?? [])
15
+ .filter((experiment) => experiment.id === target.experimentId)
16
+ .flatMap((experiment) => (experiment.measurements ?? []).map((measurement) => `${target.claimId}/${measurement.reportedMeasurementId}`)),
17
+ )) : null;
18
+ // Scope comes from the host's immutable continuation baseline, never from
19
+ // the candidate's choice to omit experiments or to label claims deferred.
20
+ const experiments = (Array.isArray(research?.experiments) ? research.experiments : [])
21
+ .filter((experiment) => !selected || targetIds.has(experiment.id));
22
+ const inventory = claims.flatMap((claim) => {
23
+ const measurements = Array.isArray(claim.reportedMeasurements) ? claim.reportedMeasurements : [];
24
+ if (measurements.length) return measurements.map((measurement) => ({
25
+ claimId: claim.id, measurementId: measurement.id, sourceLocator: measurement.sourceLocator ?? claim.sourceLocator,
26
+ }));
27
+ return ["finding", "measurement"].includes(claim.type)
28
+ ? [{ claimId: claim.id, measurementId: null, sourceLocator: claim.sourceLocator }]
29
+ : [];
30
+ }).filter((item) => !selected || selected.has(`${item.claimId}/${item.measurementId}`));
31
+ const inventoryOnly = research.compilationStage === "inventory";
32
+ const obligations = [];
33
+ for (const claim of claims) {
34
+ const required = inventory.filter((item) => item.claimId === claim.id);
35
+ if (!required.length) continue;
36
+ const coverage = automaticClaimCoverage(claim, experiments);
37
+ const blocker = claim.reproduction?.blocker;
38
+ const supportedBlocker = BLOCKER_KINDS.has(blocker?.kind) && nonempty(blocker?.evidence)
39
+ && !(blocker.kind === "budget" && (context.computeContext?.limits?.maximumCost === null));
40
+ const blockerIds = new Set(Array.isArray(blocker?.measurementIds) ? blocker.measurementIds : []);
41
+ for (const item of required) {
42
+ const planned = item.measurementId !== null && coverage.coveredIds.has(item.measurementId);
43
+ const blocked = supportedBlocker && (
44
+ (claim.reproduction?.status === "blocked" && coverage.coveredIds.size === 0 && !Array.isArray(blocker.measurementIds))
45
+ || blockerIds.has(item.measurementId)
46
+ );
47
+ obligations.push({
48
+ ...item,
49
+ status: inventoryOnly ? "recorded" : planned ? "planned" : context.licensePolicy?.executable === false ? "license_restricted" : blocked ? "blocked" : "unresolved",
50
+ ...(blocked ? { blocker } : {}),
51
+ });
52
+ }
53
+ }
54
+ // Keep the first discovered inventory across correction attempts. Regrouping
55
+ // measurements into better claims is allowed; silently deleting them is not.
56
+ const currentMeasurements = new Set(inventory.filter((item) => item.measurementId).map((item) => item.measurementId));
57
+ const currentClaims = new Set(claims.map((claim) => claim.id));
58
+ const dropped = previousInventory.filter((item) => item.measurementId
59
+ ? !currentMeasurements.has(item.measurementId)
60
+ : !currentClaims.has(item.claimId));
61
+ const unresolved = obligations.filter((item) => item.status === "unresolved");
62
+ const issues = reproductionScopeIssues(research, context.reproductionScope);
63
+ if (unresolved.length) issues.push(
64
+ `Compiler coverage incomplete: ${unresolved.map((item) => `${item.claimId}/${item.measurementId ?? "decision_rule"}`).join(", ")}. `
65
+ + "Bind each known empirical measurement to an experiment, or record a concrete blocker with kind and source/probe evidence. "
66
+ + "Keep the requested preset separate from scientific planning: a lower preset must not remove a valid experiment package. Reuse appropriate data, software, traces, model weights and simulation outputs when scientifically justified; never regenerate upstream artifacts as an automatic fallback. Complete source inventory does not require executing every package. "
67
+ + "An objective-only agent_planned experiment with measurement bindings is a valid planning route; describe unresolved assumptions and the bounded runtime probe in its objective. "
68
+ + "Unverified commands, public assets or runtime estimates alone do not establish a blocker, and planning a probe does not establish full-workload feasibility. "
69
+ + "For a partially planned claim, blocker.measurementIds must identify exactly the unbound measurements it prevents. "
70
+ + "A deferred label, representative subset, another benchmark, or an unsupported estimate is not a completed planning decision. "
71
+ + "Preserve every existing valid experiment. Operational details can be resolved by the execution Agent, but missing experiments cannot. "
72
+ + "This requirement still applies on the final correction attempt; unresolved scope cannot be published as an executable plan.",
73
+ );
74
+ if (dropped.length) issues.push(
75
+ `Compiler coverage inventory lost: ${dropped.map((item) => `${item.claimId}/${item.measurementId ?? "decision_rule"}`).join(", ")}. `
76
+ + "Restore these previously identified results. You may regroup measurements into scientifically appropriate claims while preserving their measurement ids; deleting difficult scope cannot satisfy coverage.",
77
+ );
78
+ return {
79
+ version: 1, stage: inventoryOnly ? "inventory" : "execution_plan", scope: selected ? "continuation" : "full_paper", complete: issues.length === 0,
80
+ inventory: [...previousInventory, ...inventory.filter((item) => !previousInventory.some((previous) =>
81
+ item.measurementId ? previous.measurementId === item.measurementId : previous.claimId === item.claimId && previous.measurementId === null,
82
+ ))],
83
+ obligations, issues,
84
+ };
85
+ }
@@ -0,0 +1,24 @@
1
+ import { CiteArkError } from "../util.mjs";
2
+
3
+ /**
4
+ * Semantic validation retries belong to one Research Compiler run. Once that
5
+ * bounded repair loop is exhausted, starting a fresh Processing Worker with
6
+ * the same inputs only repeats model spend, so the outer worker must fail
7
+ * closed. Provider and transport failures retain their explicit retryability.
8
+ */
9
+ export function researchCompilationFailure(validationIssues, providerFailure = null) {
10
+ const issues = (Array.isArray(validationIssues) ? validationIssues : [])
11
+ .map((issue) => String(issue ?? "").trim())
12
+ .filter(Boolean);
13
+ return new CiteArkError(
14
+ `研究编译失败:\n- ${issues.join("\n- ")}`,
15
+ {
16
+ exitCode: 2,
17
+ retryable: providerFailure ? providerFailure.retryable === true : false,
18
+ failureCode: providerFailure?.code ?? "research_compilation.validation_exhausted",
19
+ failureCategory: providerFailure?.failureCategory ?? "research_compilation",
20
+ recoveryAction: providerFailure?.recoveryAction
21
+ ?? "保留编译现场并停止自动重跑;修正规则或输入后创建显式续跑任务",
22
+ },
23
+ );
24
+ }
@@ -0,0 +1,112 @@
1
+ const HARDWARE_SENSITIVE_METRIC = /(?:^|[_ -])(time|latency|throughput|memory|energy|runtime|duration|wall(?:[_ -]?clock)?|speed(?:up)?|flops?|joules?|watts?)(?:$|[_ -])/i;
2
+
3
+ export function commandVerifiesDependencies(value) {
4
+ const command = textValue(value) ?? "";
5
+ return /(?:\b(?:from\s+[A-Za-z_][A-Za-z0-9_.]*\s+import|import\s+[A-Za-z_][A-Za-z0-9_.]*)\b|\b(?:pip|pip3|uv\s+pip|npm|pnpm|yarn)\s+(?:check|show|list|ls|freeze)\b|(?:^|[;&|]\s*|\|\|\s*)(?:make|cmake|ninja)(?:\s|$)|\bcommand\s+-v\s+[A-Za-z0-9_.+-]+)/i.test(command);
6
+ }
7
+
8
+ export function isSimpleScriptEntrypoint(value) {
9
+ const entrypoint = textValue(value) ?? "";
10
+ if (/^[A-Za-z0-9._/-]+$/.test(entrypoint.trim())) return true;
11
+ return /^\s*(?:bash|sh|python(?:3(?:\.\d+)?)?)\s+(?:\/job\/workspace\/repository\/)?[A-Za-z0-9._/-]+\s*$/i
12
+ .test(entrypoint);
13
+ }
14
+
15
+ export function hardwareSensitiveMetric(value) {
16
+ return HARDWARE_SENSITIVE_METRIC.test(textValue(value) ?? "");
17
+ }
18
+
19
+ export function explicitlyUnderspecifiedHardwareProtocol(experiment, bindings = []) {
20
+ if (!bindings.some(({ measurement, reported }) =>
21
+ hardwareSensitiveMetric(measurement?.metric ?? reported?.metric))) return false;
22
+ const description = [
23
+ experiment?.title,
24
+ experiment?.protocol?.objective,
25
+ experiment?.protocol?.instructions,
26
+ ].map(textValue).filter(Boolean).join(" ");
27
+ return /(?:paper|article|source|authors?)[\s\S]{0,180}(?:does not|doesn't|did not|never|fails? to|without)[\s\S]{0,180}(?:provide|report|specify|identify|determine)[\s\S]{0,120}(?:hardware|cpu|gpu|device|host|thread|core|timer|timing|benchmark|callable|protocol|measurement conditions?)/i
28
+ .test(description)
29
+ || /(?:hardware|cpu|gpu|device|host|thread|core|timer|timing|benchmark|callable|protocol|measurement conditions?)[\s\S]{0,180}(?:not|never|unknown|unspecified|underspecified)[\s\S]{0,120}(?:paper|article|source|reported|provided|specified|identified|determined)/i
30
+ .test(description);
31
+ }
32
+
33
+ export function claimHasExplicitHardwareProtocolBlocker(claim) {
34
+ if (claim?.reproduction?.status !== "blocked") return false;
35
+ if (!(claim?.reportedMeasurements ?? []).some((measurement) =>
36
+ hardwareSensitiveMetric(measurement?.metric))) return false;
37
+ const reason = textValue(claim?.reproduction?.reason) ?? "";
38
+ return /(?:hardware|cpu|gpu|device|host|thread|core|timer|timing|benchmark|callable|protocol|measurement conditions?)[\s\S]{0,180}(?:unknown|missing|not (?:provided|reported|specified|identified|determined)|unspecified|underspecified)/i
39
+ .test(reason)
40
+ || /(?:unknown|missing|not (?:provided|reported|specified|identified|determined)|unspecified|underspecified)[\s\S]{0,180}(?:hardware|cpu|gpu|device|host|thread|core|timer|timing|benchmark|callable|protocol|measurement conditions?)/i
41
+ .test(reason);
42
+ }
43
+
44
+ export function sanitizeParserPreflightCommand(commandValue, bindings = []) {
45
+ let command = textValue(commandValue);
46
+ if (!command) return { command, replacements: [] };
47
+ const fixtureLike = /(?:fixture|parser[-_]?sample|write_text|write_bytes|json\.(?:loads|dump)|open\s*\([^)]*,\s*["']w|(?:printf|echo)\b)/i
48
+ .test(command);
49
+ if (!fixtureLike) return { command, replacements: [] };
50
+
51
+ const replacements = [];
52
+ for (const { measurement, reported } of bindings) {
53
+ if (typeof reported?.value !== "number" || !Number.isFinite(reported.value)) continue;
54
+ const scale = Number(measurement?.parser?.config?.scale ?? 1);
55
+ const offset = Number(measurement?.parser?.config?.offset ?? 0);
56
+ const candidates = [reported.value];
57
+ if (Number.isFinite(scale) && scale !== 0 && Number.isFinite(offset)) {
58
+ candidates.push(stableNumber((reported.value - offset) / scale));
59
+ }
60
+ const sentinel = Number.isFinite(scale) && Math.abs(scale) > 1
61
+ ? 0.314159
62
+ : 1.234567;
63
+ for (const candidate of [...new Set(candidates.filter(Number.isFinite))]) {
64
+ if (Math.abs(candidate - sentinel) < 1e-12) continue;
65
+ const literal = numericLiteralPattern(candidate);
66
+ const matcher = new RegExp(`(^|[:=,\\s"'\\[{(]|\\\\t)(${literal})(?![0-9.])`, "g");
67
+ const before = command;
68
+ command = command.replace(matcher, (_match, prefix) => `${prefix}${sentinel}`);
69
+ if (command !== before) replacements.push({
70
+ measurementId: measurement?.reportedMeasurementId ?? reported?.id ?? null,
71
+ target: candidate,
72
+ sentinel,
73
+ });
74
+ }
75
+ }
76
+ return { command, replacements };
77
+ }
78
+
79
+ export function parserPreflightTargetLeaks(commandValue, bindings = []) {
80
+ const command = textValue(commandValue);
81
+ if (!command) return [];
82
+ return bindings.flatMap(({ measurement, reported }) => {
83
+ if (typeof reported?.value !== "number" || !Number.isFinite(reported.value)) return [];
84
+ const scale = Number(measurement?.parser?.config?.scale ?? 1);
85
+ const offset = Number(measurement?.parser?.config?.offset ?? 0);
86
+ const candidates = [reported.value];
87
+ if (Number.isFinite(scale) && scale !== 0 && Number.isFinite(offset)) {
88
+ candidates.push(stableNumber((reported.value - offset) / scale));
89
+ }
90
+ return [...new Set(candidates.filter(Number.isFinite))].filter((candidate) => {
91
+ const literal = numericLiteralPattern(candidate);
92
+ return new RegExp(`(?:^|[:=,\\s"'\\[{(]|\\\\t)${literal}(?![0-9.])`).test(command);
93
+ });
94
+ });
95
+ }
96
+
97
+ function numericLiteralPattern(value) {
98
+ if (Number.isInteger(value)) return `${escapeRegExp(String(value))}(?:\\.0+)?`;
99
+ return escapeRegExp(String(value));
100
+ }
101
+
102
+ function stableNumber(value) {
103
+ return Number.isFinite(value) ? Number(value.toPrecision(12)) : value;
104
+ }
105
+
106
+ function escapeRegExp(value) {
107
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
108
+ }
109
+
110
+ function textValue(value) {
111
+ return typeof value === "string" && value.trim() ? value.trim() : null;
112
+ }
@@ -0,0 +1,3 @@
1
+ export function needsCompilerRepairGeneration(authorized, compilerStatus, cloudState) {
2
+ return authorized === true && compilerStatus === 'invalid_result' && cloudState === 'SUCCEEDED';
3
+ }