@acpus/runtime 0.8.0 → 0.9.0-alpha.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 (289) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/admission/input.d.ts +5 -0
  3. package/dist/admission/input.d.ts.map +1 -0
  4. package/dist/admission/input.js +17 -0
  5. package/dist/admission/input.js.map +1 -0
  6. package/dist/artifacts/rewrite.d.ts +7 -0
  7. package/dist/artifacts/rewrite.d.ts.map +1 -0
  8. package/dist/artifacts/rewrite.js +28 -0
  9. package/dist/artifacts/rewrite.js.map +1 -0
  10. package/dist/control/agent-overrides.d.ts +4 -0
  11. package/dist/control/agent-overrides.d.ts.map +1 -0
  12. package/dist/control/agent-overrides.js +40 -0
  13. package/dist/control/agent-overrides.js.map +1 -0
  14. package/dist/daemon/loop.d.ts +16 -0
  15. package/dist/daemon/loop.d.ts.map +1 -0
  16. package/dist/daemon/loop.js +191 -0
  17. package/dist/daemon/loop.js.map +1 -0
  18. package/dist/daemon/sessions.d.ts +23 -0
  19. package/dist/daemon/sessions.d.ts.map +1 -0
  20. package/dist/daemon/sessions.js +190 -0
  21. package/dist/daemon/sessions.js.map +1 -0
  22. package/dist/daemon/socket.d.ts +82 -0
  23. package/dist/daemon/socket.d.ts.map +1 -0
  24. package/dist/daemon/socket.js +341 -0
  25. package/dist/daemon/socket.js.map +1 -0
  26. package/dist/daemon/tick.d.ts +9 -0
  27. package/dist/daemon/tick.d.ts.map +1 -0
  28. package/dist/daemon/tick.js +18 -0
  29. package/dist/daemon/tick.js.map +1 -0
  30. package/dist/evaluation/admissible.d.ts +2 -0
  31. package/dist/evaluation/admissible.d.ts.map +1 -0
  32. package/dist/evaluation/admissible.js +50 -0
  33. package/dist/evaluation/admissible.js.map +1 -0
  34. package/dist/evaluation/evaluator.d.ts +14 -0
  35. package/dist/evaluation/evaluator.d.ts.map +1 -0
  36. package/dist/evaluation/evaluator.js +34 -0
  37. package/dist/evaluation/evaluator.js.map +1 -0
  38. package/dist/evaluation/loop-limit.d.ts +4 -0
  39. package/dist/evaluation/loop-limit.d.ts.map +1 -0
  40. package/dist/evaluation/loop-limit.js +9 -0
  41. package/dist/evaluation/loop-limit.js.map +1 -0
  42. package/dist/evaluation/schema.d.ts +4 -0
  43. package/dist/evaluation/schema.d.ts.map +1 -0
  44. package/dist/evaluation/schema.js +92 -0
  45. package/dist/evaluation/schema.js.map +1 -0
  46. package/dist/execution/advance.d.ts +18 -0
  47. package/dist/execution/advance.d.ts.map +1 -0
  48. package/dist/execution/advance.js +57 -0
  49. package/dist/execution/advance.js.map +1 -0
  50. package/dist/execution/agent-node.d.ts +23 -0
  51. package/dist/execution/agent-node.d.ts.map +1 -0
  52. package/dist/execution/agent-node.js +512 -0
  53. package/dist/execution/agent-node.js.map +1 -0
  54. package/dist/execution/duration.d.ts +2 -0
  55. package/dist/execution/duration.d.ts.map +1 -0
  56. package/dist/execution/duration.js +15 -0
  57. package/dist/execution/duration.js.map +1 -0
  58. package/dist/execution/ir.d.ts +3 -0
  59. package/dist/execution/ir.d.ts.map +1 -0
  60. package/dist/execution/ir.js +46 -0
  61. package/dist/execution/ir.js.map +1 -0
  62. package/dist/execution/scheduler.d.ts +59 -0
  63. package/dist/execution/scheduler.d.ts.map +1 -0
  64. package/dist/execution/scheduler.js +306 -0
  65. package/dist/execution/scheduler.js.map +1 -0
  66. package/dist/execution/task-executor.d.ts +14 -0
  67. package/dist/execution/task-executor.d.ts.map +1 -0
  68. package/dist/execution/task-executor.js +186 -0
  69. package/dist/execution/task-executor.js.map +1 -0
  70. package/dist/hooks/config.d.ts +32 -0
  71. package/dist/hooks/config.d.ts.map +1 -0
  72. package/dist/hooks/config.js +112 -0
  73. package/dist/hooks/config.js.map +1 -0
  74. package/dist/hooks/context.d.ts +50 -0
  75. package/dist/hooks/context.d.ts.map +1 -0
  76. package/dist/hooks/context.js +116 -0
  77. package/dist/hooks/context.js.map +1 -0
  78. package/dist/hooks/events.d.ts +22 -0
  79. package/dist/hooks/events.d.ts.map +1 -0
  80. package/dist/hooks/events.js +41 -0
  81. package/dist/hooks/events.js.map +1 -0
  82. package/dist/hooks/journal.d.ts +21 -19
  83. package/dist/hooks/journal.d.ts.map +1 -1
  84. package/dist/hooks/journal.js +1 -48
  85. package/dist/hooks/journal.js.map +1 -1
  86. package/dist/hooks/loader.d.ts +33 -39
  87. package/dist/hooks/loader.d.ts.map +1 -1
  88. package/dist/hooks/loader.js +79 -95
  89. package/dist/hooks/loader.js.map +1 -1
  90. package/dist/hooks/runner.d.ts +14 -41
  91. package/dist/hooks/runner.d.ts.map +1 -1
  92. package/dist/hooks/runner.js +177 -145
  93. package/dist/hooks/runner.js.map +1 -1
  94. package/dist/index.d.ts +13 -28
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.js +13 -33
  97. package/dist/index.js.map +1 -1
  98. package/dist/runs/advance-runtime.d.ts +50 -0
  99. package/dist/runs/advance-runtime.d.ts.map +1 -0
  100. package/dist/runs/advance-runtime.js +82 -0
  101. package/dist/runs/advance-runtime.js.map +1 -0
  102. package/dist/runs/use-cases.d.ts +111 -0
  103. package/dist/runs/use-cases.d.ts.map +1 -0
  104. package/dist/runs/use-cases.js +539 -0
  105. package/dist/runs/use-cases.js.map +1 -0
  106. package/dist/scheduler/advance.d.ts +65 -0
  107. package/dist/scheduler/advance.d.ts.map +1 -0
  108. package/dist/scheduler/advance.js +435 -0
  109. package/dist/scheduler/advance.js.map +1 -0
  110. package/dist/scheduler/control.d.ts +49 -0
  111. package/dist/scheduler/control.d.ts.map +1 -0
  112. package/dist/scheduler/control.js +212 -0
  113. package/dist/scheduler/control.js.map +1 -0
  114. package/dist/scheduler/event-codec.d.ts +4 -0
  115. package/dist/scheduler/event-codec.d.ts.map +1 -0
  116. package/dist/scheduler/event-codec.js +57 -0
  117. package/dist/scheduler/event-codec.js.map +1 -0
  118. package/dist/scheduler/events.d.ts +193 -0
  119. package/dist/scheduler/events.d.ts.map +1 -0
  120. package/dist/scheduler/events.js +13 -0
  121. package/dist/scheduler/events.js.map +1 -0
  122. package/dist/scheduler/fork-seed.d.ts +38 -0
  123. package/dist/scheduler/fork-seed.d.ts.map +1 -0
  124. package/dist/scheduler/fork-seed.js +590 -0
  125. package/dist/scheduler/fork-seed.js.map +1 -0
  126. package/dist/scheduler/identity.d.ts +8 -0
  127. package/dist/scheduler/identity.d.ts.map +1 -0
  128. package/dist/scheduler/identity.js +49 -0
  129. package/dist/scheduler/identity.js.map +1 -0
  130. package/dist/scheduler/ir-walk.d.ts +3 -0
  131. package/dist/scheduler/ir-walk.d.ts.map +1 -0
  132. package/dist/scheduler/ir-walk.js +25 -0
  133. package/dist/scheduler/ir-walk.js.map +1 -0
  134. package/dist/scheduler/limiter.d.ts +7 -0
  135. package/dist/scheduler/limiter.d.ts.map +1 -0
  136. package/dist/scheduler/limiter.js +10 -0
  137. package/dist/scheduler/limiter.js.map +1 -0
  138. package/dist/scheduler/materialize.d.ts +7 -0
  139. package/dist/scheduler/materialize.d.ts.map +1 -0
  140. package/dist/scheduler/materialize.js +756 -0
  141. package/dist/scheduler/materialize.js.map +1 -0
  142. package/dist/scheduler/membership.d.ts +12 -0
  143. package/dist/scheduler/membership.d.ts.map +1 -0
  144. package/dist/scheduler/membership.js +74 -0
  145. package/dist/scheduler/membership.js.map +1 -0
  146. package/dist/scheduler/node-executor.d.ts +15 -0
  147. package/dist/scheduler/node-executor.d.ts.map +1 -0
  148. package/dist/scheduler/node-executor.js +69 -0
  149. package/dist/scheduler/node-executor.js.map +1 -0
  150. package/dist/scheduler/runtime-runner.d.ts +44 -0
  151. package/dist/scheduler/runtime-runner.d.ts.map +1 -0
  152. package/dist/scheduler/runtime-runner.js +155 -0
  153. package/dist/scheduler/runtime-runner.js.map +1 -0
  154. package/dist/scheduler/scope.d.ts +6 -0
  155. package/dist/scheduler/scope.d.ts.map +1 -0
  156. package/dist/scheduler/scope.js +56 -0
  157. package/dist/scheduler/scope.js.map +1 -0
  158. package/dist/scheduler/store-port.d.ts +211 -0
  159. package/dist/scheduler/store-port.d.ts.map +1 -0
  160. package/dist/scheduler/store-port.js +28 -0
  161. package/dist/scheduler/store-port.js.map +1 -0
  162. package/dist/scheduler/transitions.d.ts +89 -0
  163. package/dist/scheduler/transitions.d.ts.map +1 -0
  164. package/dist/scheduler/transitions.js +967 -0
  165. package/dist/scheduler/transitions.js.map +1 -0
  166. package/dist/scheduler/types.d.ts +146 -0
  167. package/dist/scheduler/types.d.ts.map +1 -0
  168. package/dist/{executors → scheduler}/types.js.map +1 -1
  169. package/dist/store/store.d.ts +390 -0
  170. package/dist/store/store.d.ts.map +1 -0
  171. package/dist/store/store.js +3053 -0
  172. package/dist/store/store.js.map +1 -0
  173. package/dist/visualization/overlay.d.ts +86 -0
  174. package/dist/visualization/overlay.d.ts.map +1 -0
  175. package/dist/visualization/overlay.js +161 -0
  176. package/dist/visualization/overlay.js.map +1 -0
  177. package/package.json +19 -37
  178. package/README.md +0 -7
  179. package/dist/agent-telemetry.d.ts +0 -56
  180. package/dist/agent-telemetry.d.ts.map +0 -1
  181. package/dist/agent-telemetry.js +0 -304
  182. package/dist/agent-telemetry.js.map +0 -1
  183. package/dist/artifacts.d.ts +0 -45
  184. package/dist/artifacts.d.ts.map +0 -1
  185. package/dist/artifacts.js +0 -163
  186. package/dist/artifacts.js.map +0 -1
  187. package/dist/attempt-artifacts.d.ts +0 -35
  188. package/dist/attempt-artifacts.d.ts.map +0 -1
  189. package/dist/attempt-artifacts.js +0 -90
  190. package/dist/attempt-artifacts.js.map +0 -1
  191. package/dist/client.d.ts +0 -82
  192. package/dist/client.d.ts.map +0 -1
  193. package/dist/client.js +0 -200
  194. package/dist/client.js.map +0 -1
  195. package/dist/evaluator.d.ts +0 -36
  196. package/dist/evaluator.d.ts.map +0 -1
  197. package/dist/evaluator.js +0 -101
  198. package/dist/evaluator.js.map +0 -1
  199. package/dist/executors/agent.d.ts +0 -103
  200. package/dist/executors/agent.d.ts.map +0 -1
  201. package/dist/executors/agent.js +0 -516
  202. package/dist/executors/agent.js.map +0 -1
  203. package/dist/executors/mock-program.d.ts +0 -26
  204. package/dist/executors/mock-program.d.ts.map +0 -1
  205. package/dist/executors/mock-program.js +0 -100
  206. package/dist/executors/mock-program.js.map +0 -1
  207. package/dist/executors/output-preview.d.ts +0 -2
  208. package/dist/executors/output-preview.d.ts.map +0 -1
  209. package/dist/executors/output-preview.js +0 -20
  210. package/dist/executors/output-preview.js.map +0 -1
  211. package/dist/executors/program.d.ts +0 -30
  212. package/dist/executors/program.d.ts.map +0 -1
  213. package/dist/executors/program.js +0 -230
  214. package/dist/executors/program.js.map +0 -1
  215. package/dist/executors/types.d.ts +0 -32
  216. package/dist/executors/types.d.ts.map +0 -1
  217. package/dist/fork.d.ts +0 -74
  218. package/dist/fork.d.ts.map +0 -1
  219. package/dist/fork.js +0 -278
  220. package/dist/fork.js.map +0 -1
  221. package/dist/hooks/payload.d.ts +0 -17
  222. package/dist/hooks/payload.d.ts.map +0 -1
  223. package/dist/hooks/payload.js +0 -45
  224. package/dist/hooks/payload.js.map +0 -1
  225. package/dist/interpreter.d.ts +0 -168
  226. package/dist/interpreter.d.ts.map +0 -1
  227. package/dist/interpreter.js +0 -1747
  228. package/dist/interpreter.js.map +0 -1
  229. package/dist/keys.d.ts +0 -77
  230. package/dist/keys.d.ts.map +0 -1
  231. package/dist/keys.js +0 -382
  232. package/dist/keys.js.map +0 -1
  233. package/dist/run-control.d.ts +0 -45
  234. package/dist/run-control.d.ts.map +0 -1
  235. package/dist/run-control.js +0 -255
  236. package/dist/run-control.js.map +0 -1
  237. package/dist/run-id.d.ts +0 -3
  238. package/dist/run-id.d.ts.map +0 -1
  239. package/dist/run-id.js +0 -10
  240. package/dist/run-id.js.map +0 -1
  241. package/dist/state-machine.d.ts +0 -31
  242. package/dist/state-machine.d.ts.map +0 -1
  243. package/dist/state-machine.js +0 -102
  244. package/dist/state-machine.js.map +0 -1
  245. package/dist/store.d.ts +0 -92
  246. package/dist/store.d.ts.map +0 -1
  247. package/dist/store.js +0 -420
  248. package/dist/store.js.map +0 -1
  249. package/dist/supervisor-app.d.ts +0 -27
  250. package/dist/supervisor-app.d.ts.map +0 -1
  251. package/dist/supervisor-app.js +0 -694
  252. package/dist/supervisor-app.js.map +0 -1
  253. package/dist/supervisor-discovery.d.ts +0 -18
  254. package/dist/supervisor-discovery.d.ts.map +0 -1
  255. package/dist/supervisor-discovery.js +0 -180
  256. package/dist/supervisor-discovery.js.map +0 -1
  257. package/dist/supervisor-entry.d.ts +0 -11
  258. package/dist/supervisor-entry.d.ts.map +0 -1
  259. package/dist/supervisor-entry.js +0 -50
  260. package/dist/supervisor-entry.js.map +0 -1
  261. package/dist/supervisor-lock.d.ts +0 -26
  262. package/dist/supervisor-lock.d.ts.map +0 -1
  263. package/dist/supervisor-lock.js +0 -49
  264. package/dist/supervisor-lock.js.map +0 -1
  265. package/dist/supervisor-runner.d.ts +0 -11
  266. package/dist/supervisor-runner.d.ts.map +0 -1
  267. package/dist/supervisor-runner.js +0 -128
  268. package/dist/supervisor-runner.js.map +0 -1
  269. package/dist/types.d.ts +0 -375
  270. package/dist/types.d.ts.map +0 -1
  271. package/dist/types.js +0 -7
  272. package/dist/types.js.map +0 -1
  273. package/dist/validate-input.d.ts +0 -27
  274. package/dist/validate-input.d.ts.map +0 -1
  275. package/dist/validate-input.js +0 -56
  276. package/dist/validate-input.js.map +0 -1
  277. package/dist/validate-signal.d.ts +0 -14
  278. package/dist/validate-signal.d.ts.map +0 -1
  279. package/dist/validate-signal.js +0 -31
  280. package/dist/validate-signal.js.map +0 -1
  281. package/dist/workflow-context.d.ts +0 -4
  282. package/dist/workflow-context.d.ts.map +0 -1
  283. package/dist/workflow-context.js +0 -11
  284. package/dist/workflow-context.js.map +0 -1
  285. package/dist/workflow-outputs.d.ts +0 -9
  286. package/dist/workflow-outputs.d.ts.map +0 -1
  287. package/dist/workflow-outputs.js +0 -60
  288. package/dist/workflow-outputs.js.map +0 -1
  289. /package/dist/{executors → scheduler}/types.js +0 -0
