cool-workflow 0.1.97 → 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 (309) 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} +12 -5
  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 +4 -0
  139. package/docs/cli-mcp-parity.7.md +284 -211
  140. package/docs/contract-migration-tooling.7.md +4 -0
  141. package/docs/control-plane-scheduling.7.md +4 -0
  142. package/docs/cross-agent-ledger.7.md +217 -0
  143. package/docs/designs/handoff-ledger.md +145 -0
  144. package/docs/durable-state-and-locking.7.md +4 -0
  145. package/docs/evidence-adoption-reasoning-chain.7.md +4 -0
  146. package/docs/execution-backends.7.md +4 -0
  147. package/docs/handoff-setup.md +120 -0
  148. package/docs/multi-agent-cli-mcp-surface.7.md +4 -0
  149. package/docs/multi-agent-eval-replay-harness.7.md +4 -0
  150. package/docs/multi-agent-operator-ux.7.md +4 -0
  151. package/docs/node-snapshot-diff-replay.7.md +4 -0
  152. package/docs/observability-cost-accounting.7.md +4 -0
  153. package/docs/project-index.md +143 -71
  154. package/docs/real-execution-backends.7.md +4 -0
  155. package/docs/release-and-migration.7.md +4 -0
  156. package/docs/release-tooling.7.md +4 -0
  157. package/docs/run-registry-control-plane.7.md +4 -0
  158. package/docs/run-retention-reclamation.7.md +25 -0
  159. package/docs/state-explosion-management.7.md +4 -0
  160. package/docs/team-collaboration.7.md +4 -0
  161. package/docs/web-desktop-workbench.7.md +4 -0
  162. package/manifest/plugin.manifest.json +1 -1
  163. package/manifest/source-context-profiles.json +9 -13
  164. package/package.json +1 -1
  165. package/scripts/agents/codex-agent.js +34 -4
  166. package/scripts/agents/cw-attest-wrap.js +2 -2
  167. package/scripts/bump-version.js +4 -3
  168. package/scripts/canonical-apps.js +4 -4
  169. package/scripts/children/batch-delegate-child.js +30 -10
  170. package/scripts/dogfood-architecture-review.js +2 -3
  171. package/scripts/dogfood-release.js +3 -3
  172. package/scripts/gen-parity-doc.js +15 -2
  173. package/scripts/golden-path.js +4 -4
  174. package/scripts/onramp-check.js +1 -1
  175. package/scripts/parity-check.js +38 -21
  176. package/scripts/release-flow.js +9 -3
  177. package/scripts/sync-project-index.js +51 -27
  178. package/scripts/validate-run-state-schema.js +2 -2
  179. package/scripts/version-sync-check.js +30 -30
  180. package/dist/candidate-scoring.js +0 -729
  181. package/dist/capability-core.js +0 -1186
  182. package/dist/capability-registry.js +0 -879
  183. package/dist/cli/command-surface.js +0 -490
  184. package/dist/cli/format.js +0 -56
  185. package/dist/cli/handlers/audit.js +0 -82
  186. package/dist/cli/handlers/blackboard.js +0 -81
  187. package/dist/cli/handlers/candidate.js +0 -40
  188. package/dist/cli/handlers/clones.js +0 -34
  189. package/dist/cli/handlers/collaboration.js +0 -61
  190. package/dist/cli/handlers/eval.js +0 -40
  191. package/dist/cli/handlers/maintenance.js +0 -107
  192. package/dist/cli/handlers/multi-agent.js +0 -165
  193. package/dist/cli/handlers/node.js +0 -41
  194. package/dist/cli/handlers/operational.js +0 -155
  195. package/dist/cli/handlers/operator.js +0 -146
  196. package/dist/cli/handlers/registry.js +0 -68
  197. package/dist/cli/handlers/run.js +0 -153
  198. package/dist/cli/handlers/scheduling.js +0 -132
  199. package/dist/cli/handlers/workbench.js +0 -41
  200. package/dist/cli/handlers/worker.js +0 -45
  201. package/dist/cli/run-summary.js +0 -45
  202. package/dist/clones.js +0 -162
  203. package/dist/collaboration.js +0 -726
  204. package/dist/commit.js +0 -592
  205. package/dist/compare.js +0 -18
  206. package/dist/coordinator/classify.js +0 -45
  207. package/dist/coordinator/paths.js +0 -42
  208. package/dist/coordinator/util.js +0 -126
  209. package/dist/coordinator.js +0 -990
  210. package/dist/daemon.js +0 -44
  211. package/dist/dispatch.js +0 -250
  212. package/dist/drive.js +0 -827
  213. package/dist/error-feedback.js +0 -419
  214. package/dist/evidence-grounding.js +0 -184
  215. package/dist/execution-backend/agent.js +0 -294
  216. package/dist/execution-backend/probes.js +0 -112
  217. package/dist/execution-backend/util.js +0 -47
  218. package/dist/execution-backend.js +0 -961
  219. package/dist/gates.js +0 -48
  220. package/dist/harness.js +0 -61
  221. package/dist/loop-expansion.js +0 -60
  222. package/dist/mcp/tool-call.js +0 -434
  223. package/dist/mcp/tool-definitions.js +0 -1040
  224. package/dist/mcp-surface.js +0 -30
  225. package/dist/multi-agent/graph.js +0 -84
  226. package/dist/multi-agent/helpers.js +0 -141
  227. package/dist/multi-agent/ids.js +0 -20
  228. package/dist/multi-agent/paths.js +0 -22
  229. package/dist/multi-agent-eval/normalize.js +0 -51
  230. package/dist/multi-agent-eval.js +0 -678
  231. package/dist/multi-agent-host.js +0 -777
  232. package/dist/multi-agent.js +0 -984
  233. package/dist/node-projection.js +0 -59
  234. package/dist/node-snapshot.js +0 -260
  235. package/dist/operator-ux.js +0 -631
  236. package/dist/orchestrator/app-operations.js +0 -211
  237. package/dist/orchestrator/audit-operations.js +0 -182
  238. package/dist/orchestrator/candidate-operations.js +0 -117
  239. package/dist/orchestrator/cli-options.js +0 -294
  240. package/dist/orchestrator/collaboration-operations.js +0 -86
  241. package/dist/orchestrator/feedback-operations.js +0 -81
  242. package/dist/orchestrator/host-operations.js +0 -78
  243. package/dist/orchestrator/lifecycle-operations.js +0 -626
  244. package/dist/orchestrator/migration-operations.js +0 -44
  245. package/dist/orchestrator/multi-agent-operations.js +0 -362
  246. package/dist/orchestrator/topology-operations.js +0 -84
  247. package/dist/orchestrator.js +0 -917
  248. package/dist/pipeline-runner.js +0 -285
  249. package/dist/reclamation/hash.js +0 -72
  250. package/dist/reclamation.js +0 -812
  251. package/dist/reporter.js +0 -67
  252. package/dist/run-export.js +0 -784
  253. package/dist/run-registry/derive.js +0 -175
  254. package/dist/run-registry/format.js +0 -124
  255. package/dist/run-registry/gc.js +0 -251
  256. package/dist/run-registry/policy.js +0 -16
  257. package/dist/run-registry/queue.js +0 -115
  258. package/dist/run-registry.js +0 -850
  259. package/dist/run-state-schema.js +0 -68
  260. package/dist/scheduling.js +0 -184
  261. package/dist/state-explosion.js +0 -1014
  262. package/dist/state.js +0 -367
  263. package/dist/telemetry-ledger.js +0 -196
  264. package/dist/topology.js +0 -565
  265. package/dist/triggers.js +0 -184
  266. package/dist/trust-audit.js +0 -644
  267. package/dist/types/blackboard.js +0 -2
  268. package/dist/types/candidate.js +0 -2
  269. package/dist/types/collaboration.js +0 -2
  270. package/dist/types/core.js +0 -2
  271. package/dist/types/drive.js +0 -10
  272. package/dist/types/error-feedback.js +0 -2
  273. package/dist/types/evidence-reasoning.js +0 -2
  274. package/dist/types/execution-backend.js +0 -2
  275. package/dist/types/multi-agent.js +0 -2
  276. package/dist/types/observability.js +0 -2
  277. package/dist/types/pipeline.js +0 -2
  278. package/dist/types/reclamation.js +0 -8
  279. package/dist/types/report-bundle.js +0 -6
  280. package/dist/types/result.js +0 -2
  281. package/dist/types/run-registry.js +0 -2
  282. package/dist/types/run.js +0 -2
  283. package/dist/types/sandbox.js +0 -2
  284. package/dist/types/schedule.js +0 -2
  285. package/dist/types/state-node.js +0 -2
  286. package/dist/types/topology.js +0 -2
  287. package/dist/types/trust.js +0 -2
  288. package/dist/types/workbench.js +0 -2
  289. package/dist/types/worker.js +0 -2
  290. package/dist/types/workflow-app.js +0 -2
  291. package/dist/types.js +0 -44
  292. package/dist/util/fingerprint.js +0 -19
  293. package/dist/util/fingerprint.test.js +0 -27
  294. package/dist/verifier.js +0 -78
  295. package/dist/version.js +0 -8
  296. package/dist/workbench-host.js +0 -182
  297. package/dist/workbench.js +0 -192
  298. package/dist/worker-accept/acceptance.js +0 -114
  299. package/dist/worker-accept/blackboard-fanout.js +0 -80
  300. package/dist/worker-accept/blackboard-linkage.js +0 -19
  301. package/dist/worker-accept/context.js +0 -2
  302. package/dist/worker-accept/telemetry-ledger.js +0 -126
  303. package/dist/worker-accept/validation.js +0 -77
  304. package/dist/worker-accept/verifier-completion.js +0 -73
  305. package/dist/worker-isolation/helpers.js +0 -51
  306. package/dist/worker-isolation/paths.js +0 -46
  307. package/dist/worker-isolation.js +0 -656
  308. package/dist/workflow-api.js +0 -131
  309. /package/dist/{types → core/types}/boundary.js +0 -0
