@osolmaz/pi-workflows 0.16.1 → 0.16.3

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 (327) hide show
  1. package/README.md +41 -41
  2. package/dist/builtins/monitor.workflow.d.ts +1 -1
  3. package/dist/builtins/monitor.workflow.js +8 -8
  4. package/dist/builtins/pi-agent-group.js +3 -3
  5. package/dist/builtins/pi-agent-group.js.map +1 -1
  6. package/dist/channels/adapter-entry.js +14 -14
  7. package/dist/channels/adapter-entry.js.map +1 -1
  8. package/dist/client/client.d.ts +6 -6
  9. package/dist/client/client.js +27 -27
  10. package/dist/client/client.js.map +1 -1
  11. package/dist/client/protocol.d.ts +4 -1
  12. package/dist/client/protocol.js +17 -11
  13. package/dist/client/protocol.js.map +1 -1
  14. package/dist/client/resolver.d.ts +4 -4
  15. package/dist/client/view.d.ts +7 -1
  16. package/dist/client/view.js +1 -0
  17. package/dist/client/view.js.map +1 -1
  18. package/dist/extension/index.d.ts +1 -1
  19. package/dist/extension/index.js +66 -47
  20. package/dist/extension/index.js.map +1 -1
  21. package/dist/extension/recorder.d.ts +1 -1
  22. package/dist/extension/recorder.js +1 -1
  23. package/dist/extension/recorder.js.map +1 -1
  24. package/dist/extension/remote-recorder-store.d.ts +1 -1
  25. package/dist/extension/remote-recorder-store.js +2 -2
  26. package/dist/extension/remote-recorder-store.js.map +1 -1
  27. package/dist/extension/{controller-command.d.ts → resource-manager-command.d.ts} +6 -6
  28. package/dist/extension/{controller-command.js → resource-manager-command.js} +7 -7
  29. package/dist/extension/resource-manager-command.js.map +1 -0
  30. package/dist/extension/session-delivery.d.ts +1 -1
  31. package/dist/extension/session-delivery.js +2 -2
  32. package/dist/extension/session-delivery.js.map +1 -1
  33. package/dist/extension/session-view.d.ts +1 -1
  34. package/dist/extension/session-view.js +1 -1
  35. package/dist/extension/session-view.js.map +1 -1
  36. package/dist/extension/workflow-message-coordinator.d.ts +4 -3
  37. package/dist/extension/workflow-message-coordinator.js +81 -29
  38. package/dist/extension/workflow-message-coordinator.js.map +1 -1
  39. package/dist/resource-managers/conditions.d.ts +6 -0
  40. package/dist/{controllers → resource-managers}/conditions.js +3 -3
  41. package/dist/resource-managers/conditions.js.map +1 -0
  42. package/dist/resource-managers/definition.d.ts +6 -0
  43. package/dist/resource-managers/definition.js +45 -0
  44. package/dist/resource-managers/definition.js.map +1 -0
  45. package/dist/resource-managers/effects.d.ts +15 -0
  46. package/dist/{controllers → resource-managers}/effects.js +2 -2
  47. package/dist/resource-managers/effects.js.map +1 -0
  48. package/dist/resource-managers/errors.d.ts +12 -0
  49. package/dist/resource-managers/errors.js +25 -0
  50. package/dist/resource-managers/errors.js.map +1 -0
  51. package/dist/resource-managers/index.d.ts +12 -0
  52. package/dist/resource-managers/index.js +12 -0
  53. package/dist/resource-managers/index.js.map +1 -0
  54. package/dist/resource-managers/json.js.map +1 -0
  55. package/dist/resource-managers/loader.d.ts +23 -0
  56. package/dist/resource-managers/loader.js +75 -0
  57. package/dist/resource-managers/loader.js.map +1 -0
  58. package/dist/resource-managers/results.d.ts +5 -0
  59. package/dist/resource-managers/results.js.map +1 -0
  60. package/dist/resource-managers/runtime.d.ts +59 -0
  61. package/dist/{controllers/manager.js → resource-managers/runtime.js} +57 -57
  62. package/dist/resource-managers/runtime.js.map +1 -0
  63. package/dist/{controllers → resource-managers}/sqlite.d.ts +51 -43
  64. package/dist/{controllers → resource-managers}/sqlite.js +187 -125
  65. package/dist/resource-managers/sqlite.js.map +1 -0
  66. package/dist/{controllers → resource-managers}/store.d.ts +33 -33
  67. package/dist/{controllers → resource-managers}/store.js.map +1 -1
  68. package/dist/{controllers → resource-managers}/types.d.ts +41 -41
  69. package/dist/{controllers → resource-managers}/types.js.map +1 -1
  70. package/dist/resource-managers/workflows.d.ts +34 -0
  71. package/dist/{controllers → resource-managers}/workflows.js +15 -15
  72. package/dist/resource-managers/workflows.js.map +1 -0
  73. package/dist/server/channel-effects.js.map +1 -0
  74. package/dist/{host → server}/channel-supervisor.d.ts +6 -6
  75. package/dist/{host → server}/channel-supervisor.js +3 -3
  76. package/dist/server/channel-supervisor.js.map +1 -0
  77. package/dist/{host/child-worker-supervisor.d.ts → server/child-runner-supervisor.d.ts} +15 -13
  78. package/dist/{host/child-worker-supervisor.js → server/child-runner-supervisor.js} +6 -5
  79. package/dist/server/child-runner-supervisor.js.map +1 -0
  80. package/dist/{host → server}/processes.d.ts +3 -3
  81. package/dist/{host → server}/processes.js +3 -3
  82. package/dist/server/processes.js.map +1 -0
  83. package/dist/{host → server}/resolver-entry.d.ts +6 -6
  84. package/dist/{host → server}/resolver-entry.js +14 -14
  85. package/dist/server/resolver-entry.js.map +1 -0
  86. package/dist/server/resource-runner-entry.d.ts +2 -0
  87. package/dist/{host/controller-worker-entry.js → server/resource-runner-entry.js} +33 -33
  88. package/dist/server/resource-runner-entry.js.map +1 -0
  89. package/dist/server/resource-runner-protocol.d.ts +36 -0
  90. package/dist/server/resource-runner-protocol.js +49 -0
  91. package/dist/server/resource-runner-protocol.js.map +1 -0
  92. package/dist/server/resource-runner-supervisor.d.ts +21 -0
  93. package/dist/{host/worker-supervisor.js → server/resource-runner-supervisor.js} +17 -17
  94. package/dist/server/resource-runner-supervisor.js.map +1 -0
  95. package/dist/{host → server}/rpc-bridge.d.ts +3 -3
  96. package/dist/{host → server}/rpc-bridge.js +3 -3
  97. package/dist/server/rpc-bridge.js.map +1 -0
  98. package/dist/{host → server}/rpc-executor.d.ts +1 -1
  99. package/dist/{host → server}/rpc-executor.js +3 -3
  100. package/dist/server/rpc-executor.js.map +1 -0
  101. package/dist/{host/host-entry.js → server/server-entry.js} +6 -6
  102. package/dist/server/server-entry.js.map +1 -0
  103. package/dist/{host/runner.d.ts → server/server.d.ts} +47 -39
  104. package/dist/{host/runner.js → server/server.js} +624 -535
  105. package/dist/server/server.js.map +1 -0
  106. package/dist/{host → server}/state.d.ts +25 -25
  107. package/dist/{host → server}/state.js +49 -49
  108. package/dist/server/state.js.map +1 -0
  109. package/dist/{host → server}/view.d.ts +7 -7
  110. package/dist/{host → server}/view.js +19 -15
  111. package/dist/server/view.js.map +1 -0
  112. package/dist/server/workflow-runner-content.d.ts +6 -0
  113. package/dist/server/workflow-runner-content.js +96 -0
  114. package/dist/server/workflow-runner-content.js.map +1 -0
  115. package/dist/server/workflow-runner-entry.d.ts +13 -0
  116. package/dist/{host/worker-entry.js → server/workflow-runner-entry.js} +89 -57
  117. package/dist/server/workflow-runner-entry.js.map +1 -0
  118. package/dist/server/workflow-runner-protocol.d.ts +69 -0
  119. package/dist/server/workflow-runner-protocol.js +176 -0
  120. package/dist/server/workflow-runner-protocol.js.map +1 -0
  121. package/dist/{host/worker-store.d.ts → server/workflow-runner-store.d.ts} +11 -11
  122. package/dist/{host/worker-store.js → server/workflow-runner-store.js} +8 -8
  123. package/dist/server/workflow-runner-store.js.map +1 -0
  124. package/dist/server/workflow-runner-supervisor.d.ts +22 -0
  125. package/dist/server/workflow-runner-supervisor.js +56 -0
  126. package/dist/server/workflow-runner-supervisor.js.map +1 -0
  127. package/dist/state/prune.d.ts +1 -1
  128. package/dist/state/prune.js +17 -10
  129. package/dist/state/prune.js.map +1 -1
  130. package/dist/state/schema.js +2 -2
  131. package/dist/state/workflow-messages.d.ts +3 -1
  132. package/dist/state/workflow-messages.js +32 -1
  133. package/dist/state/workflow-messages.js.map +1 -1
  134. package/dist/viewer/backup.js +1 -1
  135. package/dist/viewer/backup.js.map +1 -1
  136. package/dist/viewer/cli.d.ts +2 -2
  137. package/dist/viewer/cli.js +46 -32
  138. package/dist/viewer/cli.js.map +1 -1
  139. package/dist/viewer/tui.d.ts +1 -1
  140. package/dist/viewer/tui.js +1 -1
  141. package/dist/viewer/tui.js.map +1 -1
  142. package/dist/workflows/command-batch.js +2 -2
  143. package/dist/workflows/composition.js +0 -4
  144. package/dist/workflows/composition.js.map +1 -1
  145. package/dist/workflows/definition.js +0 -8
  146. package/dist/workflows/definition.js.map +1 -1
  147. package/dist/workflows/engine.js +18 -20
  148. package/dist/workflows/engine.js.map +1 -1
  149. package/dist/workflows/schema.js +0 -4
  150. package/dist/workflows/schema.js.map +1 -1
  151. package/dist/workflows/store.d.ts +27 -11
  152. package/dist/workflows/store.js +66 -18
  153. package/dist/workflows/store.js.map +1 -1
  154. package/dist/workflows/types.d.ts +3 -5
  155. package/docs/2026-08-20-durable-workflow-launch-plan.md +12 -12
  156. package/docs/2026-08-25-workflow-follow-ups.md +7 -7
  157. package/docs/2026-08-25-workflow-settings.md +3 -3
  158. package/docs/2026-08-30-out-of-process-workflow-host-plan.md +3 -3
  159. package/docs/2026-09-01-restore-session-delivery-controls-plan.md +5 -5
  160. package/docs/2026-09-01-unified-workflow-client-plan.md +6 -6
  161. package/docs/2026-09-02-installed-live-e2e-plan.md +3 -3
  162. package/docs/2026-09-02-unify-workflow-messages-plan.md +8 -8
  163. package/docs/2026-09-04-workflow-run-state-plan.md +363 -0
  164. package/docs/DEFERRED_TURNS.md +7 -7
  165. package/docs/DESIGN_PHILOSOPHY.md +1 -1
  166. package/docs/HUMAN_DECISIONS.md +11 -11
  167. package/docs/HUMAN_DECISION_PRESENTATIONS.md +4 -4
  168. package/docs/MONITOR.md +1 -1
  169. package/docs/RESOURCE_MANAGERS.md +221 -0
  170. package/docs/SQLITE_STATE.md +40 -34
  171. package/docs/WORKFLOW_COMPOSITION.md +1 -1
  172. package/docs/{WORKFLOW_HOST.md → WORKFLOW_SERVER.md} +131 -116
  173. package/docs/WORKFLOW_STEP_MESSAGES.md +18 -18
  174. package/docs/WORKFLOW_UPDATES.md +16 -16
  175. package/docs/development.md +15 -14
  176. package/docs/live-replay-protocol.md +20 -20
  177. package/docs/plans/2026-08-04-controller-runtime-plan.md +25 -25
  178. package/docs/plans/2026-08-05-always-on-workflows-plan.md +8 -8
  179. package/docs/plans/2026-08-10-agent-managed-monitor-workflows-plan.md +2 -2
  180. package/docs/plans/2026-08-13-session-addressed-workflow-notifications-plan.md +1 -1
  181. package/docs/plans/2026-08-16-workflow-updates-plan.md +5 -5
  182. package/docs/plans/2026-08-19-human-decision-gates-plan.md +1 -1
  183. package/docs/plans/2026-08-20-bounded-command-batches-plan.md +1 -1
  184. package/docs/plans/2026-08-21-deferred-turn-intents-plan.md +3 -3
  185. package/docs/plans/2026-08-21-sanity-check-plan.md +2 -2
  186. package/docs/plans/2026-08-23-assistant-agent-completion-plan.md +5 -5
  187. package/docs/plans/2026-08-23-sqlite-state-plan.md +25 -25
  188. package/docs/plans/2026-08-25-live-workflow-settings-plan.md +4 -4
  189. package/docs/plans/2026-08-27-workflow-terminal-restart-plan.md +3 -3
  190. package/docs/plans/2026-09-04-workflow-runner-resume-state-plan.md +318 -0
  191. package/docs/plans/piw-viewer-experience-implementation-plan.md +1 -1
  192. package/docs/tui-viewer.md +9 -9
  193. package/docs/workflows.md +78 -63
  194. package/examples/{controllers/pull-request.controller.ts → resource-managers/pull-request.resource-manager.ts} +12 -12
  195. package/herdr-plugin.toml +1 -1
  196. package/package.json +5 -5
  197. package/protocol/client.v1.schema.json +7 -7
  198. package/protocol/fixtures/client-v1.json +1 -1
  199. package/src/builtins/monitor.workflow.ts +9 -9
  200. package/src/builtins/pi-agent-group.ts +3 -3
  201. package/src/channels/adapter-entry.ts +14 -14
  202. package/src/client/client.ts +33 -32
  203. package/src/client/protocol.ts +16 -11
  204. package/src/client/resolver.ts +4 -4
  205. package/src/client/view.ts +9 -1
  206. package/src/extension/index.ts +81 -53
  207. package/src/extension/recorder.ts +1 -1
  208. package/src/extension/remote-recorder-store.ts +2 -2
  209. package/src/extension/resource-manager-command.ts +45 -0
  210. package/src/extension/session-delivery.ts +2 -2
  211. package/src/extension/session-view.ts +1 -1
  212. package/src/extension/workflow-message-coordinator.ts +94 -30
  213. package/src/{controllers → resource-managers}/conditions.ts +23 -23
  214. package/src/resource-managers/definition.ts +71 -0
  215. package/src/{controllers → resource-managers}/effects.ts +9 -9
  216. package/src/resource-managers/errors.ts +27 -0
  217. package/src/resource-managers/index.ts +88 -0
  218. package/src/resource-managers/loader.ts +111 -0
  219. package/src/{controllers → resource-managers}/results.ts +4 -4
  220. package/src/{controllers/manager.ts → resource-managers/runtime.ts} +95 -92
  221. package/src/{controllers → resource-managers}/sqlite.ts +275 -181
  222. package/src/{controllers → resource-managers}/store.ts +46 -38
  223. package/src/{controllers → resource-managers}/types.ts +50 -41
  224. package/src/{controllers → resource-managers}/workflows.ts +43 -41
  225. package/src/{host → server}/channel-supervisor.ts +8 -8
  226. package/src/{host/child-worker-supervisor.ts → server/child-runner-supervisor.ts} +22 -18
  227. package/src/{host → server}/processes.ts +3 -3
  228. package/src/{host → server}/resolver-entry.ts +28 -25
  229. package/src/{host/controller-worker-entry.ts → server/resource-runner-entry.ts} +67 -65
  230. package/src/server/resource-runner-protocol.ts +103 -0
  231. package/src/server/resource-runner-supervisor.ts +76 -0
  232. package/src/{host → server}/rpc-bridge.ts +3 -3
  233. package/src/{host → server}/rpc-executor.ts +4 -4
  234. package/src/{host/host-entry.ts → server/server-entry.ts} +5 -5
  235. package/src/{host/runner.ts → server/server.ts} +786 -672
  236. package/src/{host → server}/state.ts +78 -67
  237. package/src/{host → server}/view.ts +21 -17
  238. package/src/server/workflow-runner-content.ts +119 -0
  239. package/src/{host/worker-entry.ts → server/workflow-runner-entry.ts} +131 -82
  240. package/src/server/workflow-runner-protocol.ts +241 -0
  241. package/src/{host/worker-store.ts → server/workflow-runner-store.ts} +18 -20
  242. package/src/server/workflow-runner-supervisor.ts +79 -0
  243. package/src/state/prune.ts +27 -9
  244. package/src/state/schema.ts +2 -2
  245. package/src/state/workflow-messages.ts +52 -1
  246. package/src/viewer/backup.ts +1 -1
  247. package/src/viewer/cli.ts +50 -36
  248. package/src/viewer/tui.ts +1 -1
  249. package/src/workflows/command-batch.ts +2 -2
  250. package/src/workflows/composition.ts +0 -5
  251. package/src/workflows/definition.ts +0 -8
  252. package/src/workflows/engine.ts +18 -21
  253. package/src/workflows/schema.ts +0 -6
  254. package/src/workflows/store.ts +95 -28
  255. package/src/workflows/types.ts +3 -5
  256. package/dist/controllers/conditions.d.ts +0 -6
  257. package/dist/controllers/conditions.js.map +0 -1
  258. package/dist/controllers/definition.d.ts +0 -6
  259. package/dist/controllers/definition.js +0 -45
  260. package/dist/controllers/definition.js.map +0 -1
  261. package/dist/controllers/effects.d.ts +0 -15
  262. package/dist/controllers/effects.js.map +0 -1
  263. package/dist/controllers/errors.d.ts +0 -12
  264. package/dist/controllers/errors.js +0 -25
  265. package/dist/controllers/errors.js.map +0 -1
  266. package/dist/controllers/index.d.ts +0 -12
  267. package/dist/controllers/index.js +0 -12
  268. package/dist/controllers/index.js.map +0 -1
  269. package/dist/controllers/json.js.map +0 -1
  270. package/dist/controllers/loader.d.ts +0 -23
  271. package/dist/controllers/loader.js +0 -74
  272. package/dist/controllers/loader.js.map +0 -1
  273. package/dist/controllers/manager.d.ts +0 -59
  274. package/dist/controllers/manager.js.map +0 -1
  275. package/dist/controllers/results.d.ts +0 -5
  276. package/dist/controllers/results.js.map +0 -1
  277. package/dist/controllers/sqlite.js.map +0 -1
  278. package/dist/controllers/workflows.d.ts +0 -34
  279. package/dist/controllers/workflows.js.map +0 -1
  280. package/dist/extension/controller-command.js.map +0 -1
  281. package/dist/host/channel-effects.js.map +0 -1
  282. package/dist/host/channel-supervisor.js.map +0 -1
  283. package/dist/host/child-worker-supervisor.js.map +0 -1
  284. package/dist/host/controller-worker-entry.d.ts +0 -2
  285. package/dist/host/controller-worker-entry.js.map +0 -1
  286. package/dist/host/controller-worker-protocol.d.ts +0 -36
  287. package/dist/host/controller-worker-protocol.js +0 -49
  288. package/dist/host/controller-worker-protocol.js.map +0 -1
  289. package/dist/host/controller-worker-supervisor.d.ts +0 -21
  290. package/dist/host/controller-worker-supervisor.js +0 -54
  291. package/dist/host/controller-worker-supervisor.js.map +0 -1
  292. package/dist/host/host-entry.js.map +0 -1
  293. package/dist/host/processes.js.map +0 -1
  294. package/dist/host/resolver-entry.js.map +0 -1
  295. package/dist/host/rpc-bridge.js.map +0 -1
  296. package/dist/host/rpc-executor.js.map +0 -1
  297. package/dist/host/runner.js.map +0 -1
  298. package/dist/host/state.js.map +0 -1
  299. package/dist/host/view.js.map +0 -1
  300. package/dist/host/worker-entry.d.ts +0 -10
  301. package/dist/host/worker-entry.js.map +0 -1
  302. package/dist/host/worker-protocol.d.ts +0 -31
  303. package/dist/host/worker-protocol.js +0 -122
  304. package/dist/host/worker-protocol.js.map +0 -1
  305. package/dist/host/worker-store.js.map +0 -1
  306. package/dist/host/worker-supervisor.d.ts +0 -22
  307. package/dist/host/worker-supervisor.js.map +0 -1
  308. package/docs/CONTROLLERS.md +0 -217
  309. package/src/controllers/definition.ts +0 -65
  310. package/src/controllers/errors.ts +0 -27
  311. package/src/controllers/index.ts +0 -88
  312. package/src/controllers/loader.ts +0 -104
  313. package/src/extension/controller-command.ts +0 -45
  314. package/src/host/controller-worker-protocol.ts +0 -104
  315. package/src/host/controller-worker-supervisor.ts +0 -79
  316. package/src/host/worker-protocol.ts +0 -165
  317. package/src/host/worker-supervisor.ts +0 -74
  318. /package/dist/{controllers → resource-managers}/json.d.ts +0 -0
  319. /package/dist/{controllers → resource-managers}/json.js +0 -0
  320. /package/dist/{controllers → resource-managers}/results.js +0 -0
  321. /package/dist/{controllers → resource-managers}/store.js +0 -0
  322. /package/dist/{controllers → resource-managers}/types.js +0 -0
  323. /package/dist/{host → server}/channel-effects.d.ts +0 -0
  324. /package/dist/{host → server}/channel-effects.js +0 -0
  325. /package/dist/{host/host-entry.d.ts → server/server-entry.d.ts} +0 -0
  326. /package/src/{controllers → resource-managers}/json.ts +0 -0
  327. /package/src/{host → server}/channel-effects.ts +0 -0
