cool-workflow 0.1.98 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (306) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/README.md +11 -2
  4. package/apps/architecture-review/app.json +1 -1
  5. package/apps/architecture-review-fast/app.json +1 -1
  6. package/apps/end-to-end-golden-path/app.json +1 -1
  7. package/apps/pr-review-fix-ci/app.json +1 -1
  8. package/apps/release-cut/app.json +1 -1
  9. package/apps/research-synthesis/app.json +1 -1
  10. package/dist/cli/dispatch.js +236 -0
  11. package/dist/cli/entry.js +120 -0
  12. package/dist/cli/io.js +21 -4
  13. package/dist/cli/parseargv.js +157 -0
  14. package/dist/cli.js +6 -33
  15. package/dist/core/capability-table.js +3534 -0
  16. package/dist/core/format/help.js +314 -0
  17. package/dist/{state-explosion/format.js → core/format/state-explosion-text.js} +10 -1
  18. package/dist/core/hash.js +137 -0
  19. package/dist/core/multi-agent/candidate-scoring.js +219 -0
  20. package/dist/core/multi-agent/collaboration.js +481 -0
  21. package/dist/core/multi-agent/coordinator.js +515 -0
  22. package/dist/core/multi-agent/eval-replay.js +306 -0
  23. package/dist/core/multi-agent/runtime.js +929 -0
  24. package/dist/core/multi-agent/topology.js +298 -0
  25. package/dist/core/multi-agent/trust-policy.js +197 -0
  26. package/dist/core/pipeline/commit-gate.js +320 -0
  27. package/dist/{pipeline-contract.js → core/pipeline/contract.js} +24 -37
  28. package/dist/core/pipeline/dispatch.js +103 -0
  29. package/dist/core/pipeline/drive-decide.js +227 -0
  30. package/dist/core/pipeline/error-feedback.js +161 -0
  31. package/dist/core/pipeline/loop-expansion.js +124 -0
  32. package/dist/{result-normalize.js → core/pipeline/result-normalize.js} +14 -37
  33. package/dist/core/pipeline/runner.js +230 -0
  34. package/dist/{contract-migration.js → core/state/contract-migration.js} +68 -92
  35. package/dist/{state-migrations.js → core/state/migrations.js} +103 -96
  36. package/dist/core/state/node-projection.js +95 -0
  37. package/dist/core/state/node-snapshot.js +230 -0
  38. package/dist/core/state/run-paths.js +93 -0
  39. package/dist/{schema-validate.js → core/state/schema-validate.js} +35 -28
  40. package/dist/core/state/schema.js +50 -0
  41. package/dist/core/state/state-explosion/digest.js +243 -0
  42. package/dist/core/state/state-explosion/graph.js +527 -0
  43. package/dist/{state-explosion → core/state/state-explosion}/helpers.js +34 -3
  44. package/dist/core/state/state-explosion/report.js +187 -0
  45. package/dist/{state-explosion → core/state/state-explosion}/size.js +25 -7
  46. package/dist/{state-node.js → core/state/state-node.js} +90 -113
  47. package/dist/core/state/types.js +19 -0
  48. package/dist/{validation.js → core/state/validation.js} +64 -131
  49. package/dist/core/trust/evidence-grounding.js +134 -0
  50. package/dist/core/trust/ledger.js +199 -0
  51. package/dist/{telemetry-attestation.js → core/trust/telemetry-attestation.js} +94 -68
  52. package/dist/core/trust/telemetry-ledger.js +127 -0
  53. package/dist/core/types.js +20 -0
  54. package/dist/core/version.js +16 -0
  55. package/dist/{workflow-app-framework.js → core/workflow-apps/app-schema.js} +337 -426
  56. package/dist/mcp/dispatch.js +104 -0
  57. package/dist/mcp/server.js +144 -0
  58. package/dist/mcp-server.js +6 -84
  59. package/dist/{agent-config.js → shell/agent-config.js} +118 -71
  60. package/dist/shell/app-run-cli.js +88 -0
  61. package/dist/shell/audit-cli.js +259 -0
  62. package/dist/shell/audit-provenance.js +83 -0
  63. package/dist/shell/candidate-scoring-io.js +459 -0
  64. package/dist/shell/collaboration-io.js +264 -0
  65. package/dist/shell/commit-summary.js +104 -0
  66. package/dist/shell/commit.js +290 -0
  67. package/dist/shell/coordinator-io.js +476 -0
  68. package/dist/shell/demo-cli.js +19 -0
  69. package/dist/shell/dispatch.js +162 -0
  70. package/dist/{doctor.js → shell/doctor.js} +123 -56
  71. package/dist/shell/drive.js +873 -0
  72. package/dist/shell/error-feedback-io.js +305 -0
  73. package/dist/shell/eval-io.js +473 -0
  74. package/dist/{multi-agent-eval/format.js → shell/eval-text.js} +78 -49
  75. package/dist/{evidence-reasoning.js → shell/evidence-reasoning.js} +124 -255
  76. package/dist/shell/exec-backend-cli.js +88 -0
  77. package/dist/shell/execution-backend/agent.js +475 -0
  78. package/dist/shell/execution-backend/ci.js +15 -0
  79. package/dist/shell/execution-backend/container.js +69 -0
  80. package/dist/shell/execution-backend/envelopes.js +55 -0
  81. package/dist/shell/execution-backend/local.js +113 -0
  82. package/dist/shell/execution-backend/probes.js +175 -0
  83. package/dist/shell/execution-backend/registry.js +402 -0
  84. package/dist/shell/execution-backend/remote.js +128 -0
  85. package/dist/shell/execution-backend/types.js +11 -0
  86. package/dist/shell/feedback-cli.js +81 -0
  87. package/dist/shell/feedback-operations.js +48 -0
  88. package/dist/shell/fs-atomic.js +276 -0
  89. package/dist/shell/harness.js +98 -0
  90. package/dist/shell/ledger-cli.js +212 -0
  91. package/dist/shell/ledger-io.js +169 -0
  92. package/dist/shell/man-cli.js +89 -0
  93. package/dist/shell/metrics-cli.js +98 -0
  94. package/dist/shell/multi-agent-cli.js +1002 -0
  95. package/dist/shell/multi-agent-host.js +563 -0
  96. package/dist/shell/multi-agent-io.js +387 -0
  97. package/dist/{multi-agent-operator-ux.js → shell/multi-agent-operator-ux.js} +234 -191
  98. package/dist/shell/node-store.js +124 -0
  99. package/dist/{observability/format.js → shell/observability-format.js} +7 -1
  100. package/dist/{observability/intake.js → shell/observability-intake.js} +79 -56
  101. package/dist/{observability.js → shell/observability.js} +159 -332
  102. package/dist/{onramp.js → shell/onramp.js} +11 -0
  103. package/dist/{operator-ux/format.js → shell/operator-ux-text.js} +250 -239
  104. package/dist/shell/operator-ux.js +431 -0
  105. package/dist/shell/orchestrator.js +231 -0
  106. package/dist/shell/pipeline-cli.js +667 -0
  107. package/dist/shell/pipeline.js +217 -0
  108. package/dist/shell/reclamation-io.js +1366 -0
  109. package/dist/shell/registry-cli.js +329 -0
  110. package/dist/{remote-source.js → shell/remote-source.js} +2 -2
  111. package/dist/shell/report-cli.js +101 -0
  112. package/dist/shell/report-view-cli.js +117 -0
  113. package/dist/{orchestrator → shell}/report.js +289 -282
  114. package/dist/shell/reporter.js +62 -0
  115. package/dist/shell/run-export-cli.js +106 -0
  116. package/dist/shell/run-export.js +680 -0
  117. package/dist/shell/run-registry-io.js +1014 -0
  118. package/dist/shell/run-store.js +164 -0
  119. package/dist/{sandbox-profile.js → shell/sandbox-profile.js} +134 -95
  120. package/dist/{scheduler.js → shell/scheduler-io.js} +248 -48
  121. package/dist/shell/scheduling-io.js +311 -0
  122. package/dist/shell/state-cli.js +181 -0
  123. package/dist/shell/state-explosion-cli.js +197 -0
  124. package/dist/shell/telemetry-cli.js +85 -0
  125. package/dist/{telemetry-demo.js → shell/telemetry-demo.js} +149 -119
  126. package/dist/shell/telemetry-ledger-io.js +132 -0
  127. package/dist/{term.js → shell/term.js} +36 -46
  128. package/dist/shell/topology-io.js +361 -0
  129. package/dist/shell/trust-audit.js +471 -0
  130. package/dist/{multi-agent-trust.js → shell/trust-policy-io.js} +67 -205
  131. package/dist/shell/verifier.js +48 -0
  132. package/dist/shell/workbench-host.js +250 -0
  133. package/dist/shell/workbench-text.js +18 -0
  134. package/dist/shell/workbench.js +175 -0
  135. package/dist/shell/worker-cli.js +124 -0
  136. package/dist/shell/worker-isolation.js +852 -0
  137. package/dist/shell/workflow-app-loader.js +650 -0
  138. package/docs/agent-delegation-drive.7.md +2 -0
  139. package/docs/cli-mcp-parity.7.md +280 -219
  140. package/docs/contract-migration-tooling.7.md +2 -0
  141. package/docs/control-plane-scheduling.7.md +2 -0
  142. package/docs/durable-state-and-locking.7.md +2 -0
  143. package/docs/evidence-adoption-reasoning-chain.7.md +2 -0
  144. package/docs/execution-backends.7.md +2 -0
  145. package/docs/multi-agent-cli-mcp-surface.7.md +2 -0
  146. package/docs/multi-agent-eval-replay-harness.7.md +2 -0
  147. package/docs/multi-agent-operator-ux.7.md +2 -0
  148. package/docs/node-snapshot-diff-replay.7.md +2 -0
  149. package/docs/observability-cost-accounting.7.md +2 -0
  150. package/docs/project-index.md +132 -71
  151. package/docs/real-execution-backends.7.md +2 -0
  152. package/docs/release-and-migration.7.md +2 -0
  153. package/docs/release-tooling.7.md +2 -0
  154. package/docs/run-registry-control-plane.7.md +2 -0
  155. package/docs/run-retention-reclamation.7.md +23 -0
  156. package/docs/state-explosion-management.7.md +2 -0
  157. package/docs/team-collaboration.7.md +2 -0
  158. package/docs/web-desktop-workbench.7.md +2 -0
  159. package/manifest/plugin.manifest.json +1 -1
  160. package/manifest/source-context-profiles.json +9 -13
  161. package/package.json +1 -1
  162. package/scripts/agents/cw-attest-wrap.js +2 -2
  163. package/scripts/bump-version.js +4 -3
  164. package/scripts/canonical-apps.js +4 -4
  165. package/scripts/dogfood-architecture-review.js +2 -3
  166. package/scripts/dogfood-release.js +3 -3
  167. package/scripts/gen-parity-doc.js +15 -2
  168. package/scripts/golden-path.js +4 -4
  169. package/scripts/onramp-check.js +1 -1
  170. package/scripts/parity-check.js +38 -21
  171. package/scripts/release-flow.js +2 -2
  172. package/scripts/sync-project-index.js +51 -27
  173. package/scripts/validate-run-state-schema.js +2 -2
  174. package/scripts/version-sync-check.js +30 -30
  175. package/dist/candidate-scoring.js +0 -729
  176. package/dist/capability-core.js +0 -1189
  177. package/dist/capability-registry.js +0 -885
  178. package/dist/cli/command-surface.js +0 -494
  179. package/dist/cli/format.js +0 -56
  180. package/dist/cli/handlers/audit.js +0 -82
  181. package/dist/cli/handlers/blackboard.js +0 -81
  182. package/dist/cli/handlers/candidate.js +0 -40
  183. package/dist/cli/handlers/clones.js +0 -34
  184. package/dist/cli/handlers/collaboration.js +0 -61
  185. package/dist/cli/handlers/eval.js +0 -40
  186. package/dist/cli/handlers/ledger.js +0 -169
  187. package/dist/cli/handlers/maintenance.js +0 -107
  188. package/dist/cli/handlers/multi-agent.js +0 -165
  189. package/dist/cli/handlers/node.js +0 -41
  190. package/dist/cli/handlers/operational.js +0 -155
  191. package/dist/cli/handlers/operator.js +0 -146
  192. package/dist/cli/handlers/registry.js +0 -68
  193. package/dist/cli/handlers/run.js +0 -153
  194. package/dist/cli/handlers/scheduling.js +0 -132
  195. package/dist/cli/handlers/workbench.js +0 -41
  196. package/dist/cli/handlers/worker.js +0 -45
  197. package/dist/cli/run-summary.js +0 -45
  198. package/dist/clones.js +0 -162
  199. package/dist/collaboration.js +0 -726
  200. package/dist/commit.js +0 -592
  201. package/dist/compare.js +0 -18
  202. package/dist/coordinator/classify.js +0 -45
  203. package/dist/coordinator/paths.js +0 -42
  204. package/dist/coordinator/util.js +0 -126
  205. package/dist/coordinator.js +0 -990
  206. package/dist/daemon.js +0 -44
  207. package/dist/dispatch.js +0 -250
  208. package/dist/drive.js +0 -864
  209. package/dist/error-feedback.js +0 -419
  210. package/dist/evidence-grounding.js +0 -184
  211. package/dist/execution-backend/agent.js +0 -354
  212. package/dist/execution-backend/probes.js +0 -112
  213. package/dist/execution-backend/util.js +0 -47
  214. package/dist/execution-backend.js +0 -961
  215. package/dist/gates.js +0 -48
  216. package/dist/harness.js +0 -61
  217. package/dist/ledger.js +0 -313
  218. package/dist/loop-expansion.js +0 -60
  219. package/dist/mcp/tool-call.js +0 -470
  220. package/dist/mcp/tool-definitions.js +0 -1066
  221. package/dist/mcp-surface.js +0 -30
  222. package/dist/multi-agent/graph.js +0 -84
  223. package/dist/multi-agent/helpers.js +0 -141
  224. package/dist/multi-agent/ids.js +0 -20
  225. package/dist/multi-agent/paths.js +0 -22
  226. package/dist/multi-agent-eval/normalize.js +0 -51
  227. package/dist/multi-agent-eval.js +0 -678
  228. package/dist/multi-agent-host.js +0 -777
  229. package/dist/multi-agent.js +0 -984
  230. package/dist/node-projection.js +0 -59
  231. package/dist/node-snapshot.js +0 -260
  232. package/dist/operator-ux.js +0 -631
  233. package/dist/orchestrator/app-operations.js +0 -211
  234. package/dist/orchestrator/audit-operations.js +0 -182
  235. package/dist/orchestrator/candidate-operations.js +0 -117
  236. package/dist/orchestrator/cli-options.js +0 -294
  237. package/dist/orchestrator/collaboration-operations.js +0 -86
  238. package/dist/orchestrator/feedback-operations.js +0 -81
  239. package/dist/orchestrator/host-operations.js +0 -78
  240. package/dist/orchestrator/lifecycle-operations.js +0 -650
  241. package/dist/orchestrator/migration-operations.js +0 -44
  242. package/dist/orchestrator/multi-agent-operations.js +0 -362
  243. package/dist/orchestrator/topology-operations.js +0 -84
  244. package/dist/orchestrator.js +0 -925
  245. package/dist/pipeline-runner.js +0 -285
  246. package/dist/reclamation/hash.js +0 -72
  247. package/dist/reclamation.js +0 -812
  248. package/dist/reporter.js +0 -67
  249. package/dist/run-export.js +0 -815
  250. package/dist/run-registry/derive.js +0 -175
  251. package/dist/run-registry/format.js +0 -124
  252. package/dist/run-registry/gc.js +0 -251
  253. package/dist/run-registry/policy.js +0 -16
  254. package/dist/run-registry/queue.js +0 -115
  255. package/dist/run-registry.js +0 -850
  256. package/dist/run-state-schema.js +0 -68
  257. package/dist/scheduling.js +0 -184
  258. package/dist/state-explosion.js +0 -1014
  259. package/dist/state.js +0 -367
  260. package/dist/telemetry-ledger.js +0 -196
  261. package/dist/topology.js +0 -565
  262. package/dist/triggers.js +0 -184
  263. package/dist/trust-audit.js +0 -644
  264. package/dist/types/blackboard.js +0 -2
  265. package/dist/types/candidate.js +0 -2
  266. package/dist/types/collaboration.js +0 -2
  267. package/dist/types/core.js +0 -2
  268. package/dist/types/drive.js +0 -10
  269. package/dist/types/error-feedback.js +0 -2
  270. package/dist/types/evidence-reasoning.js +0 -2
  271. package/dist/types/execution-backend.js +0 -2
  272. package/dist/types/multi-agent.js +0 -2
  273. package/dist/types/observability.js +0 -2
  274. package/dist/types/pipeline.js +0 -2
  275. package/dist/types/reclamation.js +0 -8
  276. package/dist/types/report-bundle.js +0 -6
  277. package/dist/types/result.js +0 -2
  278. package/dist/types/run-registry.js +0 -2
  279. package/dist/types/run.js +0 -2
  280. package/dist/types/sandbox.js +0 -2
  281. package/dist/types/schedule.js +0 -2
  282. package/dist/types/state-node.js +0 -2
  283. package/dist/types/topology.js +0 -2
  284. package/dist/types/trust.js +0 -2
  285. package/dist/types/workbench.js +0 -2
  286. package/dist/types/worker.js +0 -2
  287. package/dist/types/workflow-app.js +0 -2
  288. package/dist/types.js +0 -44
  289. package/dist/util/fingerprint.js +0 -19
  290. package/dist/util/fingerprint.test.js +0 -27
  291. package/dist/verifier.js +0 -78
  292. package/dist/version.js +0 -8
  293. package/dist/workbench-host.js +0 -192
  294. package/dist/workbench.js +0 -192
  295. package/dist/worker-accept/acceptance.js +0 -114
  296. package/dist/worker-accept/blackboard-fanout.js +0 -80
  297. package/dist/worker-accept/blackboard-linkage.js +0 -19
  298. package/dist/worker-accept/context.js +0 -2
  299. package/dist/worker-accept/telemetry-ledger.js +0 -126
  300. package/dist/worker-accept/validation.js +0 -77
  301. package/dist/worker-accept/verifier-completion.js +0 -73
  302. package/dist/worker-isolation/helpers.js +0 -51
  303. package/dist/worker-isolation/paths.js +0 -46
  304. package/dist/worker-isolation.js +0 -656
  305. package/dist/workflow-api.js +0 -131
  306. /package/dist/{types → core/types}/boundary.js +0 -0
