cool-workflow 0.1.98 → 0.2.1

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 (315) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/README.md +18 -7
  4. package/apps/architecture-review/app.json +2 -2
  5. package/apps/architecture-review/workflow.js +12 -12
  6. package/apps/architecture-review-fast/app.json +1 -1
  7. package/apps/end-to-end-golden-path/app.json +1 -1
  8. package/apps/pr-review-fix-ci/app.json +1 -1
  9. package/apps/release-cut/app.json +1 -1
  10. package/apps/research-synthesis/app.json +1 -1
  11. package/dist/cli/dispatch.js +236 -0
  12. package/dist/cli/entry.js +120 -0
  13. package/dist/cli/io.js +21 -4
  14. package/dist/cli/parseargv.js +157 -0
  15. package/dist/cli.js +6 -33
  16. package/dist/core/capability-table.js +3518 -0
  17. package/dist/core/format/help.js +314 -0
  18. package/dist/{state-explosion/format.js → core/format/state-explosion-text.js} +10 -1
  19. package/dist/core/hash.js +137 -0
  20. package/dist/core/multi-agent/candidate-scoring.js +219 -0
  21. package/dist/core/multi-agent/collaboration.js +481 -0
  22. package/dist/core/multi-agent/coordinator.js +515 -0
  23. package/dist/core/multi-agent/eval-replay.js +306 -0
  24. package/dist/core/multi-agent/runtime.js +929 -0
  25. package/dist/core/multi-agent/topology.js +298 -0
  26. package/dist/core/multi-agent/trust-policy.js +197 -0
  27. package/dist/core/pipeline/commit-gate.js +320 -0
  28. package/dist/{pipeline-contract.js → core/pipeline/contract.js} +24 -37
  29. package/dist/core/pipeline/dispatch.js +103 -0
  30. package/dist/core/pipeline/drive-decide.js +227 -0
  31. package/dist/core/pipeline/error-feedback.js +161 -0
  32. package/dist/core/pipeline/loop-expansion.js +124 -0
  33. package/dist/{result-normalize.js → core/pipeline/result-normalize.js} +14 -37
  34. package/dist/core/pipeline/runner.js +230 -0
  35. package/dist/{contract-migration.js → core/state/contract-migration.js} +68 -92
  36. package/dist/{state-migrations.js → core/state/migrations.js} +103 -96
  37. package/dist/core/state/node-projection.js +95 -0
  38. package/dist/core/state/node-snapshot.js +230 -0
  39. package/dist/core/state/run-paths.js +93 -0
  40. package/dist/{schema-validate.js → core/state/schema-validate.js} +35 -28
  41. package/dist/core/state/schema.js +50 -0
  42. package/dist/core/state/state-explosion/digest.js +243 -0
  43. package/dist/core/state/state-explosion/graph.js +527 -0
  44. package/dist/{state-explosion → core/state/state-explosion}/helpers.js +34 -3
  45. package/dist/core/state/state-explosion/report.js +187 -0
  46. package/dist/{state-explosion → core/state/state-explosion}/size.js +25 -7
  47. package/dist/{state-node.js → core/state/state-node.js} +90 -113
  48. package/dist/core/state/types.js +19 -0
  49. package/dist/{validation.js → core/state/validation.js} +64 -131
  50. package/dist/core/trust/evidence-grounding.js +134 -0
  51. package/dist/core/trust/ledger.js +199 -0
  52. package/dist/{telemetry-attestation.js → core/trust/telemetry-attestation.js} +94 -68
  53. package/dist/core/trust/telemetry-ledger.js +127 -0
  54. package/dist/core/types.js +20 -0
  55. package/dist/core/version.js +16 -0
  56. package/dist/{workflow-app-framework.js → core/workflow-apps/app-schema.js} +337 -426
  57. package/dist/mcp/dispatch.js +104 -0
  58. package/dist/mcp/server.js +144 -0
  59. package/dist/mcp-server.js +6 -84
  60. package/dist/{agent-config.js → shell/agent-config.js} +118 -71
  61. package/dist/shell/app-run-cli.js +88 -0
  62. package/dist/shell/audit-cli.js +259 -0
  63. package/dist/shell/audit-provenance.js +83 -0
  64. package/dist/shell/candidate-scoring-io.js +459 -0
  65. package/dist/shell/collaboration-io.js +264 -0
  66. package/dist/shell/commit-summary.js +104 -0
  67. package/dist/shell/commit.js +290 -0
  68. package/dist/shell/coordinator-io.js +476 -0
  69. package/dist/shell/demo-cli.js +19 -0
  70. package/dist/shell/dispatch.js +162 -0
  71. package/dist/shell/doctor.js +292 -0
  72. package/dist/shell/drive.js +885 -0
  73. package/dist/shell/error-feedback-io.js +305 -0
  74. package/dist/shell/eval-io.js +473 -0
  75. package/dist/{multi-agent-eval/format.js → shell/eval-text.js} +78 -49
  76. package/dist/{evidence-reasoning.js → shell/evidence-reasoning.js} +124 -255
  77. package/dist/shell/exec-backend-cli.js +88 -0
  78. package/dist/shell/execution-backend/agent.js +507 -0
  79. package/dist/shell/execution-backend/ci.js +15 -0
  80. package/dist/shell/execution-backend/container.js +69 -0
  81. package/dist/shell/execution-backend/envelopes.js +55 -0
  82. package/dist/shell/execution-backend/local.js +113 -0
  83. package/dist/shell/execution-backend/probes.js +175 -0
  84. package/dist/shell/execution-backend/registry.js +402 -0
  85. package/dist/shell/execution-backend/remote.js +128 -0
  86. package/dist/shell/execution-backend/types.js +11 -0
  87. package/dist/shell/feedback-cli.js +81 -0
  88. package/dist/shell/feedback-operations.js +48 -0
  89. package/dist/shell/fs-atomic.js +276 -0
  90. package/dist/shell/harness.js +98 -0
  91. package/dist/shell/ledger-cli.js +212 -0
  92. package/dist/shell/ledger-io.js +169 -0
  93. package/dist/shell/man-cli.js +89 -0
  94. package/dist/shell/metrics-cli.js +100 -0
  95. package/dist/shell/multi-agent-cli.js +1002 -0
  96. package/dist/shell/multi-agent-host.js +563 -0
  97. package/dist/shell/multi-agent-io.js +387 -0
  98. package/dist/{multi-agent-operator-ux.js → shell/multi-agent-operator-ux.js} +234 -191
  99. package/dist/shell/node-store.js +124 -0
  100. package/dist/{observability/format.js → shell/observability-format.js} +7 -1
  101. package/dist/{observability/intake.js → shell/observability-intake.js} +79 -56
  102. package/dist/{observability.js → shell/observability.js} +159 -332
  103. package/dist/{onramp.js → shell/onramp.js} +11 -0
  104. package/dist/{operator-ux/format.js → shell/operator-ux-text.js} +250 -239
  105. package/dist/shell/operator-ux.js +431 -0
  106. package/dist/shell/orchestrator.js +231 -0
  107. package/dist/shell/pipeline-cli.js +667 -0
  108. package/dist/shell/pipeline.js +217 -0
  109. package/dist/shell/reclamation-io.js +1366 -0
  110. package/dist/shell/registry-cli.js +344 -0
  111. package/dist/{remote-source.js → shell/remote-source.js} +2 -2
  112. package/dist/shell/report-cli.js +101 -0
  113. package/dist/shell/report-view-cli.js +117 -0
  114. package/dist/{orchestrator → shell}/report.js +289 -282
  115. package/dist/shell/reporter.js +62 -0
  116. package/dist/shell/run-export-cli.js +106 -0
  117. package/dist/shell/run-export.js +680 -0
  118. package/dist/shell/run-registry-io.js +1014 -0
  119. package/dist/shell/run-store.js +164 -0
  120. package/dist/{sandbox-profile.js → shell/sandbox-profile.js} +134 -95
  121. package/dist/{scheduler.js → shell/scheduler-io.js} +257 -48
  122. package/dist/shell/scheduling-io.js +321 -0
  123. package/dist/shell/state-cli.js +181 -0
  124. package/dist/shell/state-explosion-cli.js +197 -0
  125. package/dist/shell/telemetry-cli.js +85 -0
  126. package/dist/{telemetry-demo.js → shell/telemetry-demo.js} +149 -119
  127. package/dist/shell/telemetry-ledger-io.js +132 -0
  128. package/dist/{term.js → shell/term.js} +36 -46
  129. package/dist/shell/topology-io.js +361 -0
  130. package/dist/shell/trust-audit.js +472 -0
  131. package/dist/{multi-agent-trust.js → shell/trust-policy-io.js} +67 -205
  132. package/dist/shell/verifier.js +48 -0
  133. package/dist/shell/workbench-host.js +258 -0
  134. package/dist/shell/workbench-text.js +18 -0
  135. package/dist/shell/workbench.js +170 -0
  136. package/dist/shell/worker-cli.js +124 -0
  137. package/dist/shell/worker-isolation.js +852 -0
  138. package/dist/shell/workflow-app-loader.js +650 -0
  139. package/docs/agent-delegation-drive.7.md +4 -0
  140. package/docs/cli-mcp-parity.7.md +282 -219
  141. package/docs/contract-migration-tooling.7.md +4 -0
  142. package/docs/control-plane-scheduling.7.md +4 -0
  143. package/docs/durable-state-and-locking.7.md +4 -0
  144. package/docs/evidence-adoption-reasoning-chain.7.md +4 -0
  145. package/docs/execution-backends.7.md +4 -0
  146. package/docs/multi-agent-cli-mcp-surface.7.md +4 -0
  147. package/docs/multi-agent-eval-replay-harness.7.md +4 -0
  148. package/docs/multi-agent-operator-ux.7.md +4 -0
  149. package/docs/node-snapshot-diff-replay.7.md +4 -0
  150. package/docs/observability-cost-accounting.7.md +6 -1
  151. package/docs/project-index.md +137 -71
  152. package/docs/real-execution-backends.7.md +4 -0
  153. package/docs/release-and-migration.7.md +4 -0
  154. package/docs/release-tooling.7.md +4 -0
  155. package/docs/remote-source-review.7.md +4 -4
  156. package/docs/report-verifiable-bundle.7.md +1 -1
  157. package/docs/run-registry-control-plane.7.md +4 -0
  158. package/docs/run-retention-reclamation.7.md +25 -0
  159. package/docs/security-trust-hardening.7.md +3 -1
  160. package/docs/state-explosion-management.7.md +4 -0
  161. package/docs/team-collaboration.7.md +4 -0
  162. package/docs/web-desktop-workbench.7.md +15 -1
  163. package/manifest/plugin.manifest.json +1 -1
  164. package/manifest/source-context-profiles.json +9 -13
  165. package/package.json +1 -1
  166. package/scripts/agents/agent-adapter-core.js +22 -2
  167. package/scripts/agents/claude-p-agent.js +8 -3
  168. package/scripts/agents/cw-attest-wrap.js +2 -2
  169. package/scripts/agents/gemini-agent.js +5 -1
  170. package/scripts/agents/opencode-agent.js +5 -1
  171. package/scripts/bump-version.js +4 -3
  172. package/scripts/canonical-apps.js +4 -4
  173. package/scripts/dogfood-architecture-review.js +2 -3
  174. package/scripts/dogfood-release.js +3 -3
  175. package/scripts/gen-parity-doc.js +15 -2
  176. package/scripts/golden-path.js +4 -4
  177. package/scripts/onramp-check.js +1 -1
  178. package/scripts/parity-check.js +38 -21
  179. package/scripts/release-flow.js +2 -2
  180. package/scripts/sync-project-index.js +51 -27
  181. package/scripts/validate-run-state-schema.js +2 -2
  182. package/scripts/version-sync-check.js +30 -30
  183. package/dist/candidate-scoring.js +0 -729
  184. package/dist/capability-core.js +0 -1189
  185. package/dist/capability-registry.js +0 -885
  186. package/dist/cli/command-surface.js +0 -494
  187. package/dist/cli/format.js +0 -56
  188. package/dist/cli/handlers/audit.js +0 -82
  189. package/dist/cli/handlers/blackboard.js +0 -81
  190. package/dist/cli/handlers/candidate.js +0 -40
  191. package/dist/cli/handlers/clones.js +0 -34
  192. package/dist/cli/handlers/collaboration.js +0 -61
  193. package/dist/cli/handlers/eval.js +0 -40
  194. package/dist/cli/handlers/ledger.js +0 -169
  195. package/dist/cli/handlers/maintenance.js +0 -107
  196. package/dist/cli/handlers/multi-agent.js +0 -165
  197. package/dist/cli/handlers/node.js +0 -41
  198. package/dist/cli/handlers/operational.js +0 -155
  199. package/dist/cli/handlers/operator.js +0 -146
  200. package/dist/cli/handlers/registry.js +0 -68
  201. package/dist/cli/handlers/run.js +0 -153
  202. package/dist/cli/handlers/scheduling.js +0 -132
  203. package/dist/cli/handlers/workbench.js +0 -41
  204. package/dist/cli/handlers/worker.js +0 -45
  205. package/dist/cli/run-summary.js +0 -45
  206. package/dist/clones.js +0 -162
  207. package/dist/collaboration.js +0 -726
  208. package/dist/commit.js +0 -592
  209. package/dist/compare.js +0 -18
  210. package/dist/coordinator/classify.js +0 -45
  211. package/dist/coordinator/paths.js +0 -42
  212. package/dist/coordinator/util.js +0 -126
  213. package/dist/coordinator.js +0 -990
  214. package/dist/daemon.js +0 -44
  215. package/dist/dispatch.js +0 -250
  216. package/dist/doctor.js +0 -212
  217. package/dist/drive.js +0 -864
  218. package/dist/error-feedback.js +0 -419
  219. package/dist/evidence-grounding.js +0 -184
  220. package/dist/execution-backend/agent.js +0 -354
  221. package/dist/execution-backend/probes.js +0 -112
  222. package/dist/execution-backend/util.js +0 -47
  223. package/dist/execution-backend.js +0 -961
  224. package/dist/gates.js +0 -48
  225. package/dist/harness.js +0 -61
  226. package/dist/ledger.js +0 -313
  227. package/dist/loop-expansion.js +0 -60
  228. package/dist/mcp/tool-call.js +0 -470
  229. package/dist/mcp/tool-definitions.js +0 -1066
  230. package/dist/mcp-surface.js +0 -30
  231. package/dist/multi-agent/graph.js +0 -84
  232. package/dist/multi-agent/helpers.js +0 -141
  233. package/dist/multi-agent/ids.js +0 -20
  234. package/dist/multi-agent/paths.js +0 -22
  235. package/dist/multi-agent-eval/normalize.js +0 -51
  236. package/dist/multi-agent-eval.js +0 -678
  237. package/dist/multi-agent-host.js +0 -777
  238. package/dist/multi-agent.js +0 -984
  239. package/dist/node-projection.js +0 -59
  240. package/dist/node-snapshot.js +0 -260
  241. package/dist/operator-ux.js +0 -631
  242. package/dist/orchestrator/app-operations.js +0 -211
  243. package/dist/orchestrator/audit-operations.js +0 -182
  244. package/dist/orchestrator/candidate-operations.js +0 -117
  245. package/dist/orchestrator/cli-options.js +0 -294
  246. package/dist/orchestrator/collaboration-operations.js +0 -86
  247. package/dist/orchestrator/feedback-operations.js +0 -81
  248. package/dist/orchestrator/host-operations.js +0 -78
  249. package/dist/orchestrator/lifecycle-operations.js +0 -650
  250. package/dist/orchestrator/migration-operations.js +0 -44
  251. package/dist/orchestrator/multi-agent-operations.js +0 -362
  252. package/dist/orchestrator/topology-operations.js +0 -84
  253. package/dist/orchestrator.js +0 -925
  254. package/dist/pipeline-runner.js +0 -285
  255. package/dist/reclamation/hash.js +0 -72
  256. package/dist/reclamation.js +0 -812
  257. package/dist/reporter.js +0 -67
  258. package/dist/run-export.js +0 -815
  259. package/dist/run-registry/derive.js +0 -175
  260. package/dist/run-registry/format.js +0 -124
  261. package/dist/run-registry/gc.js +0 -251
  262. package/dist/run-registry/policy.js +0 -16
  263. package/dist/run-registry/queue.js +0 -115
  264. package/dist/run-registry.js +0 -850
  265. package/dist/run-state-schema.js +0 -68
  266. package/dist/scheduling.js +0 -184
  267. package/dist/state-explosion.js +0 -1014
  268. package/dist/state.js +0 -367
  269. package/dist/telemetry-ledger.js +0 -196
  270. package/dist/topology.js +0 -565
  271. package/dist/triggers.js +0 -184
  272. package/dist/trust-audit.js +0 -644
  273. package/dist/types/blackboard.js +0 -2
  274. package/dist/types/candidate.js +0 -2
  275. package/dist/types/collaboration.js +0 -2
  276. package/dist/types/core.js +0 -2
  277. package/dist/types/drive.js +0 -10
  278. package/dist/types/error-feedback.js +0 -2
  279. package/dist/types/evidence-reasoning.js +0 -2
  280. package/dist/types/execution-backend.js +0 -2
  281. package/dist/types/multi-agent.js +0 -2
  282. package/dist/types/observability.js +0 -2
  283. package/dist/types/pipeline.js +0 -2
  284. package/dist/types/reclamation.js +0 -8
  285. package/dist/types/report-bundle.js +0 -6
  286. package/dist/types/result.js +0 -2
  287. package/dist/types/run-registry.js +0 -2
  288. package/dist/types/run.js +0 -2
  289. package/dist/types/sandbox.js +0 -2
  290. package/dist/types/schedule.js +0 -2
  291. package/dist/types/state-node.js +0 -2
  292. package/dist/types/topology.js +0 -2
  293. package/dist/types/trust.js +0 -2
  294. package/dist/types/workbench.js +0 -2
  295. package/dist/types/worker.js +0 -2
  296. package/dist/types/workflow-app.js +0 -2
  297. package/dist/types.js +0 -44
  298. package/dist/util/fingerprint.js +0 -19
  299. package/dist/util/fingerprint.test.js +0 -27
  300. package/dist/verifier.js +0 -78
  301. package/dist/version.js +0 -8
  302. package/dist/workbench-host.js +0 -192
  303. package/dist/workbench.js +0 -192
  304. package/dist/worker-accept/acceptance.js +0 -114
  305. package/dist/worker-accept/blackboard-fanout.js +0 -80
  306. package/dist/worker-accept/blackboard-linkage.js +0 -19
  307. package/dist/worker-accept/context.js +0 -2
  308. package/dist/worker-accept/telemetry-ledger.js +0 -126
  309. package/dist/worker-accept/validation.js +0 -77
  310. package/dist/worker-accept/verifier-completion.js +0 -73
  311. package/dist/worker-isolation/helpers.js +0 -51
  312. package/dist/worker-isolation/paths.js +0 -46
  313. package/dist/worker-isolation.js +0 -656
  314. package/dist/workflow-api.js +0 -131
  315. /package/dist/{types → core/types}/boundary.js +0 -0
