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.
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +11 -2
- package/apps/architecture-review/app.json +1 -1
- package/apps/architecture-review-fast/app.json +1 -1
- package/apps/end-to-end-golden-path/app.json +1 -1
- package/apps/pr-review-fix-ci/app.json +1 -1
- package/apps/release-cut/app.json +1 -1
- package/apps/research-synthesis/app.json +1 -1
- package/dist/cli/dispatch.js +236 -0
- package/dist/cli/entry.js +120 -0
- package/dist/cli/io.js +21 -4
- package/dist/cli/parseargv.js +157 -0
- package/dist/cli.js +6 -33
- package/dist/core/capability-table.js +3534 -0
- package/dist/core/format/help.js +314 -0
- package/dist/{state-explosion/format.js → core/format/state-explosion-text.js} +10 -1
- package/dist/core/hash.js +137 -0
- package/dist/core/multi-agent/candidate-scoring.js +219 -0
- package/dist/core/multi-agent/collaboration.js +481 -0
- package/dist/core/multi-agent/coordinator.js +515 -0
- package/dist/core/multi-agent/eval-replay.js +306 -0
- package/dist/core/multi-agent/runtime.js +929 -0
- package/dist/core/multi-agent/topology.js +298 -0
- package/dist/core/multi-agent/trust-policy.js +197 -0
- package/dist/core/pipeline/commit-gate.js +320 -0
- package/dist/{pipeline-contract.js → core/pipeline/contract.js} +24 -37
- package/dist/core/pipeline/dispatch.js +103 -0
- package/dist/core/pipeline/drive-decide.js +227 -0
- package/dist/core/pipeline/error-feedback.js +161 -0
- package/dist/core/pipeline/loop-expansion.js +124 -0
- package/dist/{result-normalize.js → core/pipeline/result-normalize.js} +14 -37
- package/dist/core/pipeline/runner.js +230 -0
- package/dist/{contract-migration.js → core/state/contract-migration.js} +68 -92
- package/dist/{state-migrations.js → core/state/migrations.js} +103 -96
- package/dist/core/state/node-projection.js +95 -0
- package/dist/core/state/node-snapshot.js +230 -0
- package/dist/core/state/run-paths.js +93 -0
- package/dist/{schema-validate.js → core/state/schema-validate.js} +35 -28
- package/dist/core/state/schema.js +50 -0
- package/dist/core/state/state-explosion/digest.js +243 -0
- package/dist/core/state/state-explosion/graph.js +527 -0
- package/dist/{state-explosion → core/state/state-explosion}/helpers.js +34 -3
- package/dist/core/state/state-explosion/report.js +187 -0
- package/dist/{state-explosion → core/state/state-explosion}/size.js +25 -7
- package/dist/{state-node.js → core/state/state-node.js} +90 -113
- package/dist/core/state/types.js +19 -0
- package/dist/{validation.js → core/state/validation.js} +64 -131
- package/dist/core/trust/evidence-grounding.js +134 -0
- package/dist/core/trust/ledger.js +199 -0
- package/dist/{telemetry-attestation.js → core/trust/telemetry-attestation.js} +94 -68
- package/dist/core/trust/telemetry-ledger.js +127 -0
- package/dist/core/types.js +20 -0
- package/dist/core/version.js +16 -0
- package/dist/{workflow-app-framework.js → core/workflow-apps/app-schema.js} +337 -426
- package/dist/mcp/dispatch.js +104 -0
- package/dist/mcp/server.js +144 -0
- package/dist/mcp-server.js +6 -84
- package/dist/{agent-config.js → shell/agent-config.js} +118 -71
- package/dist/shell/app-run-cli.js +88 -0
- package/dist/shell/audit-cli.js +259 -0
- package/dist/shell/audit-provenance.js +83 -0
- package/dist/shell/candidate-scoring-io.js +459 -0
- package/dist/shell/collaboration-io.js +264 -0
- package/dist/shell/commit-summary.js +104 -0
- package/dist/shell/commit.js +290 -0
- package/dist/shell/coordinator-io.js +476 -0
- package/dist/shell/demo-cli.js +19 -0
- package/dist/shell/dispatch.js +162 -0
- package/dist/{doctor.js → shell/doctor.js} +123 -56
- package/dist/shell/drive.js +873 -0
- package/dist/shell/error-feedback-io.js +305 -0
- package/dist/shell/eval-io.js +473 -0
- package/dist/{multi-agent-eval/format.js → shell/eval-text.js} +78 -49
- package/dist/{evidence-reasoning.js → shell/evidence-reasoning.js} +124 -255
- package/dist/shell/exec-backend-cli.js +88 -0
- package/dist/shell/execution-backend/agent.js +475 -0
- package/dist/shell/execution-backend/ci.js +15 -0
- package/dist/shell/execution-backend/container.js +69 -0
- package/dist/shell/execution-backend/envelopes.js +55 -0
- package/dist/shell/execution-backend/local.js +113 -0
- package/dist/shell/execution-backend/probes.js +175 -0
- package/dist/shell/execution-backend/registry.js +402 -0
- package/dist/shell/execution-backend/remote.js +128 -0
- package/dist/shell/execution-backend/types.js +11 -0
- package/dist/shell/feedback-cli.js +81 -0
- package/dist/shell/feedback-operations.js +48 -0
- package/dist/shell/fs-atomic.js +276 -0
- package/dist/shell/harness.js +98 -0
- package/dist/shell/ledger-cli.js +212 -0
- package/dist/shell/ledger-io.js +169 -0
- package/dist/shell/man-cli.js +89 -0
- package/dist/shell/metrics-cli.js +98 -0
- package/dist/shell/multi-agent-cli.js +1002 -0
- package/dist/shell/multi-agent-host.js +563 -0
- package/dist/shell/multi-agent-io.js +387 -0
- package/dist/{multi-agent-operator-ux.js → shell/multi-agent-operator-ux.js} +234 -191
- package/dist/shell/node-store.js +124 -0
- package/dist/{observability/format.js → shell/observability-format.js} +7 -1
- package/dist/{observability/intake.js → shell/observability-intake.js} +79 -56
- package/dist/{observability.js → shell/observability.js} +159 -332
- package/dist/{onramp.js → shell/onramp.js} +11 -0
- package/dist/{operator-ux/format.js → shell/operator-ux-text.js} +250 -239
- package/dist/shell/operator-ux.js +431 -0
- package/dist/shell/orchestrator.js +231 -0
- package/dist/shell/pipeline-cli.js +667 -0
- package/dist/shell/pipeline.js +217 -0
- package/dist/shell/reclamation-io.js +1366 -0
- package/dist/shell/registry-cli.js +329 -0
- package/dist/{remote-source.js → shell/remote-source.js} +2 -2
- package/dist/shell/report-cli.js +101 -0
- package/dist/shell/report-view-cli.js +117 -0
- package/dist/{orchestrator → shell}/report.js +289 -282
- package/dist/shell/reporter.js +62 -0
- package/dist/shell/run-export-cli.js +106 -0
- package/dist/shell/run-export.js +680 -0
- package/dist/shell/run-registry-io.js +1014 -0
- package/dist/shell/run-store.js +164 -0
- package/dist/{sandbox-profile.js → shell/sandbox-profile.js} +134 -95
- package/dist/{scheduler.js → shell/scheduler-io.js} +248 -48
- package/dist/shell/scheduling-io.js +311 -0
- package/dist/shell/state-cli.js +181 -0
- package/dist/shell/state-explosion-cli.js +197 -0
- package/dist/shell/telemetry-cli.js +85 -0
- package/dist/{telemetry-demo.js → shell/telemetry-demo.js} +149 -119
- package/dist/shell/telemetry-ledger-io.js +132 -0
- package/dist/{term.js → shell/term.js} +36 -46
- package/dist/shell/topology-io.js +361 -0
- package/dist/shell/trust-audit.js +471 -0
- package/dist/{multi-agent-trust.js → shell/trust-policy-io.js} +67 -205
- package/dist/shell/verifier.js +48 -0
- package/dist/shell/workbench-host.js +250 -0
- package/dist/shell/workbench-text.js +18 -0
- package/dist/shell/workbench.js +175 -0
- package/dist/shell/worker-cli.js +124 -0
- package/dist/shell/worker-isolation.js +852 -0
- package/dist/shell/workflow-app-loader.js +650 -0
- package/docs/agent-delegation-drive.7.md +2 -0
- package/docs/cli-mcp-parity.7.md +280 -219
- package/docs/contract-migration-tooling.7.md +2 -0
- package/docs/control-plane-scheduling.7.md +2 -0
- package/docs/durable-state-and-locking.7.md +2 -0
- package/docs/evidence-adoption-reasoning-chain.7.md +2 -0
- package/docs/execution-backends.7.md +2 -0
- package/docs/multi-agent-cli-mcp-surface.7.md +2 -0
- package/docs/multi-agent-eval-replay-harness.7.md +2 -0
- package/docs/multi-agent-operator-ux.7.md +2 -0
- package/docs/node-snapshot-diff-replay.7.md +2 -0
- package/docs/observability-cost-accounting.7.md +2 -0
- package/docs/project-index.md +132 -71
- package/docs/real-execution-backends.7.md +2 -0
- package/docs/release-and-migration.7.md +2 -0
- package/docs/release-tooling.7.md +2 -0
- package/docs/run-registry-control-plane.7.md +2 -0
- package/docs/run-retention-reclamation.7.md +23 -0
- package/docs/state-explosion-management.7.md +2 -0
- package/docs/team-collaboration.7.md +2 -0
- package/docs/web-desktop-workbench.7.md +2 -0
- package/manifest/plugin.manifest.json +1 -1
- package/manifest/source-context-profiles.json +9 -13
- package/package.json +1 -1
- package/scripts/agents/cw-attest-wrap.js +2 -2
- package/scripts/bump-version.js +4 -3
- package/scripts/canonical-apps.js +4 -4
- package/scripts/dogfood-architecture-review.js +2 -3
- package/scripts/dogfood-release.js +3 -3
- package/scripts/gen-parity-doc.js +15 -2
- package/scripts/golden-path.js +4 -4
- package/scripts/onramp-check.js +1 -1
- package/scripts/parity-check.js +38 -21
- package/scripts/release-flow.js +2 -2
- package/scripts/sync-project-index.js +51 -27
- package/scripts/validate-run-state-schema.js +2 -2
- package/scripts/version-sync-check.js +30 -30
- package/dist/candidate-scoring.js +0 -729
- package/dist/capability-core.js +0 -1189
- package/dist/capability-registry.js +0 -885
- package/dist/cli/command-surface.js +0 -494
- package/dist/cli/format.js +0 -56
- package/dist/cli/handlers/audit.js +0 -82
- package/dist/cli/handlers/blackboard.js +0 -81
- package/dist/cli/handlers/candidate.js +0 -40
- package/dist/cli/handlers/clones.js +0 -34
- package/dist/cli/handlers/collaboration.js +0 -61
- package/dist/cli/handlers/eval.js +0 -40
- package/dist/cli/handlers/ledger.js +0 -169
- package/dist/cli/handlers/maintenance.js +0 -107
- package/dist/cli/handlers/multi-agent.js +0 -165
- package/dist/cli/handlers/node.js +0 -41
- package/dist/cli/handlers/operational.js +0 -155
- package/dist/cli/handlers/operator.js +0 -146
- package/dist/cli/handlers/registry.js +0 -68
- package/dist/cli/handlers/run.js +0 -153
- package/dist/cli/handlers/scheduling.js +0 -132
- package/dist/cli/handlers/workbench.js +0 -41
- package/dist/cli/handlers/worker.js +0 -45
- package/dist/cli/run-summary.js +0 -45
- package/dist/clones.js +0 -162
- package/dist/collaboration.js +0 -726
- package/dist/commit.js +0 -592
- package/dist/compare.js +0 -18
- package/dist/coordinator/classify.js +0 -45
- package/dist/coordinator/paths.js +0 -42
- package/dist/coordinator/util.js +0 -126
- package/dist/coordinator.js +0 -990
- package/dist/daemon.js +0 -44
- package/dist/dispatch.js +0 -250
- package/dist/drive.js +0 -864
- package/dist/error-feedback.js +0 -419
- package/dist/evidence-grounding.js +0 -184
- package/dist/execution-backend/agent.js +0 -354
- package/dist/execution-backend/probes.js +0 -112
- package/dist/execution-backend/util.js +0 -47
- package/dist/execution-backend.js +0 -961
- package/dist/gates.js +0 -48
- package/dist/harness.js +0 -61
- package/dist/ledger.js +0 -313
- package/dist/loop-expansion.js +0 -60
- package/dist/mcp/tool-call.js +0 -470
- package/dist/mcp/tool-definitions.js +0 -1066
- package/dist/mcp-surface.js +0 -30
- package/dist/multi-agent/graph.js +0 -84
- package/dist/multi-agent/helpers.js +0 -141
- package/dist/multi-agent/ids.js +0 -20
- package/dist/multi-agent/paths.js +0 -22
- package/dist/multi-agent-eval/normalize.js +0 -51
- package/dist/multi-agent-eval.js +0 -678
- package/dist/multi-agent-host.js +0 -777
- package/dist/multi-agent.js +0 -984
- package/dist/node-projection.js +0 -59
- package/dist/node-snapshot.js +0 -260
- package/dist/operator-ux.js +0 -631
- package/dist/orchestrator/app-operations.js +0 -211
- package/dist/orchestrator/audit-operations.js +0 -182
- package/dist/orchestrator/candidate-operations.js +0 -117
- package/dist/orchestrator/cli-options.js +0 -294
- package/dist/orchestrator/collaboration-operations.js +0 -86
- package/dist/orchestrator/feedback-operations.js +0 -81
- package/dist/orchestrator/host-operations.js +0 -78
- package/dist/orchestrator/lifecycle-operations.js +0 -650
- package/dist/orchestrator/migration-operations.js +0 -44
- package/dist/orchestrator/multi-agent-operations.js +0 -362
- package/dist/orchestrator/topology-operations.js +0 -84
- package/dist/orchestrator.js +0 -925
- package/dist/pipeline-runner.js +0 -285
- package/dist/reclamation/hash.js +0 -72
- package/dist/reclamation.js +0 -812
- package/dist/reporter.js +0 -67
- package/dist/run-export.js +0 -815
- package/dist/run-registry/derive.js +0 -175
- package/dist/run-registry/format.js +0 -124
- package/dist/run-registry/gc.js +0 -251
- package/dist/run-registry/policy.js +0 -16
- package/dist/run-registry/queue.js +0 -115
- package/dist/run-registry.js +0 -850
- package/dist/run-state-schema.js +0 -68
- package/dist/scheduling.js +0 -184
- package/dist/state-explosion.js +0 -1014
- package/dist/state.js +0 -367
- package/dist/telemetry-ledger.js +0 -196
- package/dist/topology.js +0 -565
- package/dist/triggers.js +0 -184
- package/dist/trust-audit.js +0 -644
- package/dist/types/blackboard.js +0 -2
- package/dist/types/candidate.js +0 -2
- package/dist/types/collaboration.js +0 -2
- package/dist/types/core.js +0 -2
- package/dist/types/drive.js +0 -10
- package/dist/types/error-feedback.js +0 -2
- package/dist/types/evidence-reasoning.js +0 -2
- package/dist/types/execution-backend.js +0 -2
- package/dist/types/multi-agent.js +0 -2
- package/dist/types/observability.js +0 -2
- package/dist/types/pipeline.js +0 -2
- package/dist/types/reclamation.js +0 -8
- package/dist/types/report-bundle.js +0 -6
- package/dist/types/result.js +0 -2
- package/dist/types/run-registry.js +0 -2
- package/dist/types/run.js +0 -2
- package/dist/types/sandbox.js +0 -2
- package/dist/types/schedule.js +0 -2
- package/dist/types/state-node.js +0 -2
- package/dist/types/topology.js +0 -2
- package/dist/types/trust.js +0 -2
- package/dist/types/workbench.js +0 -2
- package/dist/types/worker.js +0 -2
- package/dist/types/workflow-app.js +0 -2
- package/dist/types.js +0 -44
- package/dist/util/fingerprint.js +0 -19
- package/dist/util/fingerprint.test.js +0 -27
- package/dist/verifier.js +0 -78
- package/dist/version.js +0 -8
- package/dist/workbench-host.js +0 -192
- package/dist/workbench.js +0 -192
- package/dist/worker-accept/acceptance.js +0 -114
- package/dist/worker-accept/blackboard-fanout.js +0 -80
- package/dist/worker-accept/blackboard-linkage.js +0 -19
- package/dist/worker-accept/context.js +0 -2
- package/dist/worker-accept/telemetry-ledger.js +0 -126
- package/dist/worker-accept/validation.js +0 -77
- package/dist/worker-accept/verifier-completion.js +0 -73
- package/dist/worker-isolation/helpers.js +0 -51
- package/dist/worker-isolation/paths.js +0 -46
- package/dist/worker-isolation.js +0 -656
- package/dist/workflow-api.js +0 -131
- /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
|
-
//
|
|
3
|
-
// subsystem over the existing run-state migration pipeline, extended to the
|
|
4
|
-
// workflow-app schema.
|
|
2
|
+
// core/state/contract-migration.ts — declared migration registry + prover.
|
|
5
3
|
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
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
|
-
//
|
|
22
|
-
|
|
23
|
-
|
|
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
|
|
32
|
-
const version_1 = require("
|
|
33
|
-
const
|
|
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
|
-
|
|
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
|
|
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 {
|
|
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 {
|
|
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,
|
|
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 {
|
|
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
|
|
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,
|
|
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
|
-
/**
|
|
163
|
-
*
|
|
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,
|
|
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,
|
|
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
|
-
}
|