@@ -0,0 +1,230 @@
1
+ "use strict";
2
+ // core/pipeline/runner.ts — findRunnablePipelineStages, runPipelineStage
3
+ // (pure transform), advancePipeline, failPipelineStage.
4
+ //
5
+ // MILESTONE 6+7 (combined). Byte-exact port of the old build's
6
+ // src/pipeline-runner.ts, split so this file stays PURE (no fs — actual
7
+ // disk writes are the caller's `persist` callback, threaded through from
8
+ // shell/). The real per-stage disk write (node file + checkpoint) is
9
+ // shell/run-store.ts + shell/node-store.ts; this file only mutates the
10
+ // in-memory `run` object and returns what happened.
11
+ //
12
+ // Evidence: SPEC/pipeline-run.md "Pipeline kernel — src/pipeline-
13
+ // runner.ts".
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.getRunContract = getRunContract;
16
+ exports.getRunNode = getRunNode;
17
+ exports.findRunnablePipelineStages = findRunnablePipelineStages;
18
+ exports.runPipelineStage = runPipelineStage;
19
+ exports.advancePipeline = advancePipeline;
20
+ exports.failPipelineStage = failPipelineStage;
21
+ const state_node_1 = require("../state/state-node");
22
+ const contract_1 = require("./contract");
23
+ /** `getRunContract(run, contractId?)` — with no id, uses the default
24
+ * contract id; upserts the default contract onto the run if absent. An
25
+ * unknown non-default id throws. A found contract is re-validated. */
26
+ function getRunContract(run, contractId) {
27
+ const id = contractId || contract_1.DEFAULT_PIPELINE_CONTRACT_ID;
28
+ const contracts = run.contracts || [];
29
+ const found = contracts.find((c) => c.id === id);
30
+ if (found) {
31
+ (0, state_node_1.validatePipelineContract)(found);
32
+ return found;
33
+ }
34
+ if (id === contract_1.DEFAULT_PIPELINE_CONTRACT_ID) {
35
+ return (0, state_node_1.upsertRunContract)(run, (0, contract_1.createDefaultPipelineContract)());
36
+ }
37
+ throw new Error(`Unknown pipeline contract for run ${run.id}: ${id}`);
38
+ }
39
+ /** `getRunNode(run, nodeId)` — finds a node or throws. */
40
+ function getRunNode(run, nodeId) {
41
+ const node = (run.nodes || []).find((n) => n.id === nodeId);
42
+ if (!node)
43
+ throw new Error(`Unknown state node for run ${run.id}: ${nodeId}`);
44
+ return node;
45
+ }
46
+ /** Byte-exact port of the old build's `hasRequiredEvidence`: a stage's own
47
+ * `requiredEvidence` list AND the contract-wide
48
+ * `evidencePolicy.requireEvidence` flag both gate this pre-filter, exactly
49
+ * like assertRequiredEvidence's stricter check in state-node.ts — so a
50
+ * node findRunnablePipelineStages reports "runnable" never fails this
51
+ * same check again inside runPipelineStage. */
52
+ function evidenceSatisfied(node, stage, contract) {
53
+ const requiredEvidence = stage.requiredEvidence || [];
54
+ const contractRequiresEvidence = Boolean(contract.evidencePolicy?.requireEvidence);
55
+ if ((requiredEvidence.length || contractRequiresEvidence) && !node.evidence.length)
56
+ return false;
57
+ for (const required of requiredEvidence) {
58
+ const matches = node.evidence.filter((e) => e.id === required || e.source === required);
59
+ if (!matches.length)
60
+ return false;
61
+ }
62
+ return true;
63
+ }
64
+ function artifactsSatisfied(node, stage, pathExists) {
65
+ for (const required of stage.requiredArtifacts || []) {
66
+ const artifact = node.artifacts.find((a) => a.id === required || a.kind === required);
67
+ if (!artifact)
68
+ return false;
69
+ if (artifact.path && !pathExists(artifact.path))
70
+ return false;
71
+ }
72
+ return true;
73
+ }
74
+ function verifierGatePasses(node, stage, contract) {
75
+ const gate = stage.verifierGate;
76
+ const commitRequiresGate = Boolean(contract.commitPolicy?.requiresVerifierGate) && stage.producedOutputKind === "commit";
77
+ if (!gate?.required && !commitRequiresGate)
78
+ return true;
79
+ const acceptedStatuses = gate?.acceptedStatuses || contract.commitPolicy?.acceptedVerifierStatuses || ["verified"];
80
+ if (!acceptedStatuses.includes(node.status))
81
+ return false;
82
+ if ((gate?.requiredEvidence || contract.evidencePolicy?.requireEvidence) && !node.evidence.length)
83
+ return false;
84
+ return true;
85
+ }
86
+ /** `findRunnablePipelineStages(run, contract?)` — every node x every
87
+ * stage, kept only when kind/status/artifacts/evidence/verifier-gate all
88
+ * pass. */
89
+ function findRunnablePipelineStages(run, contract, pathExists = () => true) {
90
+ const resolvedContract = contract || getRunContract(run);
91
+ const out = [];
92
+ for (const node of run.nodes || []) {
93
+ for (const stage of resolvedContract.stages) {
94
+ if (!stage.acceptedInputKinds.includes(node.kind))
95
+ continue;
96
+ if (!stage.acceptedInputStatuses.includes(node.status))
97
+ continue;
98
+ if (!artifactsSatisfied(node, stage, pathExists))
99
+ continue;
100
+ if (!evidenceSatisfied(node, stage, resolvedContract))
101
+ continue;
102
+ if (!verifierGatePasses(node, stage, resolvedContract))
103
+ continue;
104
+ out.push({
105
+ runId: run.id,
106
+ contractId: resolvedContract.id,
107
+ stageId: stage.id,
108
+ inputNodeId: node.id,
109
+ outputKind: stage.producedOutputKind,
110
+ });
111
+ }
112
+ }
113
+ return out;
114
+ }
115
+ /** `runPipelineStage(run, stageId, inputNodeId, options?)` — the one-step
116
+ * engine. Mutates `run.nodes` in place (via appendRunNode/persist) and
117
+ * returns the result envelope. A thrown PipelineContractError becomes
118
+ * `failPipelineStage`; any other error re-throws untouched. */
119
+ function runPipelineStage(run, stageId, inputNodeId, options = {}, runnerOptions = {}) {
120
+ const contract = getRunContract(run, runnerOptions.contractId);
121
+ const inputNode = getRunNode(run, inputNodeId);
122
+ const pathExists = runnerOptions.pathExists || (() => true);
123
+ try {
124
+ (0, state_node_1.assertNodeSatisfiesContract)(inputNode, contract, stageId, pathExists);
125
+ }
126
+ catch (error) {
127
+ if (error instanceof state_node_1.PipelineContractError) {
128
+ return failPipelineStage(run, stageId, inputNode, error, runnerOptions);
129
+ }
130
+ throw error;
131
+ }
132
+ const stage = contract.stages.find((s) => s.id === stageId);
133
+ const targetStatus = options.outputStatus || (stage.producedOutputKind === "commit" ? "committed" : "completed");
134
+ const initialStatus = targetStatus === "committed" ? "verified" : "pending";
135
+ let outputNode = (0, state_node_1.createStateNode)({
136
+ id: options.outputNodeId,
137
+ kind: stage.producedOutputKind,
138
+ status: initialStatus,
139
+ loopStage: options.loopStage || inputNode.loopStage,
140
+ inputs: options.inputs,
141
+ outputs: options.outputs,
142
+ artifacts: options.artifacts,
143
+ evidence: options.evidence,
144
+ contractId: contract.id,
145
+ metadata: options.metadata,
146
+ });
147
+ if (targetStatus !== initialStatus) {
148
+ outputNode = (0, state_node_1.transitionStateNode)(outputNode, {
149
+ status: targetStatus,
150
+ loopStage: options.loopStage,
151
+ outputs: options.outputs,
152
+ artifacts: options.artifacts,
153
+ evidence: options.evidence,
154
+ metadata: options.metadata,
155
+ });
156
+ }
157
+ const persistNode = options.persist === false || runnerOptions.persist === false ? undefined : runnerOptions.persistNode;
158
+ const [linkedInput, linkedOutput] = (0, state_node_1.linkStateNodes)(inputNode, outputNode);
159
+ (0, state_node_1.appendRunNode)(run, linkedInput, persistNode);
160
+ (0, state_node_1.appendRunNode)(run, linkedOutput, persistNode);
161
+ if (options.persist !== false && runnerOptions.persist !== false && runnerOptions.saveCheckpoint) {
162
+ runnerOptions.saveCheckpoint(run);
163
+ }
164
+ return {
165
+ status: "advanced",
166
+ runId: run.id,
167
+ stageId,
168
+ inputNodeId: inputNode.id,
169
+ outputNodeId: linkedOutput.id,
170
+ outputKind: stage.producedOutputKind,
171
+ };
172
+ }
173
+ /** `advancePipeline(run, options?)` — first runnable stage list; empty ⇒
174
+ * idle. First "advanced" result stops. A "failed" result stops unless
175
+ * `contract.failurePolicy.autoAdvance`. */
176
+ function advancePipeline(run, runnerOptions = {}) {
177
+ const contract = getRunContract(run, runnerOptions.contractId);
178
+ const stages = findRunnablePipelineStages(run, contract, runnerOptions.pathExists);
179
+ if (!stages.length)
180
+ return { status: "idle", stages: [] };
181
+ let lastFailure;
182
+ for (const candidate of stages) {
183
+ const result = runPipelineStage(run, candidate.stageId, candidate.inputNodeId, {}, runnerOptions);
184
+ if (result.status === "advanced") {
185
+ return { ...result, stages };
186
+ }
187
+ lastFailure = { ...result, stages };
188
+ if (!contract.failurePolicy?.autoAdvance)
189
+ return lastFailure;
190
+ }
191
+ return lastFailure || { status: "idle", stages };
192
+ }
193
+ function failPipelineStage(run, stageId, inputNode, error, options = {}) {
194
+ const contract = getRunContract(run, options.contractId);
195
+ const stage = contract.stages.find((s) => s.id === stageId);
196
+ const structured = error instanceof state_node_1.PipelineContractError
197
+ ? error.structured
198
+ : {
199
+ code: "pipeline-stage-error",
200
+ message: error instanceof Error ? error.message : String(error),
201
+ at: options.now || new Date().toISOString(),
202
+ nodeId: inputNode.id,
203
+ retryable: stage?.failure?.retryable ?? contract.failurePolicy?.retryableByDefault ?? false,
204
+ };
205
+ const preserve = options.preserveFailureNode ?? stage?.failure?.preserveFailureNode ?? contract.failurePolicy?.preserveFailureNodes ?? false;
206
+ if (!preserve) {
207
+ return { status: "failed", runId: run.id, stageId, inputNodeId: inputNode.id, error: structured };
208
+ }
209
+ const persistNode = options.persist === false ? undefined : options.persistNode;
210
+ let errorNode = (0, state_node_1.recordNodeError)((0, state_node_1.createStateNode)({
211
+ // Honor a caller-supplied failure node id when given (shell binds it to
212
+ // the caller's outputNodeId); else auto-mint (`error-<hash>`).
213
+ ...(options.failureNodeId ? { id: options.failureNodeId } : {}),
214
+ kind: stage?.failure?.failureKind || "error",
215
+ status: "pending",
216
+ loopStage: inputNode.loopStage,
217
+ contractId: contract.id,
218
+ // `pipelineStage` names the stage that failed so collectRunErrors's
219
+ // dedup key matches the feedback recorded here (both key on stageId).
220
+ // Byte-behavior port of the old build's failed-node metadata.
221
+ metadata: { pipelineStage: stageId, preserved: true },
222
+ }), structured);
223
+ const [linkedInput, linkedError] = (0, state_node_1.linkStateNodes)(inputNode, errorNode);
224
+ (0, state_node_1.appendRunNode)(run, linkedInput, persistNode);
225
+ (0, state_node_1.appendRunNode)(run, linkedError, persistNode);
226
+ errorNode = linkedError;
227
+ if (options.recordFeedback)
228
+ options.recordFeedback(run, structured, errorNode.id);
229
+ return { status: "failed", runId: run.id, stageId, inputNodeId: inputNode.id, outputNodeId: errorNode.id, error: structured };
230
+ }
@@ -1,62 +1,31 @@
1
1
  "use strict";