@@ -0,0 +1,756 @@
1
+ import { assertWorkflowData } from "../evaluation/admissible.js";
2
+ import { evaluateExpr, renderTemplate } from "../evaluation/evaluator.js";
3
+ import { evaluateLoopMaxIterations } from "../evaluation/loop-limit.js";
4
+ import { appendBranch, appendFanoutItem, appendLoopIteration, appendNode, deriveInstanceKey } from "./identity.js";
5
+ import { baseScopeForFrame, completedScopeForFrame } from "./scope.js";
6
+ import { loopExhaustionResult, nextLoopStep } from "./transitions.js";
7
+ export function bootstrapRootEvents(runId, ir, scope = {}) {
8
+ const rootFrame = {
9
+ runId,
10
+ frameKey: "root",
11
+ frameKind: "root",
12
+ status: "running",
13
+ scope: scopeMapForScope([], ir.root),
14
+ };
15
+ return [
16
+ { type: "frame.started", payload: { runId, frameKey: "root", frameKind: "root", scope: rootFrame.scope } },
17
+ ...continueScopeFrameEvents({ frame: rootFrame, scopeIR: rootExecutionScope(ir), basePath: [], scope }, emptyProjection(runId)),
18
+ ];
19
+ }
20
+ export function continueRootEvents(ir, projection, scope = {}) {
21
+ for (const frame of runnableFrames(projection)) {
22
+ const events = continueFrameEvents(ir, projection, frame, scope);
23
+ if (events.length > 0)
24
+ return events;
25
+ }
26
+ return [];
27
+ }
28
+ function continueFrameEvents(ir, projection, frame, baseScope) {
29
+ if (isScopeFrame(frame)) {
30
+ const input = scopeFrame(ir, projection, frame, baseScope);
31
+ return input ? continueScopeFrameEvents(input, projection) : [];
32
+ }
33
+ if (frame.frameKind === "loop")
34
+ return continueLoopFrameEvents(ir, projection, frame, baseScope);
35
+ return continueNodeFrameEvents(ir, projection, frame, baseScope);
36
+ }
37
+ function continueScopeFrameEvents(input, projection) {
38
+ const cancelled = input.member?.status === "cancelled";
39
+ if (cancelled)
40
+ return [{ type: "frame.cancelled", payload: { frameKey: input.frame.frameKey, cancelReason: cancellationReason(input.member?.terminalReason ?? "parent_failed") } }];
41
+ let scope = input.scope;
42
+ for (let index = 0; index < input.scopeIR.nodes.length; index += 1) {
43
+ const node = input.scopeIR.nodes[index];
44
+ const nodePath = appendNode(input.basePath, node.id);
45
+ const state = nodeState(node, nodePath, projection);
46
+ if (state.status === "not_started")
47
+ return materializeNodeEvents({
48
+ runId: input.frame.runId,
49
+ node,
50
+ parentFrameKey: input.frame.frameKey,
51
+ basePath: input.basePath,
52
+ scope,
53
+ readinessSequence: nextFrameReadiness(input.member, index),
54
+ });
55
+ if (state.status === "failed")
56
+ return terminalScopeFrameEvents(input, "failed", state.error ?? { reason: "node_failed" }, state.reason ?? "node_failed");
57
+ if (state.status === "cancelled")
58
+ return terminalScopeFrameEvents(input, "cancelled", undefined, state.reason ?? "parent_failed");
59
+ if (state.status === "running")
60
+ return [];
61
+ scope = withNodeOutput(scope, node.id, state.output);
62
+ }
63
+ let result;
64
+ try {
65
+ result = evaluateOutputs(input.scopeIR.outputs ?? {}, scope);
66
+ }
67
+ catch (error) {
68
+ return terminalScopeFrameEvents(input, "failed", expressionFailure(error), "expression_failed");
69
+ }
70
+ const events = [
71
+ { type: "frame.completed", payload: { frameKey: input.frame.frameKey, result, terminalReason: completionReason(input, projection) } },
72
+ ];
73
+ if (input.member && (input.member.status === "ready" || input.member.status === "running")) {
74
+ events.push({
75
+ type: "group.member_completed",
76
+ payload: {
77
+ memberKey: input.member.memberKey,
78
+ completionSequence: nextCompletionSequence(projection),
79
+ output: result,
80
+ },
81
+ });
82
+ }
83
+ return events;
84
+ }
85
+ function continueNodeFrameEvents(ir, projection, frame, baseScope) {
86
+ const node = nodeForFrame(ir, frame);
87
+ if (!node)
88
+ return [];
89
+ if (node.kind === "if" || node.kind === "switch")
90
+ return continueConditionalFrameEvents(node, projection, frame);
91
+ if (node.kind === "parallel" || node.kind === "fanout")
92
+ return continueGroupFrameEvents(node, projection, frame);
93
+ return [];
94
+ }
95
+ function continueConditionalFrameEvents(node, projection, frame) {
96
+ const branchId = projection.branchDecisions[frame.frameKey];
97
+ if (!branchId || !frame.instancePath)
98
+ return [];
99
+ const branchFrameKey = deriveInstanceKey(appendBranch(parentPath(frame.instancePath), node.id, branchId));
100
+ const branch = projection.frames[branchFrameKey];
101
+ if (!branch)
102
+ return [];
103
+ if (branch.status === "completed") {
104
+ return [{ type: "frame.completed", payload: { frameKey: frame.frameKey, ...(branch.result === undefined ? {} : { result: branch.result }), terminalReason: "branch_completed" } }];
105
+ }
106
+ if (branch.status === "failed") {
107
+ return [{ type: "frame.failed", payload: { frameKey: frame.frameKey, error: branch.error ?? { reason: "branch_failed" }, terminalReason: branch.terminalReason ?? "branch_failed" } }];
108
+ }
109
+ if (branch.status === "cancelled") {
110
+ return [{ type: "frame.cancelled", payload: { frameKey: frame.frameKey, cancelReason: cancellationReason(branch.terminalReason ?? "parent_failed") } }];
111
+ }
112
+ return [];
113
+ }
114
+ function continueGroupFrameEvents(node, projection, frame) {
115
+ const group = projection.groups[frame.frameKey];
116
+ if (!group)
117
+ return [];
118
+ if (group.status === "completed") {
119
+ try {
120
+ const result = groupResult(node, projection, frame.frameKey);
121
+ return [{ type: "frame.completed", payload: { frameKey: frame.frameKey, ...(result === undefined ? {} : { result }), terminalReason: "group_completed" } }];
122
+ }
123
+ catch (error) {
124
+ return [{ type: "frame.failed", payload: { frameKey: frame.frameKey, error: expressionFailure(error), terminalReason: "expression_failed" } }];
125
+ }
126
+ }
127
+ if (group.status === "failed") {
128
+ return [{ type: "frame.failed", payload: { frameKey: frame.frameKey, error: group.error ?? { reason: "group_failed" }, terminalReason: "group_failed" } }];
129
+ }
130
+ if (group.status === "cancelled") {
131
+ return [{ type: "frame.cancelled", payload: { frameKey: frame.frameKey, cancelReason: "parent_failed" } }];
132
+ }
133
+ return [];
134
+ }
135
+ function continueLoopFrameEvents(ir, projection, frame, baseScope) {
136
+ const loop = nodeForFrame(ir, frame);
137
+ if (!loop || loop.kind !== "loop" || !frame.instancePath)
138
+ return [];
139
+ const iter = frame.loop?.iter ?? 0;
140
+ const iterationKey = deriveInstanceKey(appendLoopIteration(parentPath(frame.instancePath), loop.id, iter));
141
+ const iteration = projection.frames[iterationKey];
142
+ if (!iteration || iteration.status === "running" || iteration.status === "ready" || iteration.status === "awaiting")
143
+ return [];
144
+ if (iteration.status === "failed") {
145
+ return [{ type: "frame.failed", payload: { frameKey: frame.frameKey, error: iteration.error ?? { reason: "iteration_failed" }, terminalReason: iteration.terminalReason ?? "iteration_failed" } }];
146
+ }
147
+ if (iteration.status === "cancelled") {
148
+ return [{ type: "frame.cancelled", payload: { frameKey: frame.frameKey, cancelReason: cancellationReason(iteration.terminalReason ?? "parent_failed") } }];
149
+ }
150
+ const previous = frame.loop?.previous;
151
+ const nodeScope = scopeForNodeFrame(projection, frame, baseScope);
152
+ const loopScope = {
153
+ ...nodeScope,
154
+ loop: {
155
+ ...nodeScope.loop,
156
+ [loop.id]: {
157
+ iter,
158
+ ...(previous === undefined ? {} : { previous }),
159
+ ...(iteration.result === undefined ? {} : { result: iteration.result }),
160
+ },
161
+ },
162
+ };
163
+ let stop;
164
+ try {
165
+ const value = evaluateExpr(loop.stopWhen, loopScope);
166
+ if (typeof value !== "boolean")
167
+ throw new Error(`Loop node '${loop.id}' condition must evaluate to boolean.`);
168
+ stop = value;
169
+ }
170
+ catch (error) {
171
+ return [{ type: "frame.failed", payload: { frameKey: frame.frameKey, error: expressionFailure(error), terminalReason: "expression_failed" } }];
172
+ }
173
+ let maxIterations;
174
+ try {
175
+ maxIterations = evaluateLoopMaxIterations(loop.maxIterations, nodeScope, loop.id);
176
+ }
177
+ catch (error) {
178
+ return [{ type: "frame.failed", payload: { frameKey: frame.frameKey, error: expressionFailure(error), terminalReason: "expression_failed" } }];
179
+ }
180
+ const step = nextLoopStep({
181
+ iter,
182
+ maxIterations,
183
+ stop,
184
+ ...(iteration.result === undefined ? {} : { result: iteration.result }),
185
+ ...(previous === undefined ? {} : { previous }),
186
+ ...(loop.onExhausted === undefined ? {} : { onExhausted: loop.onExhausted }),
187
+ });
188
+ const events = [
189
+ { type: "frame.loop_advanced", payload: { frameKey: frame.frameKey, iter, ...(previous === undefined ? {} : { previous }), ...(iteration.result === undefined ? {} : { result: iteration.result }) } },
190
+ ];
191
+ if (step.action === "complete") {
192
+ events.push({ type: "frame.completed", payload: { frameKey: frame.frameKey, result: step.output, terminalReason: step.terminalReason } });
193
+ return events;
194
+ }
195
+ if (step.action === "fail") {
196
+ events.push({ type: "frame.failed", payload: { frameKey: frame.frameKey, error: step.error, terminalReason: step.terminalReason } });
197
+ return events;
198
+ }
199
+ events.push({ type: "frame.loop_advanced", payload: { frameKey: frame.frameKey, iter: step.iter, ...(step.previous === undefined ? {} : { previous: step.previous }) } }, ...materializeLoopIterationEvents({
200
+ runId: frame.runId,
201
+ loop,
202
+ loopFrameKey: frame.frameKey,
203
+ basePath: parentPath(frame.instancePath),
204
+ iter: step.iter,
205
+ readinessSequence: step.iter + 1,
206
+ scope: loopScopeForIteration(nodeScope, loop.id, step.iter, step.previous),
207
+ }));
208
+ return events;
209
+ }
210
+ function materializeNodeEvents(input) {
211
+ if (isSchedulerLeaf(input.node)) {
212
+ const nodePath = appendNode(input.basePath, input.node.id);
213
+ return schedulerLeafEvents({
214
+ runId: input.runId,
215
+ node: input.node,
216
+ nodeKey: deriveInstanceKey(nodePath),
217
+ instancePath: nodePath,
218
+ parentFrameKey: input.parentFrameKey,
219
+ readinessSequence: input.readinessSequence,
220
+ });
221
+ }
222
+ if (input.node.kind === "assert")
223
+ return materializeAssertEvents({ runId: input.runId, node: input.node, parentFrameKey: input.parentFrameKey, basePath: input.basePath, scope: input.scope });
224
+ if (input.node.kind === "if" || input.node.kind === "switch")
225
+ return materializeConditionalEvents(input);
226
+ if (input.node.kind === "parallel")
227
+ return materializeParallelEvents(input);
228
+ if (input.node.kind === "fanout")
229
+ return materializeFanoutEvents(input);
230
+ if (input.node.kind === "loop")
231
+ return materializeLoopEvents(input);
232
+ return [];
233
+ }
234
+ function materializeAssertEvents(input) {
235
+ const nodePath = appendNode(input.basePath, input.node.id);
236
+ const nodeKey = deriveInstanceKey(nodePath);
237
+ const start = nodeFrameStarted(input.runId, input.node, nodePath, input.parentFrameKey, "node");
238
+ try {
239
+ const passed = evaluateExpr(input.node.condition, input.scope);
240
+ if (typeof passed !== "boolean")
241
+ throw new Error(`Assert node '${input.node.id}' condition must evaluate to boolean.`);
242
+ return passed
243
+ ? [start, { type: "frame.completed", payload: { frameKey: nodeKey, result: {}, terminalReason: "assert_passed" } }]
244
+ : [start, { type: "frame.failed", payload: { frameKey: nodeKey, error: { message: renderAssertFailure(input.node, input.scope) }, terminalReason: "assert_failed" } }];
245
+ }
246
+ catch (error) {
247
+ return [start, { type: "frame.failed", payload: { frameKey: nodeKey, error: expressionFailure(error), terminalReason: "expression_failed" } }];
248
+ }
249
+ }
250
+ function materializeConditionalEvents(input) {
251
+ const nodePath = appendNode(input.basePath, input.node.id);
252
+ const nodeKey = deriveInstanceKey(nodePath);
253
+ const start = nodeFrameStarted(input.runId, input.node, nodePath, input.parentFrameKey, "node");
254
+ let selected;
255
+ try {
256
+ selected = selectConditionalBranch(input.node, input.scope);
257
+ }
258
+ catch (error) {
259
+ return [start, { type: "frame.failed", payload: { frameKey: nodeKey, error: expressionFailure(error), terminalReason: "expression_failed" } }];
260
+ }
261
+ const branchPath = appendBranch(input.basePath, input.node.id, selected.branchId);
262
+ const branchFrameKey = deriveInstanceKey(branchPath);
263
+ return [
264
+ start,
265
+ { type: "branch.decided", payload: { frameKey: nodeKey, branchId: selected.branchId } },
266
+ {
267
+ type: "frame.started",
268
+ payload: {
269
+ runId: input.runId,
270
+ frameKey: branchFrameKey,
271
+ frameKind: "branch",
272
+ instancePath: branchPath,
273
+ parentFrameKey: nodeKey,
274
+ nodeId: input.node.id,
275
+ scope: scopeMapForScope(branchPath, selected.scope),
276
+ },
277
+ },
278
+ ...materializeScopeStart(input.runId, branchFrameKey, selected.scope, branchPath, input.scope, input.readinessSequence),
279
+ ];
280
+ }
281
+ function materializeParallelEvents(input) {
282
+ const nodePath = appendNode(input.basePath, input.node.id);
283
+ const nodeKey = deriveInstanceKey(nodePath);
284
+ const events = [
285
+ nodeFrameStarted(input.runId, input.node, nodePath, input.parentFrameKey, "node", input.node.strategy),
286
+ { type: "group.started", payload: { runId: input.runId, groupKey: nodeKey, nodeKey, nodeId: input.node.id, kind: "parallel", strategy: input.node.strategy } },
287
+ ];
288
+ let readinessSequence = input.readinessSequence;
289
+ for (const [branchId, branch] of Object.entries(input.node.branches)) {
290
+ const branchPath = appendBranch(input.basePath, input.node.id, branchId);
291
+ const branchFrameKey = deriveInstanceKey(branchPath);
292
+ events.push({
293
+ type: "frame.started",
294
+ payload: {
295
+ runId: input.runId,
296
+ frameKey: branchFrameKey,
297
+ frameKind: "branch",
298
+ instancePath: branchPath,
299
+ parentFrameKey: nodeKey,
300
+ nodeId: input.node.id,
301
+ strategy: input.node.strategy,
302
+ scope: scopeMapForScope(branchPath, branch.scope),
303
+ },
304
+ }, {
305
+ type: "group.member_ready",
306
+ payload: {
307
+ runId: input.runId,
308
+ groupKey: nodeKey,
309
+ memberKey: branchFrameKey,
310
+ memberKind: "branch",
311
+ branchId,
312
+ childFrameKey: branchFrameKey,
313
+ readinessSequence,
314
+ },
315
+ }, ...materializeScopeStart(input.runId, branchFrameKey, branch.scope, branchPath, input.scope, readinessSequence, branchFrameKey));
316
+ readinessSequence += 1;
317
+ }
318
+ return events;
319
+ }
320
+ function materializeFanoutEvents(input) {
321
+ const nodePath = appendNode(input.basePath, input.node.id);
322
+ const nodeKey = deriveInstanceKey(nodePath);
323
+ const start = nodeFrameStarted(input.runId, input.node, nodePath, input.parentFrameKey, "node", input.node.strategy);
324
+ try {
325
+ const items = evaluateExpr(input.node.over, input.scope);
326
+ if (!Array.isArray(items)) {
327
+ return [start, { type: "frame.failed", payload: { frameKey: nodeKey, error: { reason: "fanout_over_not_array" }, terminalReason: "fanout_over_not_array" } }];
328
+ }
329
+ const events = [
330
+ start,
331
+ input.node.strategy === "quorum"
332
+ ? { type: "group.started", payload: { runId: input.runId, groupKey: nodeKey, nodeKey, nodeId: input.node.id, kind: "fanout", strategy: "quorum", quorumCount: input.node.count } }
333
+ : { type: "group.started", payload: { runId: input.runId, groupKey: nodeKey, nodeKey, nodeId: input.node.id, kind: "fanout", strategy: "all" } },
334
+ ];
335
+ const seenItemKeys = new Set();
336
+ for (const [itemIndex, item] of items.entries()) {
337
+ const itemKey = fanoutItemKey(input.node, input.scope, item, itemIndex);
338
+ const normalizedItemKey = String(itemKey);
339
+ if (seenItemKeys.has(normalizedItemKey)) {
340
+ return [start, { type: "frame.failed", payload: { frameKey: nodeKey, error: { reason: "duplicate_fanout_key", itemKey: normalizedItemKey }, terminalReason: "duplicate_fanout_key" } }];
341
+ }
342
+ seenItemKeys.add(normalizedItemKey);
343
+ const itemPath = appendFanoutItem(input.basePath, input.node.id, itemKey, itemIndex);
344
+ const itemFrameKey = deriveInstanceKey(itemPath);
345
+ const itemScope = withFanout(input.scope, input.node.id, item, itemIndex);
346
+ events.push({
347
+ type: "frame.started",
348
+ payload: {
349
+ runId: input.runId,
350
+ frameKey: itemFrameKey,
351
+ frameKind: "fanout_item",
352
+ instancePath: itemPath,
353
+ parentFrameKey: nodeKey,
354
+ nodeId: input.node.id,
355
+ strategy: input.node.strategy,
356
+ scope: scopeMapForScope(itemPath, input.node.do),
357
+ },
358
+ }, {
359
+ type: "group.member_ready",
360
+ payload: {
361
+ runId: input.runId,
362
+ groupKey: nodeKey,
363
+ memberKey: itemFrameKey,
364
+ memberKind: "fanout_item",
365
+ itemKey,
366
+ itemIndex,
367
+ item: item,
368
+ childFrameKey: itemFrameKey,
369
+ readinessSequence: input.readinessSequence + itemIndex,
370
+ },
371
+ }, ...materializeScopeStart(input.runId, itemFrameKey, input.node.do, itemPath, itemScope, input.readinessSequence + itemIndex, itemFrameKey));
372
+ }
373
+ return events;
374
+ }
375
+ catch (error) {
376
+ return [start, { type: "frame.failed", payload: { frameKey: nodeKey, error: expressionFailure(error), terminalReason: "expression_failed" } }];
377
+ }
378
+ }
379
+ function materializeLoopEvents(input) {
380
+ const nodePath = appendNode(input.basePath, input.node.id);
381
+ const nodeKey = deriveInstanceKey(nodePath);
382
+ const start = nodeFrameStarted(input.runId, input.node, nodePath, input.parentFrameKey, "loop");
383
+ let initial;
384
+ let maxIterations;
385
+ let stop;
386
+ try {
387
+ maxIterations = evaluateLoopMaxIterations(input.node.maxIterations, input.scope, input.node.id);
388
+ initial = evaluateExpr(input.node.initial, input.scope);
389
+ const stopScope = {
390
+ ...input.scope,
391
+ loop: {
392
+ ...input.scope.loop,
393
+ [input.node.id]: { iter: 0, previous: initial, result: initial },
394
+ },
395
+ };
396
+ const value = evaluateExpr(input.node.stopWhen, stopScope);
397
+ if (typeof value !== "boolean")
398
+ throw new Error(`Loop node '${input.node.id}' condition must evaluate to boolean.`);
399
+ stop = value;
400
+ }
401
+ catch (error) {
402
+ return [start, { type: "frame.failed", payload: { frameKey: nodeKey, error: expressionFailure(error), terminalReason: "expression_failed" } }];
403
+ }
404
+ const seed = { type: "frame.loop_advanced", payload: { frameKey: nodeKey, iter: 0, previous: initial } };
405
+ if (stop)
406
+ return [start, seed, { type: "frame.completed", payload: { frameKey: nodeKey, result: initial, terminalReason: "stopped" } }];
407
+ if (maxIterations <= 0) {
408
+ const exhausted = loopExhaustionResult({
409
+ maxIterations,
410
+ ...(input.node.onExhausted === undefined ? {} : { onExhausted: input.node.onExhausted }),
411
+ lastResult: initial,
412
+ });
413
+ return exhausted.status === "completed"
414
+ ? [start, seed, { type: "frame.completed", payload: { frameKey: nodeKey, result: exhausted.output, terminalReason: exhausted.terminalReason } }]
415
+ : [start, seed, { type: "frame.failed", payload: { frameKey: nodeKey, error: exhausted.error, terminalReason: exhausted.terminalReason } }];
416
+ }
417
+ return [
418
+ start,
419
+ seed,
420
+ ...materializeLoopIterationEvents({
421
+ runId: input.runId,
422
+ loop: input.node,
423
+ loopFrameKey: nodeKey,
424
+ basePath: input.basePath,
425
+ iter: 0,
426
+ readinessSequence: input.readinessSequence,
427
+ scope: loopScopeForIteration(input.scope, input.node.id, 0, initial),
428
+ }),
429
+ ];
430
+ }
431
+ function materializeLoopIterationEvents(input) {
432
+ const iterationPath = appendLoopIteration(input.basePath, input.loop.id, input.iter);
433
+ const iterationFrameKey = deriveInstanceKey(iterationPath);
434
+ return [
435
+ {
436
+ type: "frame.started",
437
+ payload: {
438
+ runId: input.runId,
439
+ frameKey: iterationFrameKey,
440
+ frameKind: "loop_iteration",
441
+ instancePath: iterationPath,
442
+ parentFrameKey: input.loopFrameKey,
443
+ nodeId: input.loop.id,
444
+ scope: scopeMapForScope(iterationPath, input.loop.do),
445
+ },
446
+ },
447
+ ...materializeScopeStart(input.runId, iterationFrameKey, input.loop.do, iterationPath, input.scope, input.readinessSequence),
448
+ ];
449
+ }
450
+ function materializeScopeStart(runId, frameKey, scopeIR, basePath, scope, readinessSequence, memberKey) {
451
+ const first = scopeIR.nodes[0];
452
+ if (!first) {
453
+ let result;
454
+ try {
455
+ result = evaluateOutputs(scopeIR.outputs ?? {}, scope);
456
+ }
457
+ catch (error) {
458
+ return [
459
+ { type: "frame.failed", payload: { frameKey, error: expressionFailure(error), terminalReason: "expression_failed" } },
460
+ ...(memberKey === undefined
461
+ ? []
462
+ : [{ type: "group.member_failed", payload: { memberKey, error: expressionFailure(error), terminalReason: "expression_failed" } }]),
463
+ ];
464
+ }
465
+ return [
466
+ { type: "frame.completed", payload: { frameKey, result, terminalReason: "frame_completed" } },
467
+ ...(memberKey === undefined
468
+ ? []
469
+ : [{ type: "group.member_completed", payload: { memberKey, completionSequence: readinessSequence, output: result } }]),
470
+ ];
471
+ }
472
+ return materializeNodeEvents({ runId, node: first, parentFrameKey: frameKey, basePath, scope, readinessSequence });
473
+ }
474
+ function schedulerLeafEvents(input) {
475
+ const events = [{
476
+ type: "instance.ready",
477
+ payload: {
478
+ runId: input.runId,
479
+ nodeKey: input.nodeKey,
480
+ nodeId: input.node.id,
481
+ instancePath: input.instancePath,
482
+ parentFrameKey: input.parentFrameKey,
483
+ readinessSequence: input.readinessSequence,
484
+ },
485
+ }];
486
+ return events;
487
+ }
488
+ function nodeFrameStarted(runId, node, nodePath, parentFrameKey, frameKind, strategy) {
489
+ const nodeKey = deriveInstanceKey(nodePath);
490
+ return {
491
+ type: "frame.started",
492
+ payload: {
493
+ runId,
494
+ frameKey: nodeKey,
495
+ frameKind,
496
+ instancePath: nodePath,
497
+ parentFrameKey,
498
+ nodeKey,
499
+ nodeId: node.id,
500
+ ...(strategy === undefined ? {} : { strategy }),
501
+ },
502
+ };
503
+ }
504
+ function nodeState(node, nodePath, projection) {
505
+ const key = deriveInstanceKey(nodePath);
506
+ if (isSchedulerLeaf(node)) {
507
+ const instance = projection.instances[key];
508
+ if (!instance)
509
+ return { status: "not_started" };
510
+ if (instance.status === "completed")
511
+ return instance.output === undefined ? { status: "completed" } : { status: "completed", output: instance.output };
512
+ if (instance.status === "failed")
513
+ return { status: "failed", ...(instance.error === undefined ? {} : { error: instance.error }), ...(instance.statusReason === undefined ? {} : { reason: instance.statusReason }) };
514
+ if (instance.status === "cancelled")
515
+ return { status: "cancelled", ...(instance.statusReason === undefined ? {} : { reason: instance.statusReason }) };
516
+ return { status: "running" };
517
+ }
518
+ const frame = projection.frames[key];
519
+ if (!frame)
520
+ return { status: "not_started" };
521
+ if (frame.status === "completed")
522
+ return frame.result === undefined ? { status: "completed" } : { status: "completed", output: frame.result };
523
+ if (frame.status === "failed")
524
+ return { status: "failed", ...(frame.error === undefined ? {} : { error: frame.error }), ...(frame.terminalReason === undefined ? {} : { reason: frame.terminalReason }) };
525
+ if (frame.status === "cancelled")
526
+ return { status: "cancelled", ...(frame.terminalReason === undefined ? {} : { reason: frame.terminalReason }) };
527
+ return { status: "running" };
528
+ }
529
+ function scopeFrame(ir, projection, frame, baseScope) {
530
+ if (frame.frameKey === "root") {
531
+ return { frame, scopeIR: rootExecutionScope(ir), basePath: [], scope: baseScopeForFrame(projection, frame, baseScope) };
532
+ }
533
+ if (!frame.instancePath)
534
+ return undefined;
535
+ const scopeIR = scopeForPath(ir.root, frame.instancePath);
536
+ if (!scopeIR)
537
+ return undefined;
538
+ const member = projection.groupMembers[frame.frameKey];
539
+ return {
540
+ frame,
541
+ scopeIR,
542
+ basePath: frame.instancePath,
543
+ scope: baseScopeForFrame(projection, frame, baseScope),
544
+ ...(member === undefined ? {} : { member }),
545
+ };
546
+ }
547
+ function scopeForNodeFrame(projection, frame, baseScope) {
548
+ return frame.parentFrameKey ? completedScopeForFrame(projection, frame.parentFrameKey, baseScope) : baseScope;
549
+ }
550
+ function nodeForFrame(ir, frame) {
551
+ if (!frame.instancePath)
552
+ return undefined;
553
+ const segment = lastSegment(frame.instancePath);
554
+ if (segment?.kind !== "node")
555
+ return undefined;
556
+ return scopeForPath(ir.root, parentPath(frame.instancePath))?.nodes.find(node => node.id === segment.nodeId);
557
+ }
558
+ function scopeForPath(root, path) {
559
+ let scope = root;
560
+ for (const segment of path) {
561
+ if (!scope)
562
+ return undefined;
563
+ if (segment.kind === "node")
564
+ continue;
565
+ const found = scope.nodes.find(candidate => candidate.id === segment.nodeId);
566
+ if (!found)
567
+ return undefined;
568
+ if (segment.kind === "branch") {
569
+ if (found.kind === "parallel")
570
+ scope = found.branches[segment.branchId]?.scope;
571
+ else if (found.kind === "if" || found.kind === "switch")
572
+ scope = conditionalBranchById(found, segment.branchId)?.scope;
573
+ else
574
+ return undefined;
575
+ }
576
+ else if (segment.kind === "fanout") {
577
+ if (found.kind !== "fanout")
578
+ return undefined;
579
+ scope = found.do;
580
+ }
581
+ else {
582
+ if (found.kind !== "loop")
583
+ return undefined;
584
+ scope = found.do;
585
+ }
586
+ }
587
+ return scope;
588
+ }
589
+ function groupResult(node, projection, groupKey) {
590
+ const members = Object.values(projection.groupMembers).filter(member => member.groupKey === groupKey);
591
+ if (node.kind === "parallel" && node.strategy === "all") {
592
+ return Object.fromEntries(members.map(member => [member.branchId, requireObjectOutput(member.output, `Parallel branch '${member.branchId ?? member.memberKey}'`)]));
593
+ }
594
+ if (node.kind === "parallel" && node.strategy === "race") {
595
+ const winner = members.filter(member => member.status === "completed").sort(byCompletionSequence)[0];
596
+ return winner?.branchId ? { winner: winner.branchId, result: requireObjectOutput(winner.output, `Parallel branch '${winner.branchId}'`) } : undefined;
597
+ }
598
+ if (node.kind === "fanout" && node.strategy === "all") {
599
+ return members
600
+ .filter(member => member.memberKind === "fanout_item")
601
+ .sort((left, right) => left.itemIndex - right.itemIndex)
602
+ .map(member => member.output);
603
+ }
604
+ if (node.kind === "fanout") {
605
+ const completed = members
606
+ .filter(member => member.memberKind === "fanout_item" && member.status === "completed")
607
+ .sort(byCompletionSequence)
608
+ .map(member => member.output);
609
+ return completed.slice(0, node.count);
610
+ }
611
+ return undefined;
612
+ }
613
+ function terminalScopeFrameEvents(input, status, error, reason) {
614
+ const cancelReason = cancellationReason(reason);
615
+ const events = status === "failed"
616
+ ? [{ type: "frame.failed", payload: { frameKey: input.frame.frameKey, error: error ?? { reason }, terminalReason: reason } }]
617
+ : [{ type: "frame.cancelled", payload: { frameKey: input.frame.frameKey, cancelReason } }];
618
+ if (input.member && (input.member.status === "ready" || input.member.status === "running")) {
619
+ events.push(status === "failed"
620
+ ? { type: "group.member_failed", payload: { memberKey: input.member.memberKey, error: error ?? { reason }, terminalReason: reason } }
621
+ : { type: "group.member_cancelled", payload: { memberKey: input.member.memberKey, cancelReason } });
622
+ }
623
+ return events;
624
+ }
625
+ function runnableFrames(projection) {
626
+ return Object.values(projection.frames)
627
+ .filter(frame => frame.status === "running")
628
+ .sort((left, right) => frameDepth(right) - frameDepth(left) || framePriority(left) - framePriority(right) || left.frameKey.localeCompare(right.frameKey));
629
+ }
630
+ function frameDepth(frame) {
631
+ return frame.instancePath?.length ?? 0;
632
+ }
633
+ function framePriority(frame) {
634
+ if (frame.frameKind === "branch" || frame.frameKind === "fanout_item" || frame.frameKind === "loop_iteration")
635
+ return 0;
636
+ if (frame.frameKind === "node" || frame.frameKind === "loop")
637
+ return 1;
638
+ return 2;
639
+ }
640
+ function emptyProjection(runId) {
641
+ return { run: { runId, status: "pending", paused: false }, frames: {}, instances: {}, attempts: {}, groups: {}, groupMembers: {}, signalWaits: {}, branchDecisions: {} };
642
+ }
643
+ function rootExecutionScope(ir) {
644
+ return { nodes: ir.root.nodes, outputs: ir.outputs };
645
+ }
646
+ function isScopeFrame(frame) {
647
+ return frame.frameKind === "root" || frame.frameKind === "branch" || frame.frameKind === "fanout_item" || frame.frameKind === "loop_iteration";
648
+ }
649
+ function completionReason(input, projection) {
650
+ if (input.frame.frameKey === "root")
651
+ return "root_completed";
652
+ if (input.frame.frameKind === "branch") {
653
+ const parent = input.frame.parentFrameKey ? projection.frames[input.frame.parentFrameKey] : undefined;
654
+ const parentNode = parent?.nodeId;
655
+ if (parentNode) {
656
+ const segment = lastSegment(input.frame.instancePath);
657
+ if (segment?.kind === "branch" && segment.nodeId === parentNode && !input.member)
658
+ return "branch_completed";
659
+ }
660
+ }
661
+ return "frame_completed";
662
+ }
663
+ function nextFrameReadiness(member, index) {
664
+ return (member?.readinessSequence ?? 0) + index + 1;
665
+ }
666
+ function nextCompletionSequence(projection) {
667
+ return Math.max(0, ...Object.values(projection.groupMembers).map(member => member.completionSequence ?? 0)) + 1;
668
+ }
669
+ function selectConditionalBranch(node, scope) {
670
+ if (node.kind === "if") {
671
+ const condition = evaluateExpr(node.condition, scope);
672
+ if (typeof condition !== "boolean")
673
+ throw new Error(`If node '${node.id}' condition must evaluate to boolean.`);
674
+ return condition ? { branchId: "then", scope: node.then } : { branchId: "else", scope: node.else ?? emptyScope() };
675
+ }
676
+ const selected = node.cases.findIndex(c => {
677
+ const condition = evaluateExpr(c.when, scope);
678
+ if (typeof condition !== "boolean")
679
+ throw new Error(`Switch node '${node.id}' case condition must evaluate to boolean.`);
680
+ return condition;
681
+ });
682
+ return selected >= 0
683
+ ? { branchId: `case:${selected}`, scope: node.cases[selected].then }
684
+ : { branchId: "default", scope: node.default ?? emptyScope() };
685
+ }
686
+ function conditionalBranchById(node, branchId) {
687
+ if (node.kind === "if") {
688
+ if (branchId === "then")
689
+ return { branchId, scope: node.then };
690
+ if (branchId === "else")
691
+ return { branchId, scope: node.else ?? emptyScope() };
692
+ return undefined;
693
+ }
694
+ if (branchId === "default")
695
+ return { branchId, scope: node.default ?? emptyScope() };
696
+ const match = /^case:(\d+)$/.exec(branchId);
697
+ if (!match)
698
+ return undefined;
699
+ const index = Number(match[1]);
700
+ const found = node.cases[index];
701
+ return found ? { branchId, scope: found.then } : undefined;
702
+ }
703
+ function scopeMapForScope(basePath, scope) {
704
+ return Object.fromEntries(scope.nodes.map(node => [node.id, deriveInstanceKey(appendNode(basePath, node.id))]));
705
+ }
706
+ function fanoutItemKey(node, scope, item, itemIndex) {
707
+ if (!node.key)
708
+ return itemIndex;
709
+ return renderTemplate(node.key, withFanout(scope, node.id, item, itemIndex));
710
+ }
711
+ function withNodeOutput(scope, nodeId, output) {
712
+ return { ...scope, nodes: { ...scope.nodes, [nodeId]: { status: "completed", output } } };
713
+ }
714
+ function withFanout(scope, nodeId, item, itemIndex) {
715
+ return { ...scope, fanout: { ...scope.fanout, [nodeId]: { item, itemIndex } } };
716
+ }
717
+ function loopScopeForIteration(scope, nodeId, iter, previous) {
718
+ return { ...scope, loop: { ...scope.loop, [nodeId]: { iter, ...(previous === undefined ? {} : { previous }) } } };
719
+ }
720
+ function evaluateOutputs(outputs, scope) {
721
+ const result = Object.fromEntries(Object.entries(outputs).map(([key, expr]) => [key, evaluateExpr(expr, scope)]));
722
+ assertWorkflowData(result, "Scope output");
723
+ return result;
724
+ }
725
+ function renderAssertFailure(node, scope) {
726
+ return node.message ? renderTemplate(node.message, scope) : `Assert node '${node.id}' failed.`;
727
+ }
728
+ function requireObjectOutput(value, label) {
729
+ if (!value || typeof value !== "object" || Array.isArray(value))
730
+ throw new Error(`${label} output is not an object.`);
731
+ return value;
732
+ }
733
+ function expressionFailure(error) {
734
+ return { reason: "expression_failed", message: error instanceof Error ? error.message : String(error) };
735
+ }
736
+ function byCompletionSequence(left, right) {
737
+ return (left.completionSequence ?? Number.MAX_SAFE_INTEGER) - (right.completionSequence ?? Number.MAX_SAFE_INTEGER);
738
+ }
739
+ function cancellationReason(reason) {
740
+ return reason === "race_lost" || reason === "quorum_reached" || reason === "paused" || reason === "superseded" || reason === "operator_cancelled"
741
+ ? reason
742
+ : "parent_failed";
743
+ }
744
+ function parentPath(path) {
745
+ return path.slice(0, -1);
746
+ }
747
+ function lastSegment(path) {
748
+ return path?.[path.length - 1];
749
+ }
750
+ function emptyScope() {
751
+ return { nodes: [], outputs: {} };
752
+ }
753
+ function isSchedulerLeaf(node) {
754
+ return node.kind === "task" || node.kind === "agent" || node.kind === "signal";
755
+ }
756
+ //# sourceMappingURL=materialize.js.map