@@ -5,14 +5,15 @@ import { StateDatabase, workflowStatePath } from "../state/database.js";
5
5
  import { canonicalJson } from "../state/json.js";
6
6
  import { resourceIdFor, tokenHash } from "../state/mutation.js";
7
7
  import { initializeViewerRun, recordViewerDeltas } from "../state/viewer.js";
8
+ import { WorkflowMessageStore } from "../state/workflow-messages.js";
8
9
  import {
9
10
  EffectRequestConflictError,
10
- ResourceConflictError,
11
- ResourceNotFoundError,
11
+ ManagedResourceConflictError,
12
+ ManagedResourceNotFoundError,
12
13
  WorkflowRequestConflictError,
13
14
  } from "./errors.js";
14
15
  import type {
15
- ControllerStore,
16
+ ResourceManagerStore,
16
17
  EffectReservation,
17
18
  QueueItem,
18
19
  QueueRequeueOptions,
@@ -21,11 +22,11 @@ import type {
21
22
  } from "./store.js";
22
23
  import type {
23
24
  ChildWorkflowRecord,
24
- ControllerEvent,
25
- ControllerQueueClaim,
26
- ControllerResource,
27
- ControllerResourceRef,
28
- ControllerResourceStatus,
25
+ ResourceManagerEvent,
26
+ ResourceManagerQueueClaim,
27
+ ManagedResource,
28
+ ManagedResourceRef,
29
+ ManagedResourceStatus,
29
30
  EffectRecord,
30
31
  JsonObject,
31
32
  } from "./types.js";
@@ -138,11 +139,11 @@ export type RunEventRecord = {
138
139
  payload: JsonObject;
139
140
  };
140
141
 
141
- type ControllerRow = {
142
- controllerResourceId: string;
142
+ type ResourceManagerRow = {
143
+ managedResourceId: string;
143
144
  resourceId: string;
144
145
  resourceVersion: number;
145
- controllerName: string;
146
+ resourceManagerName: string;
146
147
  resourceKey: string;
147
148
  uid: string;
148
149
  generation: number;
@@ -267,9 +268,10 @@ type WorkflowRow = {
267
268
  errorHash: Buffer | null;
268
269
  };
269
270
 
270
- export class SqliteControllerStore implements ControllerStore {
271
+ export class SqliteResourceManagerStore implements ResourceManagerStore {
271
272
  readonly filePath: string;
272
273
  readonly state: StateDatabase;
274
+ private readonly workflowMessages: WorkflowMessageStore;
273
275
  private readonly ownsState: boolean;
274
276
  private readonly projectId: string | null;
275
277
  private closed = false;
@@ -280,7 +282,7 @@ export class SqliteControllerStore implements ControllerStore {
280
282
  readOnly?: boolean;
281
283
  projectPath?: string;
282
284
  state?: StateDatabase;
283
- /** Host-only global view. Project-scoped mutations still require projectPath. */
285
+ /** Server-only global view. Project-scoped mutations still require projectPath. */
284
286
  global?: boolean;
285
287
  } = {},
286
288
  ) {
@@ -293,6 +295,7 @@ export class SqliteControllerStore implements ControllerStore {
293
295
  checkLegacyState: filePath === workflowStatePath(),
294
296
  });
295
297
  this.filePath = this.state.filePath;
298
+ this.workflowMessages = new WorkflowMessageStore(this.state);
296
299
  if (options.global === true) {
297
300
  this.projectId = null;
298
301
  } else {
@@ -309,31 +312,34 @@ export class SqliteControllerStore implements ControllerStore {
309
312
  }
310
313
 
311
314
  putResource<TSpec, TStatus>(options: {
312
- controller: string;
315
+ resourceManager: string;
313
316
  key: string;
314
317
  spec: TSpec;
315
318
  initialStatus: TStatus;
316
319
  now?: string;
317
- }): ControllerResource<TSpec, TStatus> {
320
+ }): ManagedResource<TSpec, TStatus> {
318
321
  this.assertWritable();
319
- validateName(options.controller, "controller");
322
+ validateName(options.resourceManager, "resource manager");
320
323
  validateKey(options.key, "resource key");
321
324
  const now = epoch(validTimestamp(options.now));
322
325
  const specHash = this.state.putJson(options.spec, now);
323
- const initialStatus: ControllerResourceStatus<TStatus> = {
326
+ const initialStatus: ManagedResourceStatus<TStatus> = {
324
327
  observedGeneration: 0,
325
328
  conditions: [],
326
- controllerStatus: options.initialStatus,
329
+ resourceManagerStatus: options.initialStatus,
327
330
  };
328
331
  const statusHash = this.state.putJson(initialStatus, now);
329
332
  return this.state.transaction(() => {
330
- const existing = this.controllerRow({ controller: options.controller, key: options.key });
333
+ const existing = this.resourceManagerRow({
334
+ resourceManager: options.resourceManager,
335
+ key: options.key,
336
+ });
331
337
  if (existing === undefined) {
332
338
  const uid = randomUUID();
333
- const controllerResourceId = `controller-resource-${randomUUID()}`;
339
+ const managedResourceId = `controller-resource-${randomUUID()}`;
334
340
  const resourceId = resourceIdFor(
335
341
  "controller",
336
- `${this.requireProjectId()}:${options.controller}:${options.key}`,
342
+ `${this.requireProjectId()}:${options.resourceManager}:${options.key}`,
337
343
  );
338
344
  this.state.connection
339
345
  .prepare(
@@ -341,7 +347,7 @@ export class SqliteControllerStore implements ControllerStore {
341
347
  resource_id, resource_type, aggregate_key, revision, created_at, updated_at
342
348
  ) VALUES (?, 'controller', ?, 1, ?, ?)`,
343
349
  )
344
- .run(resourceId, controllerResourceId, now, now);
350
+ .run(resourceId, managedResourceId, now, now);
345
351
  this.state.connection
346
352
  .prepare("INSERT INTO leases(resource_id, generation) VALUES (?, 0)")
347
353
  .run(resourceId);
@@ -353,10 +359,10 @@ export class SqliteControllerStore implements ControllerStore {
353
359
  ) VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?)`,
354
360
  )
355
361
  .run(
356
- controllerResourceId,
362
+ managedResourceId,
357
363
  resourceId,
358
364
  this.requireProjectId(),
359
- options.controller,
365
+ options.resourceManager,
360
366
  options.key,
361
367
  uid,
362
368
  specHash,
@@ -364,7 +370,7 @@ export class SqliteControllerStore implements ControllerStore {
364
370
  now,
365
371
  now,
366
372
  );
367
- this.enqueueControllerRow(controllerResourceId, now, now);
373
+ this.enqueueResourceManagerRow(managedResourceId, now, now);
368
374
  this.insertEvent(
369
375
  resourceId,
370
376
  1,
@@ -382,9 +388,9 @@ export class SqliteControllerStore implements ControllerStore {
382
388
  SET spec_hash = ?, generation = generation + 1, updated_at = ?
383
389
  WHERE controller_resource_id = ?`,
384
390
  )
385
- .run(specHash, now, existing.controllerResourceId);
391
+ .run(specHash, now, existing.managedResourceId);
386
392
  this.bumpResource(existing.resourceId, existing.resourceVersion, now);
387
- this.enqueueControllerRow(existing.controllerResourceId, now, now);
393
+ this.enqueueResourceManagerRow(existing.managedResourceId, now, now);
388
394
  this.insertEvent(
389
395
  existing.resourceId,
390
396
  revision,
@@ -396,74 +402,74 @@ export class SqliteControllerStore implements ControllerStore {
396
402
  );
397
403
  }
398
404
  return this.requireResource({
399
- controller: options.controller,
405
+ resourceManager: options.resourceManager,
400
406
  key: options.key,
401
- }) as ControllerResource<TSpec, TStatus>;
407
+ }) as ManagedResource<TSpec, TStatus>;
402
408
  });
403
409
  }
404
410
 
405
411
  getResource<TSpec = unknown, TStatus = unknown>(
406
- ref: ControllerResourceRef,
407
- ): ControllerResource<TSpec, TStatus> | undefined {
408
- const row = this.controllerRow(ref);
412
+ ref: ManagedResourceRef,
413
+ ): ManagedResource<TSpec, TStatus> | undefined {
414
+ const row = this.resourceManagerRow(ref);
409
415
  return row === undefined
410
416
  ? undefined
411
- : (this.mapControllerResource(row) as ControllerResource<TSpec, TStatus>);
417
+ : (this.mapManagedResource(row) as ManagedResource<TSpec, TStatus>);
412
418
  }
413
419
 
414
- getResourceByUid(uid: string): ControllerResource | undefined {
415
- const row = this.state.connection.prepare(controllerSelect("WHERE c.uid = ?")).get(uid);
416
- return isControllerRow(row) ? this.mapControllerResource(row) : undefined;
420
+ getResourceByUid(uid: string): ManagedResource | undefined {
421
+ const row = this.state.connection.prepare(resourceManagerSelect("WHERE c.uid = ?")).get(uid);
422
+ return isResourceManagerRow(row) ? this.mapManagedResource(row) : undefined;
417
423
  }
418
424
 
419
425
  listResources<TSpec = unknown, TStatus = unknown>(
420
- options: { controller?: string } = {},
421
- ): ControllerResource<TSpec, TStatus>[] {
426
+ options: { resourceManager?: string } = {},
427
+ ): ManagedResource<TSpec, TStatus>[] {
422
428
  const clauses = ["1 = 1"];
423
429
  const params: unknown[] = [];
424
430
  if (this.projectId !== null) {
425
431
  clauses.push("c.project_id = ?");
426
432
  params.push(this.projectId);
427
433
  }
428
- if (options.controller !== undefined) {
434
+ if (options.resourceManager !== undefined) {
429
435
  clauses.push("c.controller_name = ?");
430
- params.push(options.controller);
436
+ params.push(options.resourceManager);
431
437
  }
432
438
  const rows = this.state.connection
433
439
  .prepare(
434
- controllerSelect(
440
+ resourceManagerSelect(
435
441
  `WHERE ${clauses.join(" AND ")} ORDER BY c.controller_name, c.resource_key`,
436
442
  ),
437
443
  )
438
444
  .all(...params);
439
445
  return rows
440
- .filter(isControllerRow)
441
- .map((row) => this.mapControllerResource(row) as ControllerResource<TSpec, TStatus>);
446
+ .filter(isResourceManagerRow)
447
+ .map((row) => this.mapManagedResource(row) as ManagedResource<TSpec, TStatus>);
442
448
  }
443
449
 
444
450
  updateStatus<TStatus>(options: {
445
- ref: ControllerResourceRef;
451
+ ref: ManagedResourceRef;
446
452
  expectedResourceVersion: number;
447
- claim: ControllerQueueClaim;
448
- status: ControllerResourceStatus<TStatus>;
453
+ claim: ResourceManagerQueueClaim;
454
+ status: ManagedResourceStatus<TStatus>;
449
455
  finalizers?: string[];
450
456
  now?: string;
451
- }): ControllerResource<unknown, TStatus> {
457
+ }): ManagedResource<unknown, TStatus> {
452
458
  const now = epoch(validTimestamp(options.now));
453
459
  return this.state.transaction(() => {
454
- const row = this.requireControllerRow(options.ref);
455
- this.assertControllerClaim(row, options.claim, now);
460
+ const row = this.requireResourceManagerRow(options.ref);
461
+ this.assertResourceManagerClaim(row, options.claim, now);
456
462
  if (row.resourceVersion !== options.expectedResourceVersion) {
457
- throw new ResourceConflictError(options.ref.controller, options.ref.key);
463
+ throw new ManagedResourceConflictError(options.ref.resourceManager, options.ref.key);
458
464
  }
459
465
  const statusHash = this.state.putJson(options.status, now);
460
466
  this.state.connection
461
467
  .prepare(
462
468
  "UPDATE controller_resources SET status_hash = ?, updated_at = ? WHERE controller_resource_id = ?",
463
469
  )
464
- .run(statusHash, now, row.controllerResourceId);
470
+ .run(statusHash, now, row.managedResourceId);
465
471
  if (options.finalizers !== undefined)
466
- this.replaceFinalizers(row.controllerResourceId, options.finalizers);
472
+ this.replaceFinalizers(row.managedResourceId, options.finalizers);
467
473
  this.bumpResource(row.resourceId, row.resourceVersion, now);
468
474
  this.insertEvent(
469
475
  row.resourceId,
@@ -476,22 +482,22 @@ export class SqliteControllerStore implements ControllerStore {
476
482
  options.claim.generation,
477
483
  );
478
484
  options.claim.resourceVersion = row.resourceVersion + 1;
479
- return this.requireResource(options.ref) as ControllerResource<unknown, TStatus>;
485
+ return this.requireResource(options.ref) as ManagedResource<unknown, TStatus>;
480
486
  });
481
487
  }
482
488
 
483
- requestDeletion(ref: ControllerResourceRef, nowValue?: string): ControllerResource {
489
+ requestDeletion(ref: ManagedResourceRef, nowValue?: string): ManagedResource {
484
490
  const now = epoch(validTimestamp(nowValue));
485
491
  return this.state.transaction(() => {
486
- const row = this.requireControllerRow(ref);
492
+ const row = this.requireResourceManagerRow(ref);
487
493
  if (row.deletionRequestedAt === null) {
488
494
  this.state.connection
489
495
  .prepare(
490
496
  "UPDATE controller_resources SET deletion_requested_at = ?, updated_at = ? WHERE controller_resource_id = ?",
491
497
  )
492
- .run(now, now, row.controllerResourceId);
498
+ .run(now, now, row.managedResourceId);
493
499
  this.bumpResource(row.resourceId, row.resourceVersion, now);
494
- this.enqueueControllerRow(row.controllerResourceId, now, now);
500
+ this.enqueueResourceManagerRow(row.managedResourceId, now, now);
495
501
  this.insertEvent(
496
502
  row.resourceId,
497
503
  row.resourceVersion + 1,
@@ -507,21 +513,21 @@ export class SqliteControllerStore implements ControllerStore {
507
513
  }
508
514
 
509
515
  updateFinalizers(options: {
510
- ref: ControllerResourceRef;
516
+ ref: ManagedResourceRef;
511
517
  expectedResourceVersion: number;
512
518
  finalizers: string[];
513
519
  now?: string;
514
- }): ControllerResource {
520
+ }): ManagedResource {
515
521
  const now = epoch(validTimestamp(options.now));
516
522
  return this.state.transaction(() => {
517
- const row = this.requireControllerRow(options.ref);
523
+ const row = this.requireResourceManagerRow(options.ref);
518
524
  if (row.resourceVersion !== options.expectedResourceVersion) {
519
- throw new ResourceConflictError(options.ref.controller, options.ref.key);
525
+ throw new ManagedResourceConflictError(options.ref.resourceManager, options.ref.key);
520
526
  }
521
- this.replaceFinalizers(row.controllerResourceId, options.finalizers);
527
+ this.replaceFinalizers(row.managedResourceId, options.finalizers);
522
528
  this.state.connection
523
529
  .prepare("UPDATE controller_resources SET updated_at = ? WHERE controller_resource_id = ?")
524
- .run(now, row.controllerResourceId);
530
+ .run(now, row.managedResourceId);
525
531
  this.bumpResource(row.resourceId, row.resourceVersion, now);
526
532
  this.insertEvent(
527
533
  row.resourceId,
@@ -537,50 +543,50 @@ export class SqliteControllerStore implements ControllerStore {
537
543
  }
538
544
 
539
545
  deleteResource(
540
- ref: ControllerResourceRef,
546
+ ref: ManagedResourceRef,
541
547
  expectedResourceVersion: number,
542
- claim: ControllerQueueClaim,
548
+ claim: ResourceManagerQueueClaim,
543
549
  ): boolean {
544
550
  return this.state.transaction(() => {
545
- const row = this.requireControllerRow(ref);
546
- this.assertControllerClaim(row, claim, Date.now());
551
+ const row = this.requireResourceManagerRow(ref);
552
+ this.assertResourceManagerClaim(row, claim, Date.now());
547
553
  if (row.resourceVersion !== expectedResourceVersion) {
548
- throw new ResourceConflictError(ref.controller, ref.key);
554
+ throw new ManagedResourceConflictError(ref.resourceManager, ref.key);
549
555
  }
550
- if (row.deletionRequestedAt === null || this.finalizers(row.controllerResourceId).length > 0)
556
+ if (row.deletionRequestedAt === null || this.finalizers(row.managedResourceId).length > 0)
551
557
  return false;
552
558
  this.state.connection
553
559
  .prepare("DELETE FROM controller_resources WHERE controller_resource_id = ?")
554
- .run(row.controllerResourceId);
560
+ .run(row.managedResourceId);
555
561
  return true;
556
562
  });
557
563
  }
558
564
 
559
- enqueue(ref: ControllerResourceRef, availableAt?: string): void {
560
- const row = this.requireControllerRow(ref);
565
+ enqueue(ref: ManagedResourceRef, availableAt?: string): void {
566
+ const row = this.requireResourceManagerRow(ref);
561
567
  const now = Date.now();
562
- this.enqueueControllerRow(row.controllerResourceId, epoch(validTimestamp(availableAt)), now);
568
+ this.enqueueResourceManagerRow(row.managedResourceId, epoch(validTimestamp(availableAt)), now);
563
569
  }
564
570
 
565
571
  claimNext(options: {
566
- controllers: string[];
572
+ resourceManagers: string[];
567
573
  ownerId: string;
568
574
  leaseMs: number;
569
575
  now?: string;
570
- exclude?: ControllerResourceRef[];
571
- }): ControllerQueueClaim | undefined {
572
- if (options.controllers.length === 0) return undefined;
576
+ exclude?: ManagedResourceRef[];
577
+ }): ResourceManagerQueueClaim | undefined {
578
+ if (options.resourceManagers.length === 0) return undefined;
573
579
  const now = epoch(validTimestamp(options.now));
574
- const placeholders = options.controllers.map(() => "?").join(", ");
580
+ const placeholders = options.resourceManagers.map(() => "?").join(", ");
575
581
  const exclusions = options.exclude ?? [];
576
582
  const exclusionSql = exclusions
577
583
  .map(() => "AND NOT (c.controller_name = ? AND c.resource_key = ?)")
578
584
  .join("\n ");
579
- const exclusionParams = exclusions.flatMap((ref) => [ref.controller, ref.key]);
585
+ const exclusionParams = exclusions.flatMap((ref) => [ref.resourceManager, ref.key]);
580
586
  return this.state.transaction(() => {
581
587
  const row = this.state.connection
582
588
  .prepare(
583
- `${controllerSelect(`
589
+ `${resourceManagerSelect(`
584
590
  JOIN controller_queue q ON q.controller_resource_id = c.controller_resource_id
585
591
  JOIN leases l ON l.resource_id = c.resource_id
586
592
  WHERE c.project_id = ?
@@ -591,8 +597,8 @@ export class SqliteControllerStore implements ControllerStore {
591
597
  ORDER BY q.available_at, c.controller_name, c.resource_key
592
598
  LIMIT 1`)}`,
593
599
  )
594
- .get(this.requireProjectId(), ...options.controllers, ...exclusionParams, now, now);
595
- if (!isControllerRow(row)) return undefined;
600
+ .get(this.requireProjectId(), ...options.resourceManagers, ...exclusionParams, now, now);
601
+ if (!isResourceManagerRow(row)) return undefined;
596
602
  const lease = this.requireLease(row.resourceId);
597
603
  const token = randomBytes(32).toString("base64url");
598
604
  const generation = lease.generation + 1;
@@ -630,23 +636,23 @@ export class SqliteControllerStore implements ControllerStore {
630
636
  generation,
631
637
  );
632
638
  return {
633
- controller: row.controllerName,
639
+ resourceManager: row.resourceManagerName,
634
640
  key: row.resourceKey,
635
641
  ownerId: options.ownerId,
636
642
  token,
637
643
  generation,
638
- queueVersion: this.queueVersion(row.controllerResourceId),
644
+ queueVersion: this.queueVersion(row.managedResourceId),
639
645
  resourceVersion: row.resourceVersion + 1,
640
- consecutiveErrors: this.queueErrors(row.controllerResourceId),
646
+ consecutiveErrors: this.queueErrors(row.managedResourceId),
641
647
  expiresAt: new Date(expiresAt).toISOString(),
642
648
  };
643
649
  });
644
650
  }
645
651
 
646
- renewClaim(claim: ControllerQueueClaim, leaseMs: number, nowValue?: string): boolean {
652
+ renewClaim(claim: ResourceManagerQueueClaim, leaseMs: number, nowValue?: string): boolean {
647
653
  const now = epoch(validTimestamp(nowValue));
648
654
  const expiresAt = now + leaseMs;
649
- const row = this.controllerRow({ controller: claim.controller, key: claim.key });
655
+ const row = this.resourceManagerRow({ resourceManager: claim.resourceManager, key: claim.key });
650
656
  if (row === undefined) return false;
651
657
  const result = this.state.connection
652
658
  .prepare(
@@ -667,22 +673,22 @@ export class SqliteControllerStore implements ControllerStore {
667
673
  return result.changes === 1;
668
674
  }
669
675
 
670
- settleClaim(claim: ControllerQueueClaim, nowValue?: string): boolean {
671
- return this.settleControllerClaim(claim, undefined, nowValue);
676
+ settleClaim(claim: ResourceManagerQueueClaim, nowValue?: string): boolean {
677
+ return this.settleResourceManagerClaim(claim, undefined, nowValue);
672
678
  }
673
679
 
674
680
  requeueClaim(
675
- claim: ControllerQueueClaim,
681
+ claim: ResourceManagerQueueClaim,
676
682
  options: QueueRequeueOptions,
677
683
  nowValue?: string,
678
684
  ): boolean {
679
- return this.settleControllerClaim(claim, options, nowValue);
685
+ return this.settleResourceManagerClaim(claim, options, nowValue);
680
686
  }
681
687
 
682
688
  listQueue(): QueueItem[] {
683
689
  const rows = this.state.connection
684
690
  .prepare(
685
- `SELECT c.controller_name AS controller, c.resource_key AS resourceKey,
691
+ `SELECT c.controller_name AS resourceManager, c.resource_key AS resourceKey,
686
692
  q.available_at AS availableAt, q.consecutive_errors AS consecutiveErrors,
687
693
  l.expires_at AS claimExpiresAt
688
694
  FROM controller_queue q
@@ -692,7 +698,7 @@ export class SqliteControllerStore implements ControllerStore {
692
698
  )
693
699
  .all(this.requireProjectId());
694
700
  return rows.filter(isQueueListRow).map((row) => ({
695
- controller: row.controller,
701
+ resourceManager: row.resourceManager,
696
702
  key: row.resourceKey,
697
703
  availableAt: new Date(row.availableAt).toISOString(),
698
704
  consecutiveErrors: row.consecutiveErrors,
@@ -705,7 +711,7 @@ export class SqliteControllerStore implements ControllerStore {
705
711
  reserveEffect(options: {
706
712
  key: string;
707
713
  resourceUid: string;
708
- claim: ControllerQueueClaim;
714
+ claim: ResourceManagerQueueClaim;
709
715
  generation: number;
710
716
  kind: string;
711
717
  requestFingerprint: string;
@@ -713,8 +719,8 @@ export class SqliteControllerStore implements ControllerStore {
713
719
  }): EffectReservation {
714
720
  const now = epoch(validTimestamp(options.now));
715
721
  return this.state.transaction(() => {
716
- const source = this.requireControllerRowByUid(options.resourceUid);
717
- this.assertControllerClaim(source, options.claim, now);
722
+ const source = this.requireResourceManagerRowByUid(options.resourceUid);
723
+ this.assertResourceManagerClaim(source, options.claim, now);
718
724
  const effectId = effectIdFor(source.resourceId, options.key);
719
725
  const existing = this.effectRow(options.resourceUid, options.key);
720
726
  if (existing !== undefined) {
@@ -791,7 +797,7 @@ export class SqliteControllerStore implements ControllerStore {
791
797
  updateEffect(options: {
792
798
  resourceUid: string;
793
799
  key: string;
794
- claim: ControllerQueueClaim;
800
+ claim: ResourceManagerQueueClaim;
795
801
  state: EffectRecord["state"];
796
802
  externalRef?: string;
797
803
  error?: string;
@@ -799,8 +805,8 @@ export class SqliteControllerStore implements ControllerStore {
799
805
  }): EffectRecord {
800
806
  const now = epoch(validTimestamp(options.now));
801
807
  return this.state.transaction(() => {
802
- const source = this.requireControllerRowByUid(options.resourceUid);
803
- this.assertControllerClaim(source, options.claim, now);
808
+ const source = this.requireResourceManagerRowByUid(options.resourceUid);
809
+ this.assertResourceManagerClaim(source, options.claim, now);
804
810
  const row = this.requireEffectRow(options.resourceUid, options.key);
805
811
  const effectResourceId = resourceIdFor("effect", row.effectId);
806
812
  const revision = this.resourceRevision(effectResourceId);
@@ -843,15 +849,15 @@ export class SqliteControllerStore implements ControllerStore {
843
849
 
844
850
  reserveWorkflow(options: {
845
851
  resourceUid: string;
846
- claim: ControllerQueueClaim;
852
+ claim: ResourceManagerQueueClaim;
847
853
  requestKey: string;
848
854
  workflow: string;
849
855
  inputFingerprint: string;
850
856
  }): WorkflowReservation {
851
857
  const now = Date.now();
852
858
  return this.state.transaction(() => {
853
- const source = this.requireControllerRowByUid(options.resourceUid);
854
- this.assertControllerClaim(source, options.claim, now);
859
+ const source = this.requireResourceManagerRowByUid(options.resourceUid);
860
+ this.assertResourceManagerClaim(source, options.claim, now);
855
861
  const existing = this.workflowRow(options.resourceUid, options.requestKey);
856
862
  if (existing !== undefined) {
857
863
  if (
@@ -872,7 +878,7 @@ export class SqliteControllerStore implements ControllerStore {
872
878
  )
873
879
  .run(
874
880
  requestId,
875
- source.controllerResourceId,
881
+ source.managedResourceId,
876
882
  options.requestKey,
877
883
  options.workflow,
878
884
  Buffer.from(options.inputFingerprint, "hex"),
@@ -896,13 +902,13 @@ export class SqliteControllerStore implements ControllerStore {
896
902
  updateWorkflow(
897
903
  requestId: string,
898
904
  update: WorkflowRecordUpdate,
899
- claim: ControllerQueueClaim,
905
+ claim: ResourceManagerQueueClaim,
900
906
  ): ChildWorkflowRecord {
901
907
  const now = Date.now();
902
908
  return this.state.transaction(() => {
903
909
  const row = this.requireWorkflowRow(requestId);
904
- const source = this.requireControllerRowByUid(row.resourceUid);
905
- this.assertControllerClaim(source, claim, now);
910
+ const source = this.requireResourceManagerRowByUid(row.resourceUid);
911
+ this.assertResourceManagerClaim(source, claim, now);
906
912
  const errorHash =
907
913
  update.error === undefined || update.error === null
908
914
  ? null
@@ -942,7 +948,7 @@ export class SqliteControllerStore implements ControllerStore {
942
948
  if (update.runId !== undefined && row.runId !== null && update.runId !== row.runId) {
943
949
  throw new Error("Scheduler completion run ID does not match the reserved child run");
944
950
  }
945
- const source = this.requireControllerRowByUid(row.resourceUid);
951
+ const source = this.requireResourceManagerRowByUid(row.resourceUid);
946
952
  const now = Date.now();
947
953
  return this.state.transaction(() => {
948
954
  const errorHash =
@@ -993,17 +999,20 @@ export class SqliteControllerStore implements ControllerStore {
993
999
  }
994
1000
 
995
1001
  recordEvent(options: {
996
- controller: string;
1002
+ resourceManager: string;
997
1003
  key: string;
998
- claim?: ControllerQueueClaim;
1004
+ claim?: ResourceManagerQueueClaim;
999
1005
  type: string;
1000
1006
  payload?: JsonObject;
1001
1007
  now?: string;
1002
- }): ControllerEvent {
1008
+ }): ResourceManagerEvent {
1003
1009
  const now = epoch(validTimestamp(options.now));
1004
1010
  return this.state.transaction(() => {
1005
- const row = this.requireControllerRow({ controller: options.controller, key: options.key });
1006
- if (options.claim !== undefined) this.assertControllerClaim(row, options.claim, now);
1011
+ const row = this.requireResourceManagerRow({
1012
+ resourceManager: options.resourceManager,
1013
+ key: options.key,
1014
+ });
1015
+ if (options.claim !== undefined) this.assertResourceManagerClaim(row, options.claim, now);
1007
1016
  const revision = this.resourceRevision(row.resourceId) + 1;
1008
1017
  this.bumpResource(row.resourceId, revision - 1, now);
1009
1018
  const eventId = this.insertEvent(
@@ -1021,11 +1030,11 @@ export class SqliteControllerStore implements ControllerStore {
1021
1030
  .prepare("SELECT event_seq AS seq FROM events WHERE event_id = ?")
1022
1031
  .get(eventId);
1023
1032
  /* istanbul ignore if -- exact schema and internal query shape */
1024
- if (!isSequenceRow(event)) throw new Error("Controller event was not recorded");
1033
+ if (!isSequenceRow(event)) throw new Error("ResourceManager event was not recorded");
1025
1034
  return {
1026
1035
  seq: event.seq,
1027
1036
  recordedAt: new Date(now).toISOString(),
1028
- controller: options.controller,
1037
+ resourceManager: options.resourceManager,
1029
1038
  key: options.key,
1030
1039
  type: options.type,
1031
1040
  payload: options.payload ?? {},
@@ -1034,17 +1043,17 @@ export class SqliteControllerStore implements ControllerStore {
1034
1043
  }
1035
1044
 
1036
1045
  listEvents(
1037
- options: { controller?: string; key?: string; limit?: number } = {},
1038
- ): ControllerEvent[] {
1046
+ options: { resourceManager?: string; key?: string; limit?: number } = {},
1047
+ ): ResourceManagerEvent[] {
1039
1048
  const clauses = ["r.resource_type = 'controller'"];
1040
1049
  const params: unknown[] = [];
1041
1050
  if (this.projectId !== null) {
1042
1051
  clauses.push("c.project_id = ?");
1043
1052
  params.push(this.projectId);
1044
1053
  }
1045
- if (options.controller !== undefined) {
1054
+ if (options.resourceManager !== undefined) {
1046
1055
  clauses.push("c.controller_name = ?");
1047
- params.push(options.controller);
1056
+ params.push(options.resourceManager);
1048
1057
  }
1049
1058
  if (options.key !== undefined) {
1050
1059
  clauses.push("c.resource_key = ?");
@@ -1054,7 +1063,7 @@ export class SqliteControllerStore implements ControllerStore {
1054
1063
  const rows = this.state.connection
1055
1064
  .prepare(
1056
1065
  `SELECT e.event_seq AS seq, e.recorded_at AS recordedAt,
1057
- c.controller_name AS controller, c.resource_key AS resourceKey,
1066
+ c.controller_name AS resourceManager, c.resource_key AS resourceKey,
1058
1067
  e.event_type AS eventType, e.payload_hash AS payloadHash
1059
1068
  FROM events e
1060
1069
  JOIN resources r ON r.resource_id = e.resource_id
@@ -1063,10 +1072,10 @@ export class SqliteControllerStore implements ControllerStore {
1063
1072
  ORDER BY e.event_seq DESC LIMIT ?`,
1064
1073
  )
1065
1074
  .all(...params);
1066
- return rows.filter(isControllerEventRow).map((row) => ({
1075
+ return rows.filter(isResourceManagerEventRow).map((row) => ({
1067
1076
  seq: row.seq,
1068
1077
  recordedAt: new Date(row.recordedAt).toISOString(),
1069
- controller: row.controller,
1078
+ resourceManager: row.resourceManager,
1070
1079
  key: row.resourceKey,
1071
1080
  type: row.eventType,
1072
1081
  payload: row.payloadHash === null ? {} : (this.state.readJson(row.payloadHash) as JsonObject),
@@ -1403,7 +1412,7 @@ export class SqliteControllerStore implements ControllerStore {
1403
1412
  return this.claimRun(options.runId, options.runnerId, options.claimToken, options.leaseMs, now);
1404
1413
  }
1405
1414
 
1406
- /** Schedule a worker that validates one pending interactive submission. */
1415
+ /** Schedule a runner that validates one pending interactive submission. */
1407
1416
  claimWorkflowRunForInteractionValidation(options: {
1408
1417
  runId: string;
1409
1418
  runnerId: string;
@@ -1424,7 +1433,7 @@ export class SqliteControllerStore implements ControllerStore {
1424
1433
  );
1425
1434
  }
1426
1435
 
1427
- /** Take a short host claim without scheduling a parked interactive run. */
1436
+ /** Take a short server claim without scheduling a parked interactive run. */
1428
1437
  claimWorkflowRunForControl(options: {
1429
1438
  runId: string;
1430
1439
  runnerId: string;
@@ -1556,7 +1565,7 @@ export class SqliteControllerStore implements ControllerStore {
1556
1565
  "(q.affinity_runner_id IS NULL OR q.affinity_runner_id = ? OR q.status IN ('parked', 'starting', 'running'))",
1557
1566
  "NOT (q.status = 'parked' AND (r.status = 'waiting' OR r.paused = 1))",
1558
1567
  "NOT EXISTS (SELECT 1 FROM interactive_requests i WHERE i.run_id = r.run_id AND i.status = 'pending')",
1559
- "(q.error_code IS NULL OR q.error_code <> 'workflowSourceChanged')",
1568
+ "(q.error_code IS NULL OR q.error_code NOT IN ('workflowSourceChanged', 'runnerNoProgress'))",
1560
1569
  ];
1561
1570
  const params: unknown[] = [now, now, options.runnerId, options.runnerId];
1562
1571
  if (this.projectId !== null) {
@@ -1669,6 +1678,78 @@ export class SqliteControllerStore implements ControllerStore {
1669
1678
  return this.releaseRunClaim(options.runId, options.claimToken, "parked", options.now);
1670
1679
  }
1671
1680
 
1681
+ parkWorkflowRunForRunnerNoProgress(options: {
1682
+ runId: string;
1683
+ claimToken: string;
1684
+ detail: string;
1685
+ now?: string;
1686
+ }): boolean {
1687
+ const now = epoch(validTimestamp(options.now));
1688
+ return this.state.transaction(() => {
1689
+ if (
1690
+ !this.verifyWorkflowRunClaim({
1691
+ runId: options.runId,
1692
+ claimToken: options.claimToken,
1693
+ now: new Date(now).toISOString(),
1694
+ })
1695
+ ) {
1696
+ return false;
1697
+ }
1698
+ const row = this.requireWorkflowRunRow(options.runId);
1699
+ const lease = this.requireLease(row.resourceId);
1700
+ const detail = options.detail.slice(0, 8_192);
1701
+ const errorHash = this.state.putText(detail, now);
1702
+ const run = this.state.connection
1703
+ .prepare(
1704
+ `UPDATE runs SET status_detail = ?, updated_at = ?, finished_at = NULL
1705
+ WHERE run_id = ? AND status NOT IN ('completed', 'failed', 'timed_out', 'cancelled')`,
1706
+ )
1707
+ .run(detail, now, options.runId);
1708
+ const queue = this.state.connection
1709
+ .prepare(
1710
+ `UPDATE run_queue
1711
+ SET status = 'parked', error_code = 'runnerNoProgress', error_hash = ?,
1712
+ available_at = ?, updated_at = ?, finished_at = NULL
1713
+ WHERE run_id = ? AND status IN ('queued', 'starting', 'running', 'parked')`,
1714
+ )
1715
+ .run(errorHash, now, now, options.runId);
1716
+ if (run.changes !== 1 || queue.changes !== 1) {
1717
+ throw new Error(`Workflow run ${options.runId} changed during runner recovery`);
1718
+ }
1719
+ const released = this.state.connection
1720
+ .prepare(
1721
+ `UPDATE leases
1722
+ SET owner_type = NULL, owner_id = NULL, token_hash = NULL,
1723
+ acquired_at = NULL, heartbeat_at = NULL, expires_at = NULL
1724
+ WHERE resource_id = ? AND token_hash = ? AND generation = ? AND expires_at > ?`,
1725
+ )
1726
+ .run(row.resourceId, tokenHash(options.claimToken), lease.generation, now);
1727
+ /* istanbul ignore if -- the exact live claim is stable in this transaction */
1728
+ if (released.changes !== 1) {
1729
+ throw new Error(`Workflow run ${options.runId} claim changed during runner recovery`);
1730
+ }
1731
+ const revision = this.resourceRevision(row.resourceId);
1732
+ this.bumpResource(row.resourceId, revision, now);
1733
+ this.insertEvent(
1734
+ row.resourceId,
1735
+ revision + 1,
1736
+ "run.worker_no_progress",
1737
+ lease.ownerType ?? "system",
1738
+ lease.ownerId,
1739
+ { status: "parked", code: "runnerNoProgress" },
1740
+ now,
1741
+ lease.generation || undefined,
1742
+ );
1743
+ recordViewerDeltas(
1744
+ this.state,
1745
+ options.runId,
1746
+ [{ targetType: "summary" }, { targetType: "replay" }],
1747
+ now,
1748
+ );
1749
+ return true;
1750
+ });
1751
+ }
1752
+
1672
1753
  pauseParkedWorkflowRun(options: { runId: string; now?: string }): boolean {
1673
1754
  const now = epoch(validTimestamp(options.now));
1674
1755
  return this.state.transaction(() => {
@@ -2015,6 +2096,7 @@ export class SqliteControllerStore implements ControllerStore {
2015
2096
  if (run.changes !== 1) {
2016
2097
  throw new Error(`Workflow run ${options.runId} has inconsistent durable state`);
2017
2098
  }
2099
+ this.settleWorkflowRunMessages(options.runId, now);
2018
2100
  this.cancelWorkflowRunDependents(options.runId, controlId, errorHash, now);
2019
2101
 
2020
2102
  const released = this.state.connection
@@ -2216,84 +2298,87 @@ export class SqliteControllerStore implements ControllerStore {
2216
2298
 
2217
2299
  private requireProjectId(): string {
2218
2300
  if (this.projectId === null)
2219
- throw new Error("Controller project is not registered in the state database");
2301
+ throw new Error("ResourceManager project is not registered in the state database");
2220
2302
  return this.projectId;
2221
2303
  }
2222
2304
 
2223
- private controllerRow(ref: ControllerResourceRef): ControllerRow | undefined {
2305
+ private resourceManagerRow(ref: ManagedResourceRef): ResourceManagerRow | undefined {
2224
2306
  if (this.projectId === null) return undefined;
2225
2307
  const row = this.state.connection
2226
2308
  .prepare(
2227
- controllerSelect("WHERE c.project_id = ? AND c.controller_name = ? AND c.resource_key = ?"),
2309
+ resourceManagerSelect(
2310
+ "WHERE c.project_id = ? AND c.controller_name = ? AND c.resource_key = ?",
2311
+ ),
2228
2312
  )
2229
- .get(this.projectId, ref.controller, ref.key);
2230
- return isControllerRow(row) ? row : undefined;
2313
+ .get(this.projectId, ref.resourceManager, ref.key);
2314
+ return isResourceManagerRow(row) ? row : undefined;
2231
2315
  }
2232
2316
 
2233
- private requireControllerRow(ref: ControllerResourceRef): ControllerRow {
2234
- const row = this.controllerRow(ref);
2235
- if (row === undefined) throw new ResourceNotFoundError(ref.controller, ref.key);
2317
+ private requireResourceManagerRow(ref: ManagedResourceRef): ResourceManagerRow {
2318
+ const row = this.resourceManagerRow(ref);
2319
+ if (row === undefined) throw new ManagedResourceNotFoundError(ref.resourceManager, ref.key);
2236
2320
  return row;
2237
2321
  }
2238
2322
 
2239
- private requireControllerRowByUid(uid: string): ControllerRow {
2240
- const row = this.state.connection.prepare(controllerSelect("WHERE c.uid = ?")).get(uid);
2323
+ private requireResourceManagerRowByUid(uid: string): ResourceManagerRow {
2324
+ const row = this.state.connection.prepare(resourceManagerSelect("WHERE c.uid = ?")).get(uid);
2241
2325
  /* istanbul ignore if -- impossible after exact schema and transaction checks */
2242
- if (!isControllerRow(row)) throw new Error(`Controller resource not found: ${uid}`);
2326
+ if (!isResourceManagerRow(row)) throw new Error(`Managed resource not found: ${uid}`);
2243
2327
  return row;
2244
2328
  }
2245
2329
 
2246
- private requireResource(ref: ControllerResourceRef): ControllerResource {
2330
+ private requireResource(ref: ManagedResourceRef): ManagedResource {
2247
2331
  const resource = this.getResource(ref);
2248
- if (resource === undefined) throw new ResourceNotFoundError(ref.controller, ref.key);
2332
+ if (resource === undefined)
2333
+ throw new ManagedResourceNotFoundError(ref.resourceManager, ref.key);
2249
2334
  return resource;
2250
2335
  }
2251
2336
 
2252
2337
  /* istanbul ignore next -- pure projection covered by integration tests */
2253
- private mapControllerResource(row: ControllerRow): ControllerResource {
2338
+ private mapManagedResource(row: ResourceManagerRow): ManagedResource {
2254
2339
  const spec = this.state.readJson(row.specHash);
2255
- const status = this.state.readJson(row.statusHash) as ControllerResourceStatus<unknown>;
2340
+ const status = this.state.readJson(row.statusHash) as ManagedResourceStatus<unknown>;
2256
2341
  return {
2257
2342
  metadata: {
2258
2343
  uid: row.uid,
2259
- controller: row.controllerName,
2344
+ resourceManager: row.resourceManagerName,
2260
2345
  key: row.resourceKey,
2261
2346
  resourceVersion: row.resourceVersion,
2262
2347
  generation: row.generation,
2263
2348
  ...(row.deletionRequestedAt === null
2264
2349
  ? {}
2265
2350
  : { deletionTimestamp: new Date(row.deletionRequestedAt).toISOString() }),
2266
- finalizers: this.finalizers(row.controllerResourceId),
2351
+ finalizers: this.finalizers(row.managedResourceId),
2267
2352
  },
2268
2353
  spec,
2269
2354
  status,
2270
2355
  };
2271
2356
  }
2272
2357
 
2273
- private finalizers(controllerResourceId: string): string[] {
2358
+ private finalizers(managedResourceId: string): string[] {
2274
2359
  const rows = this.state.connection
2275
2360
  .prepare(
2276
2361
  "SELECT finalizer FROM controller_finalizers WHERE controller_resource_id = ? ORDER BY position",
2277
2362
  )
2278
- .all(controllerResourceId);
2363
+ .all(managedResourceId);
2279
2364
  return rows.flatMap((row) => (isFinalizerRow(row) ? [row.finalizer] : []));
2280
2365
  }
2281
2366
 
2282
- private replaceFinalizers(controllerResourceId: string, finalizers: string[]): void {
2367
+ private replaceFinalizers(managedResourceId: string, finalizers: string[]): void {
2283
2368
  const unique = [...new Set(finalizers)];
2284
2369
  if (unique.length !== finalizers.length)
2285
- throw new Error("Controller finalizers must be unique");
2370
+ throw new Error("ResourceManager finalizers must be unique");
2286
2371
  this.state.connection
2287
2372
  .prepare("DELETE FROM controller_finalizers WHERE controller_resource_id = ?")
2288
- .run(controllerResourceId);
2373
+ .run(managedResourceId);
2289
2374
  const insert = this.state.connection.prepare(
2290
2375
  "INSERT INTO controller_finalizers(controller_resource_id, finalizer, position) VALUES (?, ?, ?)",
2291
2376
  );
2292
- unique.forEach((finalizer, index) => insert.run(controllerResourceId, finalizer, index));
2377
+ unique.forEach((finalizer, index) => insert.run(managedResourceId, finalizer, index));
2293
2378
  }
2294
2379
 
2295
- private enqueueControllerRow(
2296
- controllerResourceId: string,
2380
+ private enqueueResourceManagerRow(
2381
+ managedResourceId: string,
2297
2382
  availableAt: number,
2298
2383
  now: number,
2299
2384
  ): void {
@@ -2308,50 +2393,53 @@ export class SqliteControllerStore implements ControllerStore {
2308
2393
  queue_version = controller_queue.queue_version + 1,
2309
2394
  updated_at = excluded.updated_at`,
2310
2395
  )
2311
- .run(controllerResourceId, availableAt, now, now);
2396
+ .run(managedResourceId, availableAt, now, now);
2312
2397
  }
2313
2398
 
2314
- private queueErrors(controllerResourceId: string): number {
2399
+ private queueErrors(managedResourceId: string): number {
2315
2400
  const row = this.state.connection
2316
2401
  .prepare(
2317
2402
  "SELECT consecutive_errors AS consecutiveErrors FROM controller_queue WHERE controller_resource_id = ?",
2318
2403
  )
2319
- .get(controllerResourceId);
2404
+ .get(managedResourceId);
2320
2405
  return isErrorCountRow(row) ? row.consecutiveErrors : 0;
2321
2406
  }
2322
2407
 
2323
- private queueVersion(controllerResourceId: string): number {
2408
+ private queueVersion(managedResourceId: string): number {
2324
2409
  const row = this.state.connection
2325
2410
  .prepare(
2326
2411
  "SELECT queue_version AS queueVersion FROM controller_queue WHERE controller_resource_id = ?",
2327
2412
  )
2328
- .get(controllerResourceId);
2413
+ .get(managedResourceId);
2329
2414
  /* istanbul ignore if -- exact schema and internal query shape */
2330
2415
  /* istanbul ignore if -- impossible after exact schema and transaction checks */
2331
- if (!isQueueVersionRow(row)) throw new Error("Controller queue item is missing");
2416
+ if (!isQueueVersionRow(row)) throw new Error("ResourceManager queue item is missing");
2332
2417
  return row.queueVersion;
2333
2418
  }
2334
2419
 
2335
- private settleControllerClaim(
2336
- claim: ControllerQueueClaim,
2420
+ private settleResourceManagerClaim(
2421
+ claim: ResourceManagerQueueClaim,
2337
2422
  requeue: QueueRequeueOptions | undefined,
2338
2423
  nowValue?: string,
2339
2424
  ): boolean {
2340
2425
  const now = epoch(validTimestamp(nowValue));
2341
2426
  return this.state.transaction(() => {
2342
- const row = this.controllerRow({ controller: claim.controller, key: claim.key });
2427
+ const row = this.resourceManagerRow({
2428
+ resourceManager: claim.resourceManager,
2429
+ key: claim.key,
2430
+ });
2343
2431
  if (row === undefined) return false;
2344
2432
  try {
2345
- this.assertControllerClaim(row, claim, now, false);
2433
+ this.assertResourceManagerClaim(row, claim, now, false);
2346
2434
  } catch {
2347
2435
  return false;
2348
2436
  }
2349
- const currentQueueVersion = this.queueVersion(row.controllerResourceId);
2437
+ const currentQueueVersion = this.queueVersion(row.managedResourceId);
2350
2438
  if (requeue === undefined) {
2351
2439
  if (currentQueueVersion === claim.queueVersion) {
2352
2440
  this.state.connection
2353
2441
  .prepare("DELETE FROM controller_queue WHERE controller_resource_id = ?")
2354
- .run(row.controllerResourceId);
2442
+ .run(row.managedResourceId);
2355
2443
  }
2356
2444
  } else {
2357
2445
  const errorHash =
@@ -2363,21 +2451,21 @@ export class SqliteControllerStore implements ControllerStore {
2363
2451
  consecutive_errors = consecutive_errors + 1,
2364
2452
  last_error_hash = ?, updated_at = ? WHERE controller_resource_id = ?`,
2365
2453
  )
2366
- .run(epoch(requeue.availableAt), errorHash, now, row.controllerResourceId);
2454
+ .run(epoch(requeue.availableAt), errorHash, now, row.managedResourceId);
2367
2455
  }
2368
2456
  this.releaseLease(row.resourceId, claim, now);
2369
2457
  return true;
2370
2458
  });
2371
2459
  }
2372
2460
 
2373
- private assertControllerClaim(
2374
- row: ControllerRow,
2375
- claim: ControllerQueueClaim,
2461
+ private assertResourceManagerClaim(
2462
+ row: ResourceManagerRow,
2463
+ claim: ResourceManagerQueueClaim,
2376
2464
  now: number,
2377
2465
  requireUnexpired = true,
2378
2466
  ): void {
2379
- if (row.controllerName !== claim.controller || row.resourceKey !== claim.key)
2380
- throw new Error("Controller claim targets another resource");
2467
+ if (row.resourceManagerName !== claim.resourceManager || row.resourceKey !== claim.key)
2468
+ throw new Error("ResourceManager claim targets another resource");
2381
2469
  const lease = this.requireLease(row.resourceId);
2382
2470
  if (
2383
2471
  lease.ownerType !== "controller" ||
@@ -2387,7 +2475,7 @@ export class SqliteControllerStore implements ControllerStore {
2387
2475
  !lease.tokenHash.equals(tokenHash(claim.token)) ||
2388
2476
  (requireUnexpired && (lease.expiresAt === null || lease.expiresAt <= now))
2389
2477
  ) {
2390
- throw new Error("Controller claim is stale");
2478
+ throw new Error("ResourceManager claim is stale");
2391
2479
  }
2392
2480
  }
2393
2481
 
@@ -2405,8 +2493,8 @@ export class SqliteControllerStore implements ControllerStore {
2405
2493
  return row;
2406
2494
  }
2407
2495
 
2408
- private releaseLease(resourceId: string, claim: ControllerQueueClaim, now: number): void {
2409
- const row = this.controllerRow({ controller: claim.controller, key: claim.key });
2496
+ private releaseLease(resourceId: string, claim: ResourceManagerQueueClaim, now: number): void {
2497
+ const row = this.resourceManagerRow({ resourceManager: claim.resourceManager, key: claim.key });
2410
2498
  if (row === undefined) return;
2411
2499
  const revision = this.resourceRevision(resourceId);
2412
2500
  const result = this.state.connection
@@ -2524,7 +2612,7 @@ export class SqliteControllerStore implements ControllerStore {
2524
2612
  resourceUid: row.resourceUid,
2525
2613
  generation: row.generation,
2526
2614
  kind: row.kind,
2527
- state: controllerEffectState(row.state),
2615
+ state: resourceManagerEffectState(row.state),
2528
2616
  requestFingerprint: row.requestFingerprint,
2529
2617
  startedAt: new Date(row.startedAt).toISOString(),
2530
2618
  ...(row.completedAt === null ? {} : { completedAt: new Date(row.completedAt).toISOString() }),
@@ -2924,6 +3012,7 @@ export class SqliteControllerStore implements ControllerStore {
2924
3012
  WHERE run_id = ?`,
2925
3013
  )
2926
3014
  .run(status, errorHash, now, now, runId);
3015
+ this.settleWorkflowRunMessages(runId, now);
2927
3016
  if (status === "cancelled") {
2928
3017
  this.cancelWorkflowRunDependents(
2929
3018
  runId,
@@ -2953,6 +3042,11 @@ export class SqliteControllerStore implements ControllerStore {
2953
3042
  });
2954
3043
  }
2955
3044
 
3045
+ private settleWorkflowRunMessages(runId: string, now: number): void {
3046
+ this.workflowMessages.settleOpenTurnsForRun(runId, "lost", now);
3047
+ this.workflowMessages.cancelPendingForRun(runId, now);
3048
+ }
3049
+
2956
3050
  private cancelWorkflowRunDependents(
2957
3051
  runId: string,
2958
3052
  actorId: string,
@@ -3047,14 +3141,14 @@ export class SqliteControllerStore implements ControllerStore {
3047
3141
  }
3048
3142
 
3049
3143
  private assertWritable(): void {
3050
- if (this.state.mode === "read-only") throw new Error("Controller store is read-only");
3144
+ if (this.state.mode === "read-only") throw new Error("ResourceManager store is read-only");
3051
3145
  }
3052
3146
  }
3053
3147
 
3054
- function controllerSelect(clause: string): string {
3055
- return `SELECT c.controller_resource_id AS controllerResourceId,
3148
+ function resourceManagerSelect(clause: string): string {
3149
+ return `SELECT c.controller_resource_id AS managedResourceId,
3056
3150
  c.resource_id AS resourceId, r.revision AS resourceVersion,
3057
- c.controller_name AS controllerName, c.resource_key AS resourceKey,
3151
+ c.controller_name AS resourceManagerName, c.resource_key AS resourceKey,
3058
3152
  c.uid, c.generation, c.spec_hash AS specHash, c.status_hash AS statusHash,
3059
3153
  c.deletion_requested_at AS deletionRequestedAt
3060
3154
  FROM controller_resources c JOIN resources r ON r.resource_id = c.resource_id ${clause}`;
@@ -3123,16 +3217,16 @@ function workflowRunViewSelect(clause: string): string {
3123
3217
  }
3124
3218
 
3125
3219
  type QueueListRow = {
3126
- controller: string;
3220
+ resourceManager: string;
3127
3221
  resourceKey: string;
3128
3222
  availableAt: number;
3129
3223
  consecutiveErrors: number;
3130
3224
  claimExpiresAt: number | null;
3131
3225
  };
3132
- type ControllerEventRow = {
3226
+ type ResourceManagerEventRow = {
3133
3227
  seq: number;
3134
3228
  recordedAt: number;
3135
- controller: string;
3229
+ resourceManager: string;
3136
3230
  resourceKey: string;
3137
3231
  eventType: string;
3138
3232
  payloadHash: Buffer | null;
@@ -3149,7 +3243,7 @@ type RunEventRow = {
3149
3243
  function isRecord(value: unknown): value is Record<string, unknown> {
3150
3244
  return typeof value === "object" && value !== null && !Array.isArray(value);
3151
3245
  }
3152
- function isControllerRow(value: unknown): value is ControllerRow {
3246
+ function isResourceManagerRow(value: unknown): value is ResourceManagerRow {
3153
3247
  return isRecord(value);
3154
3248
  }
3155
3249
  function isLeaseRow(value: unknown): value is LeaseRow {
@@ -3256,7 +3350,7 @@ function isWorkflowRow(value: unknown): value is WorkflowRow {
3256
3350
  function isQueueListRow(value: unknown): value is QueueListRow {
3257
3351
  return isRecord(value);
3258
3352
  }
3259
- function isControllerEventRow(value: unknown): value is ControllerEventRow {
3353
+ function isResourceManagerEventRow(value: unknown): value is ResourceManagerEventRow {
3260
3354
  return isRecord(value);
3261
3355
  }
3262
3356
  function isRunEventRow(value: unknown): value is RunEventRow {
@@ -3436,7 +3530,7 @@ function rowToSource(row: RunSourceIdentityRow): QueuedSource["root"] {
3436
3530
  function effectStatus(value: EffectRecord["state"]): string {
3437
3531
  return value === "indeterminate" ? "ambiguous" : value;
3438
3532
  }
3439
- function controllerEffectState(value: string): EffectRecord["state"] {
3533
+ function resourceManagerEffectState(value: string): EffectRecord["state"] {
3440
3534
  return value === "ambiguous" ? "indeterminate" : (value as EffectRecord["state"]);
3441
3535
  }
3442
3536
  function validTimestamp(value?: string): string {