2
- // Contract Migration Tooling (v0.1.36)a first-class, declared migration
3
- // subsystem over the existing run-state migration pipeline, extended to the
4
- // workflow-app schema.
2
+ // core/state/contract-migration.tsdeclared migration registry + prover.
5
3
  //
6
- // BSD discipline:
7
- // - MECHANISM, not policy: a declared registry of edges per contract is the
8
- // single source for "what versions exist and how to advance them". The caller
9
- // names the contract + snapshot; nothing guesses.
10
- // - FAIL CLOSED ON REACHABILITY [load-bearing]: before transforming, resolve the
11
- // full chain detected -> CURRENT. Below minimum, above current, or no chained
12
- // path REFUSES with a named unsupported verdict and NO write — never a
13
- // best-effort partial migration.
14
- // - REUSE, don't fork: run-state edges ARE RUN_STATE_MIGRATIONS; the chain runner
15
- // wraps the existing migrateRunState. No transform logic is duplicated.
16
- // - APPEND-ONLY / NON-DESTRUCTIVE: the prover proves every source key survives,
17
- // the result validates at CURRENT, re-running is idempotent, and the source
18
- // snapshot is byte-immutable (hash-before == hash-after).
19
- // - DETERMINISTIC: proofs are sha256-fingerprinted; no wall-clock in the payload.
4
+ // MILESTONE 3. Byte-exact port of the old build's src/contract-migration.ts
5
+ // (renamed target per v2/PLAN.md's module layout note listed there as
6
+ // `pipeline/contract-migration.ts`, kept here under state/ since every
7
+ // symbol it needs RUN_STATE_MIGRATIONS, migrateRunState,
8
+ // findMigrationPath is this milestone's own state kernel and nothing in
9
+ // `pipeline/` exists yet). Pure: proofs are sha256-fingerprinted; no
10
+ // wall-clock in the payload.
20
11
  //