@@ -0,0 +1,187 @@
1
+ "use strict";
2
+ // core/state/state-explosion/report.ts — buildStateExplosionReport, the
3
+ // operator-digest builder, and maybeCompactRun's PURE decision half.
4
+ //
5
+ // MILESTONE 4. Byte-exact port of the old build's `buildStateExplosion
6
+ // Report`/`buildOperatorDigestWithContext` (src/state-explosion.ts) minus
7
+ // the disk I/O — persistence (`refreshStateExplosionSummaries`'s writes,
8
+ // `loadStateExplosionSummaryIndex`'s read) is shell/state-explosion-
9
+ // cli.ts's job per docs/rebuild/PLAN.md's core/shell split. This file only builds
10
+ // the report VALUE from an in-memory run + an already-loaded index.
11
+ //
12
+ // See size.ts/graph.ts/digest.ts's own header notes on why `operatorDigest`
13
+ // carries truthfully-empty `failures`/`evidenceDigest`/`trustDigest` at
14
+ // this milestone (no multi-agent/trust records exist yet — milestone 9).
15
+ //
16
+ // Evidence: SPEC/state-core.md "buildStateExplosionReport(...)",
17
+ // "maybeCompactRun(...) — best-effort ... ALL errors silently caught".
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.computeStateSize = computeStateSize;
20
+ exports.buildOperatorDigest = buildOperatorDigest;
21
+ exports.buildStateExplosionReport = buildStateExplosionReport;
22
+ exports.shouldCompactRun = shouldCompactRun;
23
+ const hash_1 = require("../../hash");
24
+ const size_1 = require("./size");
25
+ const graph_1 = require("./graph");
26
+ const digest_1 = require("./digest");
27
+ const helpers_1 = require("./helpers");
28
+ /** `computeStateSize(run, thresholds?)` — builds the graph view via
29
+ * `runToGraphViewFromWorkflowRun` then delegates to
30
+ * `computeStateSizeWithGraph`. Lives here (not size.ts) so size.ts stays
31
+ * graph-builder-agnostic — see size.ts's own header note on this
32
+ * module-boundary choice. */
33
+ function computeStateSize(run, thresholds = size_1.DEFAULT_STATE_EXPLOSION_THRESHOLDS) {
34
+ return (0, size_1.computeStateSizeWithGraph)(run, thresholds, (0, graph_1.runToGraphViewFromWorkflowRun)(run));
35
+ }
36
+ function buildOperatorDigest(run, compact, blackboard, stateSize, now, operator) {
37
+ const hiddenSourceRecords = compact.syntheticNodes.map((syn) => ({
38
+ kind: syn.id.split(":summary:")[1] || syn.kind,
39
+ count: syn.collapsedNodeCount,
40
+ expansionCommand: syn.expansionCommand,
41
+ }));
42
+ const expansionCommands = (0, helpers_1.unique)([
43
+ `node scripts/cw.js multi-agent graph ${run.id} --view full --json`,
44
+ `node scripts/cw.js blackboard message list ${run.id} --topic <topic-id>`,
45
+ `node scripts/cw.js multi-agent graph ${run.id} --view critical-path`,
46
+ `node scripts/cw.js multi-agent failures ${run.id} --json`,
47
+ ...compact.syntheticNodes.map((syn) => syn.expansionCommand),
48
+ ]);
49
+ const evidence = operator?.evidence || [];
50
+ const adopted = evidence.filter((e) => e.status === "adopted");
51
+ const missing = evidence.filter((e) => e.status === "missing" || e.status === "pending" || e.status === "conflicting");
52
+ const rejected = evidence.filter((e) => e.status === "rejected");
53
+ return {
54
+ schemaVersion: size_1.STATE_EXPLOSION_SCHEMA_VERSION,
55
+ runId: run.id,
56
+ id: "operator-digest",
57
+ scope: "run",
58
+ sourceRecordIds: compact.sourceRecordIds,
59
+ sourceFingerprint: (0, hash_1.fingerprintStrings)([compact.sourceFingerprint, blackboard.sourceFingerprint, String(stateSize.total)]),
60
+ includedCount: compact.compactNodeCount,
61
+ omittedCount: compact.collapsedNodeCount,
62
+ importantRefs: compact.criticalPath,
63
+ evidenceRefs: (0, helpers_1.unique)(adopted.map((e) => e.ref || e.id)),
64
+ trustAuditEventRefs: (0, helpers_1.unique)(blackboard.trustAuditEventRefs),
65
+ generatedAt: now,
66
+ status: "valid",
67
+ deterministic: true,
68
+ // Prefer the operator summary's nextAction (it reflects the whole run's
69
+ // blocked/evidence state); fall back to the compact graph's own when no
70
+ // operator summary was threaded in.
71
+ nextAction: operator?.nextAction || compact.nextAction,
72
+ stateSize,
73
+ compactGraphRef: compact.id,
74
+ blackboardDigestRef: blackboard.id,
75
+ criticalPath: compact.criticalPath,
76
+ failures: (operator?.failures || []).map((f) => ({ id: f.id, kind: f.kind, status: f.status, reason: f.reason, nextCommand: f.nextCommand })),
77
+ evidenceDigest: {
78
+ adopted: adopted.length,
79
+ missing: missing.length,
80
+ rejected: rejected.length,
81
+ entries: [...adopted, ...missing].slice(0, 40).map((e) => ({
82
+ id: e.id,
83
+ label: `${e.ref || e.id} (${e.status})`,
84
+ status: e.status,
85
+ sourceIds: [e.sourceId || e.id].filter(Boolean),
86
+ evidenceRefs: [e.ref || e.id].filter(Boolean),
87
+ expansionCommand: `node scripts/cw.js multi-agent evidence ${run.id} --json`,
88
+ })),
89
+ },
90
+ trustDigest: {
91
+ events: operator?.trustEvents || 0,
92
+ policyViolations: blackboard.policyViolations.length,
93
+ judgeRationales: blackboard.judgeRationale.length,
94
+ entries: (0, helpers_1.unique)([...blackboard.policyViolations.map((p) => p.id), ...blackboard.judgeRationale.map((j) => j.id)]),
95
+ },
96
+ hiddenSourceRecords,
97
+ expansionCommands,
98
+ };
99
+ }
100
+ function currentEntryFingerprint(entry, records) {
101
+ if (entry.scope === "blackboard")
102
+ return records.blackboardDigest.sourceFingerprint;
103
+ if (entry.id.startsWith("graph-")) {
104
+ if (entry.id === records.compactGraph.id)
105
+ return records.compactGraph.sourceFingerprint;
106
+ return undefined;
107
+ }
108
+ if (entry.id === "operator-digest")
109
+ return records.operatorDigest.sourceFingerprint;
110
+ return undefined;
111
+ }
112
+ /** Builds the full `StateExplosionReport` VALUE (no disk I/O) from an
113
+ * in-memory run plus an already-loaded persisted index (or none).
114
+ *
115
+ * `options.graphView` lets a caller that already ran
116
+ * `runToGraphViewFromWorkflowRun(run)` this same tick (e.g.
117
+ * `refreshStateExplosionSummaries`) hand that value in, so this function
118
+ * does not build the graph view a second time. Mirrors the old build's
119
+ * `StateExplosionBuildContext` memoization — one graph build per refresh,
120
+ * not one per derived view. */
121
+ function buildStateExplosionReport(run, options = {}) {
122
+ const thresholds = options.thresholds || size_1.DEFAULT_STATE_EXPLOSION_THRESHOLDS;
123
+ const now = options.now || new Date().toISOString();
124
+ const graphView = options.graphView || (0, graph_1.runToGraphViewFromWorkflowRun)(run);
125
+ const stateSize = (0, size_1.computeStateSizeWithGraph)(run, thresholds, graphView);
126
+ const compactGraph = (0, graph_1.buildCompactGraphFromView)(run.id, graphView, "compact", { thresholds, now });
127
+ const criticalPathGraph = (0, graph_1.buildCompactGraphFromView)(run.id, graphView, "critical-path", { thresholds, now });
128
+ // `run.blackboard` is `unknown[]`-typed at this milestone (core/state/
129
+ // types.ts's MultiAgentState/BlackboardState header note — real record
130
+ // shapes land with milestone 9); this cast is the one bridge point
131
+ // between "genuinely empty today" and "typed once milestone 9 writes
132
+ // real records", matching digest.ts's own DigestTopic/Message/... shapes.
133
+ const blackboardDigest = (0, digest_1.summarizeBlackboardDigest)({
134
+ id: run.id,
135
+ blackboard: run.blackboard,
136
+ }, undefined, now);
137
+ const operatorDigest = buildOperatorDigest(run, compactGraph, blackboardDigest, stateSize, now, options.operator);
138
+ const currentFingerprint = (0, hash_1.fingerprintStrings)([
139
+ compactGraph.sourceFingerprint,
140
+ blackboardDigest.sourceFingerprint,
141
+ operatorDigest.sourceFingerprint,
142
+ String(stateSize.total),
143
+ ]);
144
+ const persisted = options.index;
145
+ const staleScopes = [];
146
+ let status = persisted ? "valid" : "absent";
147
+ if (persisted) {
148
+ if (persisted.sourceFingerprint !== currentFingerprint)
149
+ status = "stale";
150
+ for (const entry of persisted.entries) {
151
+ const current = currentEntryFingerprint(entry, { compactGraph, blackboardDigest, operatorDigest });
152
+ if (current && current !== entry.sourceFingerprint)
153
+ staleScopes.push(`${entry.scope}:${entry.id}`);
154
+ }
155
+ if (staleScopes.length)
156
+ status = "stale";
157
+ }
158
+ const nextAction = status === "stale" || status === "absent" ? `node scripts/cw.js summary refresh ${run.id}` : operatorDigest.nextAction;
159
+ return {
160
+ schemaVersion: size_1.STATE_EXPLOSION_SCHEMA_VERSION,
161
+ runId: run.id,
162
+ generatedAt: now,
163
+ stateSize,
164
+ freshness: {
165
+ status,
166
+ persistedFingerprint: persisted?.sourceFingerprint,
167
+ currentFingerprint,
168
+ staleScopes: staleScopes.sort(),
169
+ },
170
+ index: persisted,
171
+ compactGraph,
172
+ criticalPathGraph,
173
+ blackboardDigest,
174
+ operatorDigest,
175
+ hiddenSourceRecords: operatorDigest.hiddenSourceRecords,
176
+ expansionCommands: operatorDigest.expansionCommands,
177
+ nextAction,
178
+ };
179
+ }
180
+ /** The pure decision half of `maybeCompactRun`: true when the caller
181
+ * should refresh summaries. The actual refresh (disk write) + the "catch
182
+ * ALL errors" best-effort wrapper live in shell/state-explosion-cli.ts,
183
+ * since only that layer can fail on real disk I/O. */
184
+ function shouldCompactRun(run, thresholds = size_1.DEFAULT_STATE_EXPLOSION_THRESHOLDS) {
185
+ const graphView = (0, graph_1.runToGraphViewFromWorkflowRun)(run);
186
+ return (0, size_1.computeStateSizeWithGraph)(run, thresholds, graphView).compactionRecommended;
187
+ }
@@ -1,9 +1,30 @@
1
1
  "use strict";