@@ -1,59 +0,0 @@
1
- "use strict";
2
- // Canonical StateNode projection (F9 de-triplication) — the SINGLE source of
3
- // truth for which StateNode fields make up the derived, fingerprinted body.
4
- //
5
- // Previously this 13-field set was hand-copied in three places: node-snapshot.ts's
6
- // snapshotBody, reclamation.ts's snapshotProjectionDigest, and reclamation.ts's
7
- // rawNodeBody/nodeBodyDigest (whose comment literally said "Mirror
8
- // node-snapshot.ts"). Any field added in one place but not the others would drift
9
- // the projection — and because reclamation hashes are tombstone-chained, a drift
10
- // would silently break the chain. This module collapses the list to ONE export so
11
- // the field set can only change in one place.
12
- //
13
- // BYTE-IDENTITY [load-bearing]: the projection / digest OUTPUT here is identical to
14
- // the prior in-line implementations. `normalizeValue` sorts object keys, so the
15
- // literal field ORDER never affected the bytes — only the field SET ever mattered.
16
- // `replayStableStringify(value) === JSON.stringify(normalizeValue(value))` and
17
- // `normalizeValue` is idempotent, so the projected-body digest and the raw-body
18
- // digest funnel through the same canonical bytes (node-snapshot-diff-replay +
19
- // reclamation smokes verify this).
20
- //
21
- // Pure: no I/O, no wall-clock, no random — safe in core/state/replay logic.
22
- Object.defineProperty(exports, "__esModule", { value: true });
23
- exports.rawNodeProjection = rawNodeProjection;
24
- exports.projectNodeBody = projectNodeBody;
25
- exports.nodeProjectionDigestInput = nodeProjectionDigestInput;
26
- const multi_agent_eval_1 = require("./multi-agent-eval");
27
- /** The raw (un-normalized) projection input: the canonical field set, copied off
28
- * the StateNode with no scrubbing. `normalizeValue`/`replayStableStringify` apply
29
- * the timestamp/path scrubbing downstream. This is the ONE place the field list
30
- * lives — add or drop a projected field here and every consumer follows. */
31
- function rawNodeProjection(node) {
32
- return {
33
- id: node.id,
34
- kind: node.kind,
35
- status: node.status,
36
- loopStage: node.loopStage,
37
- inputs: node.inputs,
38
- outputs: node.outputs,
39
- artifacts: node.artifacts,
40
- evidence: node.evidence,
41
- errors: node.errors,
42
- parents: node.parents,
43
- children: node.children,
44
- contractId: node.contractId,
45
- metadata: node.metadata
46
- };
47
- }
48
- /** The normalized, derived projected body of one StateNode — timestamps/paths
49
- * stripped via the eval normalizer, so it is byte-stable across captures of the
50
- * same logical state. This is exactly node-snapshot.ts's historical snapshotBody. */
51
- function projectNodeBody(node) {
52
- return (0, multi_agent_eval_1.normalizeValue)(rawNodeProjection(node));
53
- }
54
- /** Stable digest input for the projected body: the canonical bytes that the
55
- * snapshot/reconstruction digests bind. `replayStableStringify` re-normalizes, so
56
- * feeding the raw projection or the already-normalized body yields identical bytes. */
57
- function nodeProjectionDigestInput(node) {
58
- return (0, multi_agent_eval_1.replayStableStringify)(rawNodeProjection(node));
59
- }
@@ -1,260 +0,0 @@
1
- "use strict";
2
- // Node Snapshot / Diff / Replay (v0.1.35) — per-node granularity over the eval
3
- // harness. Snapshot one StateNode into a DERIVED, sha256-fingerprinted projection,
4
- // diff two snapshots structurally, and deterministically replay one node in
5
- // isolation.
6
- //
7
- // BSD discipline:
8
- // - MECHANISM, not policy: the caller names the node id; nothing decides which
9
- // node "matters".
10
- // - FAIL CLOSED ON SOURCE DRIFT [load-bearing]: a snapshot carries a
11
- // sourceFingerprint over the RAW node (id:status:updatedAt + artifact/evidence
12
- // ids+paths). loadNodeSnapshot recomputes it from the current source; on
13
- // divergence (`stale`) or a missing node/artifact (`absent`) diff/replay REFUSE
14
- // with a structured error — never a silent stale replay.
15
- // - REUSE, don't fork: operates on the real StateNode (getRunNode) and reuses the
16
- // eval harness's normalizeValue/replayStableStringify and state-explosion's
17
- // fingerprintStrings. No parallel node type, normalizer, or replay engine.
18
- // - DETERMINISTIC: `now` is injected; the deterministic payload (normalized body
19
- // + outputFingerprint) carries zero wall-clock, so two replays are byte-identical.
20
- //
21
- // Additive: StateNode and STATE_NODE_SCHEMA_VERSION are unchanged. See
22
- // docs/node-snapshot-diff-replay.7.md.
23
- var __importDefault = (this && this.__importDefault) || function (mod) {
24
- return (mod && mod.__esModule) ? mod : { "default": mod };
25
- };
26
- Object.defineProperty(exports, "__esModule", { value: true });
27
- exports.NodeSnapshotError = exports.NODE_SNAPSHOT_SCHEMA_VERSION = void 0;
28
- exports.readNodeSnapshot = readNodeSnapshot;
29
- exports.readNodeReplay = readNodeReplay;
30
- exports.snapshotNode = snapshotNode;
31
- exports.loadNodeSnapshot = loadNodeSnapshot;
32
- exports.diffNodeSnapshots = diffNodeSnapshots;
33
- exports.replayNodeSnapshot = replayNodeSnapshot;
34
- exports.verifyNodeReplay = verifyNodeReplay;
35
- const node_fs_1 = __importDefault(require("node:fs"));
36
- const node_path_1 = __importDefault(require("node:path"));
37
- const pipeline_runner_1 = require("./pipeline-runner");
38
- const state_1 = require("./state");
39
- const multi_agent_eval_1 = require("./multi-agent-eval");
40
- const node_projection_1 = require("./node-projection");
41
- const fingerprint_1 = require("./util/fingerprint");
42
- const validation_1 = require("./validation");
43
- exports.NODE_SNAPSHOT_SCHEMA_VERSION = 1;
44
- /** Structured fail-closed error (mirrors the PipelineContractError shape). */
45
- class NodeSnapshotError extends Error {
46
- code;
47
- freshness;
48
- details;
49
- constructor(code, message, options = {}) {
50
- super(message);
51
- this.name = "NodeSnapshotError";
52
- this.code = code;
53
- this.freshness = options.freshness;
54
- this.details = options.details;
55
- }
56
- }
57
- exports.NodeSnapshotError = NodeSnapshotError;
58
- const SNAPSHOT_SECTIONS = [
59
- "status",
60
- "inputs",
61
- "outputs",
62
- "artifacts",
63
- "evidence",
64
- "errors",
65
- "links",
66
- "metadata"
67
- ];
68
- /** The normalized projection of a node — timestamps/paths stripped by the eval
69
- * normalizer, so it is byte-stable across captures of the same logical state. The
70
- * canonical field set lives in node-projection.ts (shared with reclamation.ts so
71
- * the projection can never drift across the two). */
72
- function snapshotBody(node) {
73
- return (0, node_projection_1.projectNodeBody)(node);
74
- }
75
- /** RAW fingerprint (NOT normalized): any transition (updatedAt/status) or
76
- * artifact/evidence change flips it, which is how drift is detected. */
77
- function sourceFingerprint(node) {
78
- return (0, fingerprint_1.fingerprintStrings)([
79
- `node:${node.id}:${node.status}:${node.updatedAt}`,
80
- ...node.artifacts.map((artifact) => `artifact:${artifact.id}:${artifact.path}`),
81
- ...node.evidence.map((evidence) => `evidence:${evidence.id}:${evidence.path || ""}`)
82
- ]);
83
- }
84
- function tryGetNode(run, nodeId) {
85
- try {
86
- return (0, pipeline_runner_1.getRunNode)(run, nodeId);
87
- }
88
- catch {
89
- return undefined;
90
- }
91
- }
92
- function snapshotsRoot(run) {
93
- const base = run.paths.stateNodesDir || node_path_1.default.join(run.paths.runDir, "nodes");
94
- return node_path_1.default.join(base, "snapshots");
95
- }
96
- function snapshotDir(run, nodeId) {
97
- return node_path_1.default.join(snapshotsRoot(run), (0, state_1.safeFileName)(nodeId));
98
- }
99
- /** Load a persisted snapshot by id (scans the per-node snapshot dirs). */
100
- function readNodeSnapshot(run, snapshotId) {
101
- const root = snapshotsRoot(run);
102
- if (node_fs_1.default.existsSync(root)) {
103
- for (const nodeDir of node_fs_1.default.readdirSync(root)) {
104
- const file = node_path_1.default.join(root, nodeDir, `${snapshotId}.json`);
105
- if (node_fs_1.default.existsSync(file))
106
- return (0, validation_1.validateNodeSnapshot)(JSON.parse(node_fs_1.default.readFileSync(file, "utf8")));
107
- }
108
- }
109
- throw new NodeSnapshotError("snapshot-not-found", `Node snapshot ${snapshotId} not found in run ${run.id}`, { freshness: "absent" });
110
- }
111
- /** Load a persisted replay run by id. */
112
- function readNodeReplay(run, replayId) {
113
- const root = snapshotsRoot(run);
114
- if (node_fs_1.default.existsSync(root)) {
115
- for (const nodeDir of node_fs_1.default.readdirSync(root)) {
116
- const file = node_path_1.default.join(root, nodeDir, "replays", `${replayId}.json`);
117
- if (node_fs_1.default.existsSync(file))
118
- return (0, validation_1.validateNodeReplayRun)(JSON.parse(node_fs_1.default.readFileSync(file, "utf8")));
119
- }
120
- }
121
- throw new NodeSnapshotError("replay-not-found", `Node replay ${replayId} not found in run ${run.id}`, { freshness: "absent" });
122
- }
123
- /** Snapshot one StateNode by id. Throws (fail closed) if the node is absent. */
124
- function snapshotNode(run, nodeId, options = {}) {
125
- const node = tryGetNode(run, nodeId);
126
- if (!node) {
127
- throw new NodeSnapshotError("node-absent", `Cannot snapshot: node ${nodeId} not found in run ${run.id}`, { freshness: "absent" });
128
- }
129
- const fingerprint = sourceFingerprint(node);
130
- const snapshot = {
131
- schemaVersion: 1,
132
- snapshotId: `snap-${(0, state_1.safeFileName)(nodeId)}-${fingerprint.replace("sha256:", "").slice(0, 12)}`,
133
- runId: run.id,
134
- nodeId,
135
- capturedAt: options.now || new Date().toISOString(),
136
- sourceFingerprint: fingerprint,
137
- body: snapshotBody(node)
138
- };
139
- if (options.persist !== false) {
140
- (0, state_1.writeJson)(node_path_1.default.join(snapshotDir(run, nodeId), `${snapshot.snapshotId}.json`), snapshot);
141
- }
142
- return snapshot;
143
- }
144
- /** Recompute freshness from current source. valid | stale | absent. */
145
- function loadNodeSnapshot(run, snapshot) {
146
- const node = tryGetNode(run, snapshot.nodeId);
147
- if (!node) {
148
- return { snapshot, freshness: "absent", reason: `source node ${snapshot.nodeId} is gone from run ${run.id}` };
149
- }
150
- const missingArtifact = node.artifacts.find((artifact) => artifact.path && !node_fs_1.default.existsSync(artifact.path));
151
- if (missingArtifact) {
152
- return { snapshot, freshness: "absent", reason: `referenced artifact path is unreadable: ${missingArtifact.id}` };
153
- }
154
- if (sourceFingerprint(node) !== snapshot.sourceFingerprint) {
155
- return { snapshot, freshness: "stale", reason: `source node ${snapshot.nodeId} changed since capture` };
156
- }
157
- return { snapshot, freshness: "valid" };
158
- }
159
- function sectionValue(body, section) {
160
- if (section === "links")
161
- return { parents: body.parents, children: body.children };
162
- return body[section];
163
- }
164
- /** Stable, structural diff of two snapshots (same node id or two explicit ids). */
165
- function diffNodeSnapshots(baseline, candidate) {
166
- const sections = SNAPSHOT_SECTIONS.map((section) => {
167
- const baselineValue = sectionValue(baseline.body, section);
168
- const candidateValue = sectionValue(candidate.body, section);
169
- const sameBytes = (0, multi_agent_eval_1.replayStableStringify)(baselineValue) === (0, multi_agent_eval_1.replayStableStringify)(candidateValue);
170
- let change;
171
- if (sameBytes)
172
- change = "same";
173
- else if (baselineValue === undefined)
174
- change = "added";
175
- else if (candidateValue === undefined)
176
- change = "removed";
177
- else
178
- change = "changed";
179
- const entry = { section, change };
180
- if (change !== "same") {
181
- entry.baseline = baselineValue;
182
- entry.candidate = candidateValue;
183
- }
184
- return entry;
185
- });
186
- return {
187
- schemaVersion: 1,
188
- runId: baseline.runId,
189
- baselineSnapshotId: baseline.snapshotId,
190
- candidateSnapshotId: candidate.snapshotId,
191
- baselineNodeId: baseline.nodeId,
192
- candidateNodeId: candidate.nodeId,
193
- changed: sections.some((entry) => entry.change !== "same"),
194
- sections
195
- };
196
- }
197
- /** Deterministically replay one node from its snapshot, fail-closed on drift.
198
- * `now` is injected; the deterministic payload (body + outputFingerprint) has
199
- * zero wall-clock, so two replays are byte-identical. */
200
- function replayNodeSnapshot(run, snapshot, options = {}) {
201
- const { freshness, reason } = loadNodeSnapshot(run, snapshot);
202
- if (freshness !== "valid") {
203
- throw new NodeSnapshotError(freshness === "stale" ? "snapshot-stale" : "snapshot-absent", reason || `cannot replay a ${freshness} snapshot of node ${snapshot.nodeId}`, { freshness, details: { runId: run.id, nodeId: snapshot.nodeId } });
204
- }
205
- const body = (0, multi_agent_eval_1.normalizeValue)(snapshot.body);
206
- const outputFingerprint = (0, fingerprint_1.fingerprintStrings)([(0, multi_agent_eval_1.replayStableStringify)(body)]);
207
- const replay = {
208
- schemaVersion: 1,
209
- replayId: `replay-${snapshot.snapshotId}-${outputFingerprint.replace("sha256:", "").slice(0, 8)}`,
210
- runId: run.id,
211
- nodeId: snapshot.nodeId,
212
- snapshotId: snapshot.snapshotId,
213
- replayedAt: options.now || new Date().toISOString(),
214
- freshness: "valid",
215
- contractValidated: Boolean(snapshot.body.contractId),
216
- outputFingerprint,
217
- body
218
- };
219
- if (options.persist !== false) {
220
- (0, state_1.writeJson)(node_path_1.default.join(snapshotDir(run, snapshot.nodeId), "replays", `${replay.replayId}.json`), replay);
221
- }
222
- return replay;
223
- }
224
- /** Compare a replay to a fresh snapshot of the source node; pass = byte-identical
225
- * normalized body. Findings reuse the eval harness severity/category shape. */
226
- function verifyNodeReplay(run, replay, options = {}) {
227
- const fresh = tryGetNode(run, replay.nodeId);
228
- if (!fresh) {
229
- return {
230
- schemaVersion: 1,
231
- runId: run.id,
232
- nodeId: replay.nodeId,
233
- replayId: replay.replayId,
234
- pass: false,
235
- freshness: "absent",
236
- findings: [{ id: "source-absent", severity: "error", category: "source", reason: `source node ${replay.nodeId} is gone` }]
237
- };
238
- }
239
- const freshSnapshot = snapshotNode(run, replay.nodeId, { now: options.now, persist: false });
240
- const diff = diffNodeSnapshots(freshSnapshot, { ...freshSnapshot, body: replay.body, snapshotId: replay.snapshotId });
241
- const findings = diff.sections
242
- .filter((section) => section.change !== "same")
243
- .map((section) => ({
244
- id: `drift:${section.section}`,
245
- severity: "error",
246
- category: section.section,
247
- reason: `replay diverged from source in ${section.section}`,
248
- baselineRef: replay.snapshotId,
249
- replayRef: replay.replayId
250
- }));
251
- return {
252
- schemaVersion: 1,
253
- runId: run.id,
254
- nodeId: replay.nodeId,
255
- replayId: replay.replayId,
256
- pass: findings.length === 0,
257
- freshness: "valid",
258
- findings
259
- };
260
- }