21
- // See docs/contract-migration-tooling.7.md.
22
- var __importDefault = (this && this.__importDefault) || function (mod) {
23
- return (mod && mod.__esModule) ? mod : { "default": mod };
24
- };
12
+ // Evidence: SPEC/state-core.md "src/contract-migration.ts — declared
13
+ // migration registry + prover", "MigrationVerdict / MigrationProof JSON",
14
+ // "Contract-migration prover invariants".
25
15
  Object.defineProperty(exports, "__esModule", { value: true });
26
16
  exports.CONTRACT_MIGRATION_SCHEMA_VERSION = void 0;
27
17
  exports.listMigrationContracts = listMigrationContracts;
28
18
  exports.resolveChain = resolveChain;
29
19
  exports.checkMigration = checkMigration;
30
20
  exports.proveMigration = proveMigration;
31
- const node_crypto_1 = __importDefault(require("node:crypto"));
32
- const version_1 = require("./version");
33
- const state_migrations_1 = require("./state-migrations");
21
+ const hash_1 = require("../hash");
22
+ const version_1 = require("../version");
23
+ const migrations_1 = require("./migrations");
34
24
  exports.CONTRACT_MIGRATION_SCHEMA_VERSION = 1;
35
25
  function isRecord(value) {
36
26
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
37
27
  }