2
+ // core/state/state-explosion/size.ts — computeStateSizeWithGraph,
3
+ // DEFAULT_STATE_EXPLOSION_THRESHOLDS.
4
+ //
5
+ // MILESTONE 4 (docs/rebuild/PLAN.md build order, step 4). Byte-exact port of the old
6
+ // build's src/state-explosion/size.ts. The counts are the same 12
7
+ // categories the old build reads off `run.multiAgent`/`run.blackboard`
8
+ // (loose `unknown[]`-typed record arrays at this milestone — see core/
9
+ // state/types.ts's header note; their per-record shapes land with
10
+ // milestone 9), so this file needs no reshape once those arrays start
11
+ // carrying real records.
12
+ //
13
+ // `computeStateSize` (the old build's one-arg convenience wrapper that
14
+ // ALSO builds the graph) is NOT defined here — the old build's own module
15
+ // boundary already has size.ts call the graph builder from a DIFFERENT
16
+ // file (multi-agent-operator-ux.ts); this file mirrors that by staying
17
+ // graph-builder-agnostic (`computeStateSizeWithGraph` takes the graph
18
+ // view as a plain parameter) and core/state/state-explosion/report.ts
19
+ // (which already imports both this file and graph.ts) supplies the
20
+ // one-arg convenience wrapper instead, avoiding a size.ts <-> graph.ts
21
+ // import cycle.
22
+ //
23
+ // Evidence: SPEC/state-core.md "src/state-explosion.ts + src/state-
24
+ // explosion/* — derived summary layer", "computeStateSize(...)".
2
25
  Object.defineProperty(exports, "__esModule", { value: true });