38
- /** Deterministic, key-sorted, EXACT content hash (not normalized — used to prove
39
- * the source snapshot was not mutated). */
40
- function stableHash(value) {
41
- const sort = (v) => Array.isArray(v)
42
- ? v.map(sort)
43
- : isRecord(v)
44
- ? Object.keys(v)
45
- .sort()
46
- .reduce((out, key) => {
47
- out[key] = sort(v[key]);
48
- return out;
49
- }, {})
50
- : v;
51
- return `sha256:${node_crypto_1.default.createHash("sha256").update(JSON.stringify(sort(value))).digest("hex")}`;
52
- }
53
- // ---------------------------------------------------------------------------
54
- // The declared registry. run-state edges ARE RUN_STATE_MIGRATIONS (no fork). The
55
- // workflow-app contract is declared with its current version; it has no edges yet
56
- // (only schema 1 exists) — an older app fails closed with a precise reason rather
57
- // than being silently accepted or flatly rejected.
58
- // ---------------------------------------------------------------------------
59
- const RUN_STATE_EDGES = state_migrations_1.RUN_STATE_MIGRATIONS.map((step) => ({
28
+ const RUN_STATE_EDGES = migrations_1.RUN_STATE_MIGRATIONS.map((step) => ({
60
29
  contract: "run-state",
61
30
  from: step.from,
62
31
  to: step.to,
@@ -64,8 +33,8 @@ const RUN_STATE_EDGES = state_migrations_1.RUN_STATE_MIGRATIONS.map((step) => ({
64
33
  proof: {
65
34
  invariant: `run-state ${step.from} -> ${step.to}: adds defaults only, drops no existing key`,
66
35
  addsDefaulted: ["schemaVersion"],
67
- dropsNothing: true
68
- }
36
+ dropsNothing: true,
37
+ },
69
38
  }));
70
39
  function listMigrationContracts() {
71
40
  return [
@@ -73,14 +42,14 @@ function listMigrationContracts() {
73
42
  contract: "run-state",
74
43
  currentVersion: version_1.CURRENT_RUN_STATE_SCHEMA_VERSION,
75
44
  minVersion: version_1.MIN_SUPPORTED_RUN_STATE_SCHEMA_VERSION,
76
- edges: RUN_STATE_EDGES
45
+ edges: RUN_STATE_EDGES,
77
46
  },
78
47
  {
79
48
  contract: "workflow-app",
80
49
  currentVersion: version_1.WORKFLOW_APP_SCHEMA_VERSION,
81
50
  minVersion: version_1.WORKFLOW_APP_SCHEMA_VERSION,
82
- edges: []
83
- }
51
+ edges: [],
52
+ },
84
53
  ];
85
54
  }
86
55
  function getContract(contractId) {
@@ -95,20 +64,27 @@ function detectVersion(contractId, snapshot) {
95
64
  return declared;
96
65
  return contractId === "run-state" ? version_1.LEGACY_RUN_STATE_SCHEMA_VERSION : 0;
97
66
  }
98
- /** Fail-closed reachability: detected -> current using the DAG path resolver. */
67
+ /** Fail-closed reachability: detected -> current using the DAG path
68
+ * resolver (run-state) or a simple edge walk (workflow-app). */
99
69
  function resolveChain(contract, detected) {
100
70
  if (detected < contract.minVersion) {
101
- return { reachable: false, chain: [], error: `${contract.contract} schemaVersion ${detected} is below the minimum supported ${contract.minVersion}` };
71
+ return {
72
+ reachable: false,
73
+ chain: [],
74
+ error: `${contract.contract} schemaVersion ${detected} is below the minimum supported ${contract.minVersion}`,
75
+ };
102
76
  }
103
77
  if (detected > contract.currentVersion) {
104
- return { reachable: false, chain: [], error: `${contract.contract} schemaVersion ${detected} is newer than this runtime (${contract.currentVersion})` };
78
+ return {
79
+ reachable: false,
80
+ chain: [],
81
+ error: `${contract.contract} schemaVersion ${detected} is newer than this runtime (${contract.currentVersion})`,
82
+ };
105
83
  }
106
- // Use the run-state migration DAG path resolver when applicable
107
84
  if (contract.contract === "run-state") {
108
- const resolved = (0, state_migrations_1.findMigrationPath)(state_migrations_1.RUN_STATE_MIGRATIONS, detected, contract.currentVersion);
85
+ const resolved = (0, migrations_1.findMigrationPath)(migrations_1.RUN_STATE_MIGRATIONS, detected, contract.currentVersion);
109
86
  if (!resolved.reachable)
110
87
  return { reachable: false, chain: [], error: resolved.error };
111
- // Derive the version chain from the path
112
88
  const chain = [detected];
113
89
  let v = detected;
114
90
  for (const step of resolved.path) {
@@ -117,13 +93,15 @@ function resolveChain(contract, detected) {
117
93
  }
118
94
  return { reachable: true, chain };
119
95
  }
120
- // workflow-app: no edges yet, simple check
121
96
  if (contract.edges.length === 0) {
122
97
  if (detected === contract.currentVersion)
123
98
  return { reachable: true, chain: [detected] };
124
- return { reachable: false, chain: [], error: `${contract.contract} schemaVersion ${detected} is not current (${contract.currentVersion}) and no migration edges exist` };
99
+ return {
100
+ reachable: false,
101
+ chain: [],
102
+ error: `${contract.contract} schemaVersion ${detected} is not current (${contract.currentVersion}) and no migration edges exist`,
103
+ };
125
104
  }
126
- // Generic edge-based chain resolution
127
105
  const chain = [detected];
128
106
  let version = detected;
129
107
  while (version < contract.currentVersion) {
@@ -136,7 +114,8 @@ function resolveChain(contract, detected) {
136
114
  }
137
115
  return { reachable: true, chain };
138
116
  }
139
- /** Dry-run verdict: detect, resolve, and (run-state) run the migration to report. */
117
+ /** Dry-run verdict: detect, resolve, and (run-state) run the migration to
118
+ * report. */
140
119
  function checkMigration(contractId, snapshot) {
141
120
  const contract = getContract(contractId);
142
121
  const detectedVersion = detectVersion(contractId, snapshot);
@@ -147,23 +126,37 @@ function checkMigration(contractId, snapshot) {
147
126
  detectedVersion,
148
127
  currentVersion: contract.currentVersion,
149
128
  reachable: resolved.reachable,
150
- chain: resolved.chain
129
+ chain: resolved.chain,
151
130
  };
152
131
  if (!resolved.reachable) {
153
132
  return { ...base, status: "unsupported", changes: 0, errors: [resolved.error || "unreachable"] };
154
133
  }
155
134
  if (contractId === "run-state") {
156
- const { report } = (0, state_migrations_1.migrateRunState)(snapshot, { dryRun: true });
135
+ const { report } = (0, migrations_1.migrateRunState)(snapshot, { dryRun: true });
157
136
  return { ...base, status: report.status, changes: report.changes.length, errors: report.errors };
158
137
  }
159
- // workflow-app: reachable + no edges => detected === current.
160
138
  return { ...base, status: "current", changes: 0, errors: [] };
161
139
  }
162
- /** Round-trip / non-destruction prover. Fail-closed: an unsupported verdict never
163
- * transforms and never claims a positive proof. */
140
+ /** Append-only proof: every key in the source survives into the output
141
+ * (recursive). */
142
+ function keysSurvive(source, output) {
143
+ if (!isRecord(source))
144
+ return true;
145
+ if (!isRecord(output))
146
+ return false;
147
+ for (const key of Object.keys(source)) {
148
+ if (!(key in output))
149
+ return false;
150
+ if (!keysSurvive(source[key], output[key]))
151
+ return false;
152
+ }
153
+ return true;
154
+ }
155
+ /** Round-trip / non-destruction prover. Fail-closed: an unsupported
156
+ * verdict never transforms and never claims a positive proof. */
164
157
  function proveMigration(contractId, snapshot) {
165
158
  const verdict = checkMigration(contractId, snapshot);
166
- const sourceHash = stableHash(snapshot);
159
+ const sourceHash = (0, hash_1.stableHash)(snapshot);
167
160
  const errors = [...verdict.errors];
168
161
  let validatesAtCurrent = false;
169
162
  let appendOnly = false;
@@ -171,27 +164,24 @@ function proveMigration(contractId, snapshot) {
171
164
  let result = snapshot;
172
165
  if (verdict.status !== "unsupported") {
173
166
  if (contractId === "run-state") {
174
- const migrated = (0, state_migrations_1.migrateRunState)(snapshot);
167
+ const migrated = (0, migrations_1.migrateRunState)(snapshot);
175
168
  result = migrated.run;
176
169
  validatesAtCurrent =
177
- migrated.report.status !== "unsupported" &&
178
- isRecord(result) &&
179
- result.schemaVersion === version_1.CURRENT_RUN_STATE_SCHEMA_VERSION;
170
+ migrated.report.status !== "unsupported" && isRecord(result) && result.schemaVersion === version_1.CURRENT_RUN_STATE_SCHEMA_VERSION;
180
171
  appendOnly = keysSurvive(snapshot, result);
181
- const reRun = (0, state_migrations_1.migrateRunState)(result, { dryRun: true });
172
+ const reRun = (0, migrations_1.migrateRunState)(result, { dryRun: true });
182
173
  idempotent = reRun.report.changes.length === 0 && reRun.report.status === "current";
183
174
  }
184
175
  else {
185
- // workflow-app at current: pass-through, nothing to transform.
186
176
  validatesAtCurrent = verdict.status === "current";
187
177
  appendOnly = true;
188
178
  idempotent = true;
189
179
  }
190
180
  }
191
- const sourceImmutable = stableHash(snapshot) === sourceHash;
192
- const resultHash = stableHash(result);
181
+ const sourceImmutable = (0, hash_1.stableHash)(snapshot) === sourceHash;
182
+ const resultHash = (0, hash_1.stableHash)(result);
193
183
  const pass = validatesAtCurrent && appendOnly && idempotent && sourceImmutable && errors.length === 0;
194
- const fingerprint = stableHash({
184
+ const fingerprint = (0, hash_1.stableHash)({
195
185
  contract: contractId,
196
186
  detectedVersion: verdict.detectedVersion,
197
187
  chain: verdict.chain,
@@ -201,7 +191,7 @@ function proveMigration(contractId, snapshot) {
201
191
  idempotent,
202
192
  sourceImmutable,
203
193
  sourceHash,
204
- resultHash
194
+ resultHash,
205
195
  });
206
196
  return {
207
197
  schemaVersion: 1,
@@ -215,20 +205,6 @@ function proveMigration(contractId, snapshot) {
215
205
  sourceHash,
216
206
  resultHash,
217
207
  fingerprint,
218
- errors
208
+ errors,
219
209
  };
220
210
  }
221
- /** Append-only proof: every key in the source survives into the output (recursive). */
222
- function keysSurvive(source, output) {
223
- if (!isRecord(source))
224
- return true;
225
- if (!isRecord(output))
226
- return false;
227
- for (const key of Object.keys(source)) {
228
- if (!(key in output))
229
- return false;
230
- if (!keysSurvive(source[key], output[key]))
231
- return false;
232
- }
233
- return true;
234
- }