3
26
  exports.DEFAULT_STATE_EXPLOSION_THRESHOLDS = exports.STATE_EXPLOSION_SCHEMA_VERSION = void 0;
4
- exports.computeStateSize = computeStateSize;
5
27
  exports.computeStateSizeWithGraph = computeStateSizeWithGraph;
6
- const multi_agent_operator_ux_1 = require("../multi-agent-operator-ux");
7
28
  exports.STATE_EXPLOSION_SCHEMA_VERSION = 1;
8
29
  exports.DEFAULT_STATE_EXPLOSION_THRESHOLDS = {
9
30
  graphNodes: 40,
@@ -11,11 +32,8 @@ exports.DEFAULT_STATE_EXPLOSION_THRESHOLDS = {
11
32
  blackboardMessages: 25,
12
33
  blackboardRecords: 40,
13
34
  collapseBucket: 6,
14
- totalRecords: 80
35
+ totalRecords: 80,
15
36
  };
16
- function computeStateSize(run, thresholds = exports.DEFAULT_STATE_EXPLOSION_THRESHOLDS) {
17
- return computeStateSizeWithGraph(run, thresholds, (0, multi_agent_operator_ux_1.buildMultiAgentOperatorGraph)(run));
18
- }
19
37
  function computeStateSizeWithGraph(run, thresholds, graph) {
20
38
  const ma = run.multiAgent || { runs: [], roles: [], groups: [], memberships: [], fanouts: [], fanins: [] };
21
39
  const bb = run.blackboard || { topics: [], messages: [], contexts: [], artifacts: [], snapshots: [], decisions: [] };
@@ -33,7 +51,7 @@ function computeStateSizeWithGraph(run, thresholds, graph) {
33
51
  snapshots: (bb.snapshots || []).length,
34
52
  decisions: (bb.decisions || []).length,
35
53
  graphNodes: graph.nodes.length,
36
- graphEdges: graph.edges.length
54
+ graphEdges: graph.edges.length,
37
55
  };
38
56
  const total = counts.multiAgentRuns +
39
57
  counts.roles +
@@ -1,7 +1,18 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
2
+ // core/state/state-node.ts StateNode lifecycle and pipeline-contract gates.
3
+ //
4
+ // MILESTONE 3. Byte-exact port of the old build's src/state-node.ts, split
5
+ // into a PURE half (this file: create/transition/validate/link/record —
6
+ // everything that does not touch disk) and a shell half
7
+ // (shell/node-store.ts: writeRunNode, the only disk write). `appendRunNode`
8
+ // mutates `run.nodes` in place (pure data mutation, no fs) and then calls
9
+ // out to a caller-supplied persist function so this file itself never
10
+ // imports fs.
11
+ //
12
+ // Evidence: SPEC/state-core.md "src/state-node.ts — StateNode lifecycle and
13
+ // contract gates", "StateNode transition matrix", "Deterministic id
14
+ // fallback", "Contract gates" (docs/rebuild/PLAN.md byte-compat item 7 — the double
15
+ // commit gate).
5
16
  Object.defineProperty(exports, "__esModule", { value: true });
6
17
  exports.PipelineContractError = exports.PIPELINE_CONTRACT_SCHEMA_VERSION = exports.STATE_NODE_SCHEMA_VERSION = void 0;
7
18
  exports.createStateNode = createStateNode;
@@ -12,37 +23,36 @@ exports.recordNodeError = recordNodeError;
12
23
  exports.linkStateNodes = linkStateNodes;
13
24
  exports.appendRunNode = appendRunNode;
14
25
  exports.upsertRunContract = upsertRunContract;
15
- exports.writeRunNode = writeRunNode;
16
26
  exports.artifactExists = artifactExists;
17
- const node_fs_1 = __importDefault(require("node:fs"));
18
- const node_path_1 = __importDefault(require("node:path"));
19
- const state_1 = require("./state");
20
- const execution_backend_1 = require("./execution-backend");
21
- const telemetry_attestation_1 = require("./telemetry-attestation");
27
+ const hash_1 = require("../hash");
22
28
  exports.STATE_NODE_SCHEMA_VERSION = 1;
23
29
  exports.PIPELINE_CONTRACT_SCHEMA_VERSION = 1;
24
30
  class PipelineContractError extends Error {
25
31
  structured;
26
- constructor(error) {
32
+ /** `error.at` wins when the caller already has one (e.g. re-wrapping a
33
+ * structured error); `now` is the explicit clock value for a fresh one;
34
+ * the real clock is read ONLY when neither is given, matching
35
+ * node-snapshot.ts's `options.now` fallback pattern. */
36
+ constructor(error, now) {
27
37
  super(error.message);
28
38
  this.name = "PipelineContractError";
29
- this.structured = {
30
- ...error,
31
- at: error.at || new Date().toISOString()
32
- };
39
+ this.structured = { ...error, at: error.at || now || new Date().toISOString() };
33
40
  }
34
41
  }
35
42
  exports.PipelineContractError = PipelineContractError;
36
- function createStateNode(input) {
37
- const now = new Date().toISOString();
43
+ /** `now` is the explicit clock value; the real clock is read ONLY when it
44
+ * is omitted, matching node-snapshot.ts's `options.now` fallback so a
45
+ * caller that always passes `now` gets byte-stable createdAt/updatedAt. */
46
+ function createStateNode(input, now) {
47
+ const at = now || new Date().toISOString();
38
48
  return {
39
49
  schemaVersion: exports.STATE_NODE_SCHEMA_VERSION,
40
50
  id: input.id || createNodeId(input),
41
51
  kind: input.kind,
42
52
  status: input.status || "pending",
43
53
  loopStage: input.loopStage,
44
- createdAt: now,
45
- updatedAt: now,
54
+ createdAt: at,
55
+ updatedAt: at,
46
56
  inputs: input.inputs || {},
47
57
  outputs: input.outputs || {},
48
58
  artifacts: input.artifacts || [],
@@ -51,44 +61,34 @@ function createStateNode(input) {
51
61
  parents: input.parents || [],
52
62
  children: input.children || [],
53
63
  contractId: input.contractId,
54
- metadata: input.metadata
64
+ metadata: input.metadata,
55
65
  };
56
66
  }
57
- function transitionStateNode(node, input) {
67
+ /** The full transition matrix PLUS the second gate: `committed` is refused
68
+ * unless the node is already `verified` (checked AFTER the matrix, its own
69
+ * error code `commit-without-verifier`). An illegal transition throws
70
+ * BEFORE the node changes. */
71
+ function transitionStateNode(node, input, now) {
58
72
  if (!isLegalTransition(node.status, input.status)) {
59
- throw contractError("illegal-transition", `State node ${node.id} cannot transition from ${node.status} to ${input.status}`, {
60
- nodeId: node.id,
61
- details: {
62
- from: node.status,
63
- to: input.status
64
- }
65
- });
73
+ throw contractError("illegal-transition", `State node ${node.id} cannot transition from ${node.status} to ${input.status}`, { nodeId: node.id, details: { from: node.status, to: input.status } });
66
74
  }
67
75
  if (input.status === "committed" && node.status !== "verified") {
68
- throw contractError("commit-without-verifier", `State node ${node.id} cannot be committed before it is verified`, {
69
- nodeId: node.id,
70
- details: {
71
- from: node.status,
72
- to: input.status
73
- }
74
- });
76
+ throw contractError("commit-without-verifier", `State node ${node.id} cannot be committed before it is verified`, { nodeId: node.id, details: { from: node.status, to: input.status } });
75
77
  }
76
78
  return {
77
79
  ...node,
78
80
  status: input.status,
79
81
  loopStage: input.loopStage || node.loopStage,
80
- updatedAt: new Date().toISOString(),
82
+ updatedAt: now || new Date().toISOString(),
81
83
  outputs: input.outputs ? { ...node.outputs, ...input.outputs } : node.outputs,
82
84
  artifacts: input.artifacts ? mergeById(node.artifacts, input.artifacts) : node.artifacts,
83
85
  evidence: input.evidence ? mergeById(node.evidence, input.evidence) : node.evidence,
84
- metadata: input.metadata ? { ...(node.metadata || {}), ...input.metadata } : node.metadata
86
+ metadata: input.metadata ? { ...(node.metadata || {}), ...input.metadata } : node.metadata,
85
87
  };
86
88
  }
87
89
  function validatePipelineContract(contract) {
88
90
  if (contract.schemaVersion !== exports.PIPELINE_CONTRACT_SCHEMA_VERSION) {
89
- throw contractError("invalid-contract-schema", `Pipeline contract ${contract.id || "(missing id)"} has unsupported schemaVersion`, {
90
- details: { schemaVersion: contract.schemaVersion }
91
- });
91
+ throw contractError("invalid-contract-schema", `Pipeline contract ${contract.id || "(missing id)"} has unsupported schemaVersion`, { details: { schemaVersion: contract.schemaVersion } });
92
92
  }
93
93
  if (!contract.id)
94
94
  throw contractError("invalid-contract-id", "Pipeline contract id is required");
@@ -106,97 +106,81 @@ function validatePipelineContract(contract) {
106
106
  }
107
107
  if (contract.compatibility.minSchemaVersion > exports.STATE_NODE_SCHEMA_VERSION) {
108
108
  throw contractError("incompatible-contract", `Pipeline contract ${contract.id} requires newer StateNode schema`, {
109
- details: contract.compatibility
109
+ details: contract.compatibility,
110
110
  });
111
111
  }
112
112
  }
113
- function assertNodeSatisfiesContract(node, contract, stageId) {
113
+ /** `pathExists` defaults to a function that always returns `true` (no path
114
+ * ever "missing") ONLY when the caller genuinely has no filesystem to
115
+ * check against; every real caller (shell/) passes `fs.existsSync` so the
116
+ * `missing-artifact-path` gate behaves exactly like the old build. Kept as
117
+ * an explicit parameter (never a top-level `require("node:fs")`) so this
118
+ * stays a pure core/ module per docs/rebuild/PLAN.md's core/shell split. */
119
+ function assertNodeSatisfiesContract(node, contract, stageId, pathExists = () => true) {
114
120
  validatePipelineContract(contract);
115
121
  const stage = contract.stages.find((candidate) => candidate.id === stageId);
116
122
  if (!stage) {
117
- throw contractError("unknown-contract-stage", `Pipeline contract ${contract.id} has no stage ${stageId}`, {
118
- nodeId: node.id
119
- });
123
+ throw contractError("unknown-contract-stage", `Pipeline contract ${contract.id} has no stage ${stageId}`, { nodeId: node.id });
120
124
  }
121
125
  if (!stage.acceptedInputKinds.includes(node.kind)) {
122
126
  throw contractError("unexpected-node-kind", `Stage ${stage.id} does not accept node kind ${node.kind}`, {
123
127
  nodeId: node.id,
124
- details: { expected: stage.acceptedInputKinds, actual: node.kind }
128
+ details: { expected: stage.acceptedInputKinds, actual: node.kind },
125
129
  });
126
130
  }
127
131
  if (!stage.acceptedInputStatuses.includes(node.status)) {
128
132
  throw contractError("unexpected-node-status", `Stage ${stage.id} does not accept node status ${node.status}`, {
129
133
  nodeId: node.id,
130
- details: { expected: stage.acceptedInputStatuses, actual: node.status }
134
+ details: { expected: stage.acceptedInputStatuses, actual: node.status },
131
135
  });
132
136
  }
133
- assertRequiredArtifacts(node, stage);
137
+ assertRequiredArtifacts(node, stage, pathExists);
134
138
  assertRequiredEvidence(node, stage, contract);
135
139
  assertVerifierGate(node, stage, contract);
136
140
  }
137
- function recordNodeError(node, error) {
141
+ function recordNodeError(node, error, now) {
142
+ const at = now || new Date().toISOString();
138
143
  return {
139
144
  ...node,
140
145
  status: "failed",
141
- updatedAt: new Date().toISOString(),
142
- errors: [
143
- ...node.errors,
144
- {
145
- ...error,
146
- at: error.at || new Date().toISOString(),
147
- nodeId: error.nodeId || node.id
148
- }
149
- ]
146
+ updatedAt: at,
147
+ errors: [...node.errors, { ...error, at: error.at || at, nodeId: error.nodeId || node.id }],
150
148
  };
151
149
  }
152
- function linkStateNodes(parent, child) {
150
+ function linkStateNodes(parent, child, now) {
151
+ const at = now || new Date().toISOString();
153
152
  return [
154
- {
155
- ...parent,
156
- updatedAt: new Date().toISOString(),
157
- children: unique([...parent.children, child.id])
158
- },
159
- {
160
- ...child,
161
- updatedAt: new Date().toISOString(),
162
- parents: unique([...child.parents, parent.id])
163
- }
153
+ { ...parent, updatedAt: at, children: unique([...parent.children, child.id]) },
154
+ { ...child, updatedAt: at, parents: unique([...child.parents, parent.id]) },
164
155
  ];
165
156
  }
166
- function appendRunNode(run, node) {
167
- // Mutate run.nodes in place rather than rebuilding the whole array on every
168
- // append. The old code did `nodes.map(...)` / `[...nodes, node]` per call, so a
169
- // run that appends N nodes allocated arrays of size 1..N — O(N^2) churn + GC on
170
- // a hot path (every dispatch/result/blackboard node). In place: O(1) per append
171
- // for the common new-node case, and the resulting array — content AND order — is
172
- // byte-identical to before (push appends at the end, replace keeps the slot), so
173
- // the persisted state.json is unchanged. appendRunNode is the only writer of
174
- // run.nodes, so the array reference stays stable across a run.
157
+ /** Upsert `node` into `run.nodes` IN PLACE (replace at the same index when
158
+ * the id exists, else push at the end — the array reference is stable).
159
+ * `persist` is a caller-supplied side effect (shell/node-store.ts's
160
+ * `writeRunNode`) so this pure module never imports fs itself. */
161
+ function appendRunNode(run, node, persist) {
175
162
  const nodes = run.nodes || (run.nodes = []);
176
163
  const index = nodes.findIndex((candidate) => candidate.id === node.id);
177
164
  if (index >= 0)
178
165
  nodes[index] = node;
179
166
  else
180
167
  nodes.push(node);
181
- writeRunNode(run, node);
168
+ if (persist)
169
+ persist(run, node);
182
170
  return node;
183
171
  }
184
172
  function upsertRunContract(run, contract) {
185
173
  validatePipelineContract(contract);
186
174
  const contracts = run.contracts || [];
187
175
  const index = contracts.findIndex((candidate) => candidate.id === contract.id);
188
- run.contracts =
189
- index >= 0 ? contracts.map((candidate) => (candidate.id === contract.id ? contract : candidate)) : [...contracts, contract];
176
+ run.contracts = index >= 0 ? contracts.map((candidate) => (candidate.id === contract.id ? contract : candidate)) : [...contracts, contract];
190
177
  return contract;
191
178
  }
192
- function writeRunNode(run, node) {
193
- const dir = run.paths.stateNodesDir || node_path_1.default.join(run.paths.runDir, "nodes");
194
- const file = node_path_1.default.join(dir, `${(0, state_1.safeFileName)(node.id)}.json`);
195
- (0, state_1.writeJson)(file, node);
196
- return file;
197
- }
198
- function artifactExists(artifact) {
199
- return Boolean(artifact.path && node_fs_1.default.existsSync(artifact.path));
179
+ /** `Boolean(artifact.path && <exists>)` — the existence check itself is
180
+ * supplied by the caller (shell) so this stays pure; callers pass
181
+ * `fs.existsSync` in practice. */
182
+ function artifactExists(artifact, exists) {
183
+ return Boolean(artifact.path && exists(artifact.path));
200
184
  }
201
185
  function validateStage(contract, stage, seen) {
202
186
  if (!stage.id)
@@ -216,20 +200,20 @@ function validateStage(contract, stage, seen) {
216
200
  throw contractError("invalid-contract-stage-output", `Stage ${stage.id} producedOutputKind is required`);
217
201
  }
218
202
  }
219
- function assertRequiredArtifacts(node, stage) {
203
+ function assertRequiredArtifacts(node, stage, pathExists) {
220
204
  for (const required of stage.requiredArtifacts || []) {
221
205
  const artifact = node.artifacts.find((candidate) => candidate.id === required || candidate.kind === required);
222
206
  if (!artifact) {
223
207
  throw contractError("missing-required-artifact", `Node ${node.id} is missing required artifact ${required}`, {
224
208
  nodeId: node.id,
225
- details: { requiredArtifact: required }
209
+ details: { requiredArtifact: required },
226
210
  });
227
211
  }
228
- if (!artifactExists(artifact)) {
212
+ if (!artifactExists(artifact, pathExists)) {
229
213
  throw contractError("missing-artifact-path", `Node ${node.id} artifact ${artifact.id} path does not exist`, {
230
214
  nodeId: node.id,
231
215
  path: artifact.path,
232
- details: { artifactId: artifact.id }
216
+ details: { artifactId: artifact.id },
233
217
  });
234
218
  }
235
219
  }
@@ -240,7 +224,7 @@ function assertRequiredEvidence(node, stage, contract) {
240
224
  if ((requiredEvidence.length || contractRequiresEvidence) && !node.evidence.length) {
241
225
  throw contractError("missing-required-evidence", `Node ${node.id} is missing required evidence`, {
242
226
  nodeId: node.id,
243
- details: { requiredEvidence }
227
+ details: { requiredEvidence },
244
228
  });
245
229
  }
246
230
  for (const required of requiredEvidence) {
@@ -248,7 +232,7 @@ function assertRequiredEvidence(node, stage, contract) {
248
232
  if (!evidence) {
249
233
  throw contractError("missing-required-evidence", `Node ${node.id} is missing required evidence ${required}`, {
250
234
  nodeId: node.id,
251
- details: { requiredEvidence: required }
235
+ details: { requiredEvidence: required },
252
236
  });
253
237
  }
254
238
  }
@@ -262,15 +246,16 @@ function assertVerifierGate(node, stage, contract) {
262
246
  if (!acceptedStatuses.includes(node.status)) {
263
247
  throw contractError("verifier-gate-blocked", `Stage ${stage.id} requires verifier status ${acceptedStatuses.join(", ")}`, {
264
248
  nodeId: node.id,
265
- details: { actual: node.status, accepted: acceptedStatuses }
249
+ details: { actual: node.status, accepted: acceptedStatuses },
266
250
  });
267
251
  }
268
252
  if ((gate?.requiredEvidence || contract.evidencePolicy?.requireEvidence) && !node.evidence.length) {
269
- throw contractError("verifier-gate-missing-evidence", `Stage ${stage.id} requires evidence before commit`, {
270
- nodeId: node.id
271
- });
253
+ throw contractError("verifier-gate-missing-evidence", `Stage ${stage.id} requires evidence before commit`, { nodeId: node.id });
272
254
  }
273
255
  }
256
+ /** The transition matrix: `same -> same` is always legal (checked first via
257
+ * `from === to`), plus the table below. `committed` is terminal (empty
258
+ * array). */
274
259
  function isLegalTransition(from, to) {
275
260
  if (from === to)
276
261
  return true;
@@ -282,31 +267,23 @@ function isLegalTransition(from, to) {
282
267
  blocked: ["pending", "failed"],
283
268
  verified: ["committed", "rejected"],
284
269
  rejected: ["pending", "failed"],
285
- committed: []
270
+ committed: [],
286
271
  };
287
272
  return allowed[from].includes(to);
288
273
  }
289
274
  function contractError(code, message, options = {}) {
290
- return new PipelineContractError({
291
- code,
292
- message,
293
- ...options
294
- });
275
+ return new PipelineContractError({ code, message, ...options });
295
276
  }
296
- // Deterministic id (FreeBSD-audit L12/L13): no wall-clock stamp, no PRNG suffix.
297
- // Almost every node is created WITH an explicit, already-deterministic id
298
- // (e.g. `${run.id}:result:${task.id}`); this fallback only fires for ad-hoc nodes
299
- // minted without an id. We bind the id to a short sha256 of the node's stable
300
- // content (kind + loopStage + canonical inputs/outputs/contract), so the same
301
- // logical node yields a byte-identical id across runs and replay reaches the same
302
- // fingerprint. Two nodes with identical content collapse to the same id by design.
277
+ /** Deterministic id fallback: no wall-clock, no random. A node minted
278
+ * without an explicit id gets `"<kind>-" + <first 16 hex of sha256(...)>`.
279
+ * Two nodes with the same content collapse to ONE id by design. */
303
280
  function createNodeId(input) {
304
- const digest = (0, execution_backend_1.sha256)((0, telemetry_attestation_1.stableStringify)({
281
+ const digest = (0, hash_1.sha256)((0, hash_1.stableStringify)({
305
282
  kind: input.kind,
306
283
  loopStage: input.loopStage,
307
284
  contractId: input.contractId ?? null,
308
285
  inputs: input.inputs ?? null,
309
- outputs: input.outputs ?? null
286
+ outputs: input.outputs ?? null,
310
287
  }));
311
288
  return `${input.kind}-${digest.replace("sha256:", "").slice(0, 16)}`;
312
289
  }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ // core/state/types.ts — the state-kernel's own type set.
3
+ //
4
+ // MILESTONE 3 (docs/rebuild/PLAN.md build order, step 3). Scoped to exactly what
5
+ // state-core.md's public surface needs: WorkflowRun and everything it
6
+ // carries, StateNode + its snapshot/replay/diff family, the pipeline
7
+ // contract shape, and the small persisted-record shapes validation.ts
8
+ // guards. Later milestones (multi-agent, blackboard, topology, worker,
9
+ // candidate, trust) add their OWN richer types under their own module —
10
+ // this file only carries the FIELD SET this milestone's schema/migration/
11
+ // node-lifecycle/snapshot code actually reads or writes, ported from the
12
+ // old build's src/types/*.ts. Optional subsystem state (multiAgent,
13
+ // blackboard, topologies, collaboration, workers, etc.) is typed loosely
14
+ // here (its own schemaVersion + array keys only) since normalizeRunState
15
+ // only ever fills defaults/shape-checks those fields at this milestone;
16
+ // the richer per-record shapes land with their owning milestone.
17
+ //
18
+ // Pure types — no runtime cost, no imports beyond each other.
19
+ Object.defineProperty(exports, "__esModule", { value: true });