@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
@@ -0,0 +1,363 @@
1
+ ---
2
+ title: Unify workflow run state
3
+ author: Onur Solmaz <2453968+osolmaz@users.noreply.github.com>
4
+ date: 2026-09-04
5
+ status: implemented
6
+ ---
7
+
8
+ # Unify workflow run state
9
+
10
+ ## Goal
11
+
12
+ Several Pi Workflows failures appeared together after the out-of-process host change. A provider error left old workflow-turn ownership behind. A composed workflow reused an effect key. Restart treated a failed run as a checkpoint continuation. Terminal code read a text error as JSON. That read error blocked cancellation, while the host repeatedly started a worker that could not make progress.
13
+
14
+ These failures have the same architectural cause. Important facts are inferred in more than one place. Local node names stand in for compiled identities. A parent run ID stands in for the kind of child run. Callers guess the type of stored data. Process activity stands in for workflow progress. Presentation work can determine whether a control command commits.
15
+
16
+ The approved design gives each fact one owner and one typed path. The compiler and engine create execution identities. The host state store commits workflow state. A worker executes one explicit run command. The Pi extension delivers messages and reports public Pi events. Renderers display the host view.
17
+
18
+ This plan replaces the narrower workflow-turn ownership plan. It keeps that fix and adds the effect, restart, terminal-data, cancellation, and worker-retry work needed to remove the shared cause.
19
+
20
+ ## User requirements
21
+
22
+ - Use the most direct, long-term design instead of separate guards for each symptom.
23
+ - Keep one global out-of-process host as the normal state writer.
24
+ - Keep one client protocol and one production runtime.
25
+ - Use documented Pi extension APIs only.
26
+ - Do not change Pi core or Pi session schemas.
27
+ - Keep schema version 1 and make an alpha hard cut. Do not add migrations, compatibility readers, dual paths, fallbacks, or feature flags.
28
+ - Preserve strict ownership and uniqueness checks.
29
+ - Do not claim exactly-once behavior for model calls or external systems.
30
+ - A paused workflow must remain pausable and cancellable after any earlier run failure.
31
+
32
+ ## Confirmed causes
33
+
34
+ ### Composed effects lose their full node path
35
+
36
+ `manualEffect()` and `idempotentEffect()` derive a key from `state.currentNode`. Workflow composition projects the state into a child workflow before it evaluates that key. The projection changes a compiled path such as `documentation/workspace/inspect` back to the local name `inspect`.
37
+
38
+ The outer workspace check and the documentation workspace check therefore shared the run ID and visit number. They also shared the effect type and local node name. Their requests differed, so the effect store correctly rejected the second request with `Managed effect key was reused with another request`.
39
+
40
+ ### Restart uses checkpoint continuation
41
+
42
+ The run queue records whether a child is a `continuation` or a `restart`. The worker bootstrap receives only `parentRunId`. It calls `continueRun()` for every child with a parent.
43
+
44
+ `continueRun()` requires a parent that is waiting at a checkpoint. A failed terminal run does not meet that contract. A restart must begin at the workflow start with fresh graph and effect state.
45
+
46
+ ### A failed ancestor error is read with the wrong type
47
+
48
+ Run errors are stored as text. `terminalAncestorOutcomes()` reads an ancestor `error_hash` with `readJson()`. The blob exists, but its media type is text. The generic database error says that the JSON blob is missing or has the wrong media type.
49
+
50
+ Terminal-message creation calls this reader. As a result, the error can block child failure handling and cancellation.
51
+
52
+ ### A worker can restart forever without progress
53
+
54
+ When an uninitialized worker exits, the host parks and claims the same run again. The failed restart never changes its saved workflow revision, but the host keeps launching it. The UI reports `running` because a process is active even though the workflow makes no progress.
55
+
56
+ ### Presentation can roll back control state
57
+
58
+ Cancellation and terminal-message creation currently share a transaction path. If terminal-message creation cannot read its source data, the cancellation fails too. A display failure must not keep execution authority alive.
59
+
60
+ ## Design
61
+
62
+ ### Clear responsibilities
63
+
64
+ The compiler assigns complete node paths. The engine uses those paths to identify logical work. Child workflows can receive a local view of inputs and outputs, but that local view cannot replace the compiled identity.
65
+
66
+ The host state store owns every durable transition. Server orchestration code asks the store to start, pause, finish, cancel, or recover work. It does not update lifecycle tables directly.
67
+
68
+ The worker receives one explicit command and executes it. It does not infer the command from nullable fields.
69
+
70
+ The Pi extension keeps only temporary state for the current Pi turn. A host response decides whether that turn belongs to a workflow.
71
+
72
+ Renderers use the host view. They do not infer workflow progress from process presence, messages, or local timers.
73
+
74
+ ### Complete execution identity
75
+
76
+ Each logical node visit has a stable identity made from:
77
+
78
+ - the run ID;
79
+ - the full compiled node path;
80
+ - the visit number.
81
+
82
+ The visit number is the count for that exact compiled node path. A crash retry of the same unfinished visit keeps the same number. Re-entering the node later gets the next number.
83
+
84
+ The engine derives managed-effect identity from this logical node visit and the effect type. The projected child context is still used to calculate the effect request, but it is not used to calculate internal identity.
85
+
86
+ Workflow authors no longer provide the internal effect key. If an external API needs its own idempotency key, the action sends that external key as part of the request to that API. Internal execution identity and an external API key are separate facts.
87
+
88
+ The effect store keeps its request fingerprint check. Reusing one logical effect identity with a different request remains a hard conflict.
89
+
90
+ ### One run command
91
+
92
+ The host sends the worker one tagged command:
93
+
94
+ - `start` begins a root run.
95
+ - `resume` continues the same interrupted run from saved state.
96
+ - `continue` creates a child from an accepted waiting checkpoint.
97
+ - `restart` creates a fresh child after a terminal result.
98
+
99
+ The worker handles this command with one exhaustive switch. Invalid combinations fail before workflow code runs.
100
+
101
+ A restart uses the same approved workflow definition and requested input, but it begins at the first node. It does not copy parent steps, outputs, results, open interactions, settings mutations, or effect reservations. The parent run ID and root run ID remain saved as history. The saved history also includes the restart number and terminal fingerprint.
102
+
103
+ A continuation remains the only path that carries checkpoint state forward. It requires a waiting parent and the exact accepted decision or submission.
104
+
105
+ The engine should expose one internal entry point that accepts this tagged command. The superseded parent-ID heuristic is removed in the same alpha change.
106
+
107
+ ### One durable transition interface
108
+
109
+ The existing run store becomes the only interface used by host orchestration for durable run changes. It can use focused internal modules, but callers see typed operations rather than SQL or booleans.
110
+
111
+ The interface covers:
112
+
113
+ - starting and ending exact workflow turns;
114
+ - reserving and settling exact effects;
115
+ - starting, pausing, and resuming runs;
116
+ - finishing and timing out runs;
117
+ - cancelling runs;
118
+ - preparing continuations and restarts;
119
+ - recording worker failure and recovery state.
120
+
121
+ Each operation checks the run generation and claim token in one transaction. It also checks the expected revision and run state against the exact resource identity. It returns one of these results:
122
+
123
+ - `applied` with the new saved value;
124
+ - `adopted` with an equal saved value;
125
+ - `conflict` with the conflicting evidence;
126
+ - `recoveryRequired` with the saved reason.
127
+
128
+ A boolean result is not sufficient for a lifecycle change. Callers must know whether another path already completed the same change or whether the request conflicts with current state.
129
+
130
+ ### Workflow-turn ownership
131
+
132
+ `workflowTurn.report` remains the single version-1 operation for Pi model turns.
133
+
134
+ At Pi `agent_start`, the extension proposes the exact sent workflow message and a stable turn request ID. The host atomically returns an active turn or reports that no workflow owns the Pi turn. The extension starts workflow recording only after an active result.
135
+
136
+ At Pi `agent_end`, the extension ends the exact active turn. Matching repeated reports return the saved result. Conflicting evidence remains an error.
137
+
138
+ When a run becomes terminal, the same state transaction ends its remaining open turns as `lost` and cancels still-pending workflow messages. A late report cannot revive the run. If a connection closes at an uncertain point, the extension does not attach the next Pi turn. The existing branch and idle report lets the host settle an unproved open turn as `lost`.
139
+
140
+ ### Typed run data
141
+
142
+ Run input and final output are JSON. Run error and presentation instructions are text. Code reads them through named store methods:
143
+
144
+ - `readRunInput()`;
145
+ - `readRunFinalOutput()`;
146
+ - `readRunError()`;
147
+ - `readPresentationInstructions()`;
148
+ - `readTerminalFacts()`.
149
+
150
+ Callers do not read these blob hashes directly. `readTerminalFacts()` is the only source for terminal messages and ancestor outcomes. It checks media types and returns one typed result.
151
+
152
+ The underlying content-addressed blob store remains general. The run store owns the meaning of each run column.
153
+
154
+ ### Control state before presentation
155
+
156
+ Finishing or cancelling a run commits its execution state first. That transaction saves the final status and ends open turns. It cancels pending interactions and messages before it releases the claim. It also records the terminal facts needed for presentation.
157
+
158
+ Terminal Pi-message creation is an idempotent follow-up transition derived from those saved facts. A host restart can create a missing terminal message later. A presentation error is recorded for repair, but it cannot undo the terminal state or retain execution authority.
159
+
160
+ This separation applies to completion, failure, timeout, and cancellation.
161
+
162
+ ### Retry only after progress
163
+
164
+ Every worker launch records the run revision it received. A normal worker exit reports a typed outcome to the host. Known bootstrap and workflow errors include the phase and error text.
165
+
166
+ If a worker process disappears without a report, the host compares the current run revision with the launch revision. It may resume automatically only when durable progress or a saved recovery transition changed that revision.
167
+
168
+ If no revision changed, the host parks the run with the worker failure and stops automatic launch. The user can inspect, cancel, or explicitly resume it. This rule has no arbitrary retry count. The same unchanged state is never executed in a tight loop.
169
+
170
+ The display reports `running` only while one accepted worker or origin-session turn is doing current work. A parked no-progress failure reports its recovery reason.
171
+
172
+ ## State and protocol changes
173
+
174
+ This is an alpha hard cut in schema and protocol version 1. The implementation must not add a version-2 identifier or a compatibility path.
175
+
176
+ Expected changes include:
177
+
178
+ - a tagged worker run command in the existing worker protocol;
179
+ - full compiled node identity for managed effects;
180
+ - typed results for lifecycle transitions and turn reports;
181
+ - typed run-data readers;
182
+ - durable no-progress worker failure evidence if the existing event records cannot express it without inference.
183
+
184
+ Prefer existing tables and event records when they express the contract directly. If the durable no-progress rule requires a new column or constraint, change version-1 DDL in place. An old database then fails before mutation with the standard backup-and-reset instruction.
185
+
186
+ Existing structurally valid state can use normal terminal and idle-session reconciliation. Do not add migration code to repair old table shapes.
187
+
188
+ ## Implementation plan
189
+
190
+ ### Freeze the failures in tests
191
+
192
+ Add focused tests that reproduce the current behavior before changing it:
193
+
194
+ - Mount workspace preparation directly and again under documentation, then prove the current automatic effect key collides.
195
+ - Restart a failed workflow and prove the worker selects checkpoint continuation.
196
+ - Build terminal ancestry with a failed parent and prove ancestor reading uses the wrong media type.
197
+ - Cancel a child of a failed run and prove presentation failure rolls back cancellation.
198
+ - Crash an uninitialized worker without a revision change and prove the host repeatedly claims it.
199
+ - End a workflow turn during a terminal race and prove a later ordinary Pi turn can inherit old ownership.
200
+
201
+ The final versions of these tests must assert the corrected behavior. Do not preserve assertions for the defects.
202
+
203
+ ### Move execution identity into the engine
204
+
205
+ Change managed-effect identity in `src/workflows/definition.ts`, `src/workflows/composition.ts`, `src/workflows/engine.ts`, and the related types.
206
+
207
+ The compiled engine passes the full node path and visit number to effect reservation. Child-context projection remains limited to workflow-authored request and action functions. Remove the old automatic key calculation from projected `state.currentNode`.
208
+
209
+ Update authoring docs and all built-in workflows in the same change. Keep no alias for the old internal key contract.
210
+
211
+ ### Make worker commands explicit
212
+
213
+ Add the tagged run command to `src/server/workflow-runner-protocol.ts`, the host bootstrap response, and `src/server/workflow-runner-entry.ts`.
214
+
215
+ Replace the `initialized` and `parentRunId` dispatch heuristic with an exhaustive command switch. Add the engine path for a fresh restart and keep checkpoint continuation separate. Remove the superseded dispatch code.
216
+
217
+ ### Centralize durable transitions
218
+
219
+ Move direct lifecycle SQL from `src/server/runner.ts` into typed store operations in the state and workflow-store modules. Replace ambiguous boolean returns used by run failure and cancellation with typed results.
220
+
221
+ Keep claim fencing and revision checks in each state transaction. The runner handles process supervision and protocol routing only.
222
+
223
+ ### Fix terminal state and cancellation
224
+
225
+ Add the typed run-data readers and use `readTerminalFacts()` for the current result and every ancestor result. Remove direct JSON reads of error hashes.
226
+
227
+ Commit terminal control state independently from terminal-message creation. Add idempotent reconciliation for a terminal run that has no terminal workflow message.
228
+
229
+ After this change, the currently paused failed-child case must cancel without a database reset.
230
+
231
+ ### Finish workflow-turn ownership
232
+
233
+ Implement the approved host-owned turn contract in the state store and host runner. Apply it to the extension coordinator and session view. Then connect it to recorder integration.
234
+
235
+ A terminal run must have no open workflow turn. A later ordinary Pi turn must produce no workflow-turn report for the terminal run.
236
+
237
+ ### Stop no-progress worker loops
238
+
239
+ Add structured worker exit reports for all caught bootstrap and execution failures. Save the launch revision and compare it on an unreported exit.
240
+
241
+ Park an unchanged run with a clear recovery reason. Resume automatically only after a newer durable revision makes another launch meaningful.
242
+
243
+ ### Remove old paths
244
+
245
+ Delete:
246
+
247
+ - effect keys derived from projected local node names;
248
+ - restart dispatch based only on `parentRunId`;
249
+ - direct error-hash JSON reads;
250
+ - lifecycle SQL in host orchestration where a typed store operation replaces it;
251
+ - cancellation paths that depend on successful terminal presentation;
252
+ - automatic relaunch of the same unchanged worker state;
253
+ - extension turn ownership that has not been accepted by the host.
254
+
255
+ Do not keep feature flags or fallback behavior.
256
+
257
+ ### Update documentation
258
+
259
+ Update `WORKFLOW_SERVER.md`, `SQLITE_STATE.md`, and `workflows.md` after implementation so they describe the shipped interfaces and recovery behavior. Keep this plan as the decision and implementation record.
260
+
261
+ ## Tests
262
+
263
+ ### Composition and effects
264
+
265
+ - Two mounts of the same action receive different full execution identities.
266
+ - A crash retry of one unfinished node visit reuses its identity.
267
+ - A later loop visit receives a new identity.
268
+ - The same identity and request adopts the saved effect.
269
+ - The same identity with another request returns a controlled conflict.
270
+
271
+ ### Run commands
272
+
273
+ - Root start begins at the first node.
274
+ - Resume uses the same run and saved current node.
275
+ - Continuation accepts only a waiting checkpoint parent and carries the approved state.
276
+ - Restart accepts a terminal parent and begins with no parent steps, outputs, results, or effects.
277
+ - Invalid command and state combinations fail before workflow code runs.
278
+
279
+ ### Terminal state
280
+
281
+ - Completed, failed, timed-out, and cancelled ancestors produce typed terminal facts.
282
+ - A text error is never passed to `readJson()`.
283
+ - Cancellation commits even when terminal presentation is forced to fail.
284
+ - A later reconciliation creates the missing terminal message once.
285
+ - Terminalization ends open turns and pending interactions in the same state transaction.
286
+
287
+ ### Runner recovery
288
+
289
+ - A worker crash after a newer durable revision resumes safely.
290
+ - A worker crash at the same revision parks once and does not relaunch.
291
+ - A known bootstrap error becomes a saved failure instead of a process loop.
292
+ - The widget and `piw` show the same parked reason.
293
+
294
+ ### Pi turn ownership
295
+
296
+ - A provider error ends the exact accepted turn.
297
+ - Repeated and reordered reports return saved results or controlled conflicts.
298
+ - A terminal race cannot leave an open turn.
299
+ - Reconnect settles an unproved turn as `lost`.
300
+ - A later ordinary Pi message creates no workflow turn or workflow recorder.
301
+
302
+ ### Full regression
303
+
304
+ Run Autoimplement with its direct workspace preparation and nested Autodoc workspace preparation. Force the first run to fail after a managed action. Restart it and then pause and cancel it. Prove that effect identities do not collide and restart begins cleanly. Also prove that terminal facts remain readable and cancellation commits without a worker loop.
305
+
306
+ Automated tests use temporary directories and deterministic providers. They do not call a real model.
307
+
308
+ ## Acceptance criteria
309
+
310
+ - One component owns each identity and state decision.
311
+ - Included workflows cannot collide because they share local node names.
312
+ - Restart and checkpoint continuation cannot enter each other's engine path.
313
+ - Every run column is read with its declared data type.
314
+ - Control commands remain effective when presentation fails.
315
+ - A worker cannot relaunch unchanged state indefinitely.
316
+ - A terminal run has no open workflow turn.
317
+ - Later ordinary Pi turns cannot attach to terminal workflow work.
318
+ - No raw SQLite uniqueness or media-type error reaches normal recovery paths.
319
+ - Server, extension, widget, CLI, Herdr, and `piw` agree on run activity.
320
+ - Pi core and private Pi APIs remain unchanged. Pi session schemas also remain unchanged.
321
+ - One host and one database remain. The system keeps one client protocol and one production runtime.
322
+
323
+ ## Verification
324
+
325
+ Run:
326
+
327
+ ```bash
328
+ npm run check
329
+ npm run test:e2e
330
+ npm run test:e2e:live -- --runtime-only
331
+ git diff --check
332
+ npx slophammer-ts@latest dry .
333
+ npx slophammer-ts@latest check . --only ts.dependency-boundaries-required
334
+ npx -y @simpledoc/simpledoc check
335
+ cargo test --manifest-path tui/Cargo.toml
336
+ cargo clippy --manifest-path tui/Cargo.toml --all-targets --all-features -- -D warnings
337
+ cargo fmt --manifest-path tui/Cargo.toml --check
338
+ ```
339
+
340
+ After deterministic checks pass, install the built package locally. Run a clean no-op workflow. Then run the composed Autoimplement regression and a forced provider-error recovery check. Confirm the widget and `piw` status at each stage. Use a real model only for the final manual installed-package check, with an explicit provider and model selected by the operator.
341
+
342
+ Run Pi Reviewer against `main` until no P0 or P1 finding remains. Check pull-request comments and CI before merge.
343
+
344
+ ## Scope
345
+
346
+ The implementation may change Pi Workflows engine, compiler, worker protocol, host state methods, extension coordination, viewer projection, built-in workflows, tests, and documentation in this repository.
347
+
348
+ ## Non-goals
349
+
350
+ - No Pi core or private Pi API changes.
351
+ - No Pi session schema changes.
352
+ - No new service, database, state root, or production runtime.
353
+ - No operating-system service installation.
354
+ - No migration or compatibility path for older alpha state.
355
+ - No release or package publication as part of implementation.
356
+ - No exactly-once claim for provider calls or external effects.
357
+
358
+ ## Assumptions
359
+
360
+ - Pi continues to provide the documented extension lifecycle events and session APIs.
361
+ - The host remains the only production process that opens live SQLite state.
362
+ - A package update can require the documented backup and reset when version-1 DDL changes.
363
+ - External systems remain responsible for their own stable idempotency keys or read-back checks.
@@ -1,6 +1,6 @@
1
1
  # Terminal workflow messages
2
2
 
3
- This specification defines the final Pi message for an interactive workflow. It replaces the separate deferred-turn and `workflow_turn_intents` design. Terminal messages use the same host state, client operations, and extension coordinator as all other [workflow messages](WORKFLOW_STEP_MESSAGES.md).
3
+ This specification defines the final Pi message for an interactive workflow. It replaces the separate deferred-turn and `workflow_turn_intents` design. Terminal messages use the same server state, client operations, and extension coordinator as all other [workflow messages](WORKFLOW_STEP_MESSAGES.md).
4
4
 
5
5
  The earlier [deferred-turn plan](plans/2026-08-21-deferred-turn-intents-plan.md) and [terminal restart plan](plans/2026-08-27-workflow-terminal-restart-plan.md) remain historical design records. This document is the current contract.
6
6
 
@@ -14,7 +14,7 @@ The earlier [deferred-turn plan](plans/2026-08-21-deferred-turn-intents-plan.md)
14
14
 
15
15
  ## Core rule
16
16
 
17
- The host creates one `terminal` workflow message in the same transaction that records the final terminal outcome. Only the final run in a continuation chain creates this message. A parent settled by a continuation does not create one.
17
+ The server creates one `terminal` workflow message in the same transaction that records the final terminal outcome. Only the final run in a continuation chain creates this message. A parent settled by a continuation does not create one.
18
18
 
19
19
  The terminal message uses the same `workflow_messages` table and `WorkflowMessageCoordinator` as steps, decisions, notifications, and follow-ups. Initial, reminder, and resumed prompts are one step-message kind. There is no `workflow_turn_intents` table, deferred-turn sender, terminal sender, or second send path.
20
20
 
@@ -28,9 +28,9 @@ A terminal message can report:
28
28
  - workflow failure;
29
29
  - timeout with no recovery edge;
30
30
  - cancellation;
31
- - launch or worker failure that became the final run outcome.
31
+ - launch or runner failure that became the final run outcome.
32
32
 
33
- Pause, Escape, a waiting checkpoint, a nonfinal continuation parent, user hold, and normal host shutdown do not create a terminal message.
33
+ Pause, Escape, a waiting checkpoint, a nonfinal continuation parent, user hold, and normal server shutdown do not create a terminal message.
34
34
 
35
35
  A claim loss is a handoff. It creates no terminal outcome or terminal message unless later recovery proves that the run itself failed.
36
36
 
@@ -48,15 +48,15 @@ A terminal workflow message is open only until its first model turn ends. The ex
48
48
 
49
49
  The end report includes `stopReason: "completed"`, `"aborted"`, or `"error"`. Response-entry evidence comes from `ctx.sessionManager.getBranch()` after `agent_end` and can be null. A repeated report adopts the stored result. A stale turn ID cannot end a newer turn.
50
50
 
51
- If Pi restarts after a terminal message was sent but before its end was reported, the extension's idle-session active-branch report records a synthetic end with `stopReason: "lost"`. Host restart alone does not close the turn. The terminal result remains durable and visible, but the host does not pretend that the model turn completed.
51
+ If Pi restarts after a terminal message was sent but before its end was reported, the extension's idle-session active-branch report records a synthetic end with `stopReason: "lost"`. Server restart alone does not close the turn. The terminal result remains durable and visible, but the server does not pretend that the model turn completed.
52
52
 
53
53
  ## Sending and recovery
54
54
 
55
- After every host connection, the coordinator waits for the complete origin-session view and reports the active branch before it sends a workflow message or reports a model turn. The host gives the next eligible pending message only to the active coordinator epoch for that session. A replacement connection fences the old one.
55
+ After every server connection, the coordinator waits for the complete origin-session view and reports the active branch before it sends a workflow message or reports a model turn. The server gives the next eligible pending message only to the active coordinator epoch for that session. A replacement connection fences the old one.
56
56
 
57
57
  The coordinator waits until Pi is idle and has no pending messages. It keeps the terminal workflow message ID in its in-memory queued map, checks the active branch, and reports a matching entry before any send. Otherwise, it performs one final synchronous check that Pi is idle, has no pending input, the message is absent, and its connection still owns the active epoch. It calls documented `pi.sendMessage()` without an `await` between that check and the call.
58
58
 
59
- A matching hidden workflow message ID in the active branch proves that Pi accepted the message. The host records the matching Pi entry ID and changes the message to `sent`, even if its source cancelled it after the send. If the extension reloads, it reports the active branch and adopts that entry before another send.
59
+ A matching hidden workflow message ID in the active branch proves that Pi accepted the message. The server records the matching Pi entry ID and changes the message to `sent`, even if its source cancelled it after the send. If the extension reloads, it reports the active branch and adopts that entry before another send.
60
60
 
61
61
  Absence is usable only when all three facts are true:
62
62
 
@@ -38,7 +38,7 @@ Reading shared state never gives mutation authority. Every durable write checks
38
38
 
39
39
  ## Boundaries
40
40
 
41
- The workflow engine stays independent of Pi. The Pi extension hosts the engine and connects it to a conversation. Controllers manage durable external resources. Viewers read recorded state without changing it.
41
+ The workflow engine stays independent of Pi. The Pi extension servers the engine and connects it to a conversation. Controllers manage durable external resources. Viewers read recorded state without changing it.
42
42
 
43
43
  Keep these layers separate and connect them through small public interfaces.
44
44
 
@@ -168,7 +168,7 @@ The accepted human sources are:
168
168
  - the Pi interactive decision view; and
169
169
  - a configured external decision channel such as Telegram.
170
170
 
171
- The host assigns the source. A workflow or model cannot claim that an answer came from a person. Pi non-interactive modes can wait for Telegram, but they cannot manufacture a Pi UI answer.
171
+ The server assigns the source. A workflow or model cannot claim that an answer came from a person. Pi non-interactive modes can wait for Telegram, but they cannot manufacture a Pi UI answer.
172
172
 
173
173
  ## Audiences and channel profiles
174
174
 
@@ -199,7 +199,7 @@ Private configuration maps the audience to channels:
199
199
  }
200
200
  ```
201
201
 
202
- The workflow never receives a bot token, user ID, chat ID, Telegram message ID, or Pi session detail. Channel profiles are private host configuration and are excluded from run presentation.
202
+ The workflow never receives a bot token, user ID, chat ID, Telegram message ID, or Pi session detail. Channel profiles are private server configuration and are excluded from run presentation.
203
203
 
204
204
  pi-workflows keeps credential references in a separate private file. A Telegram credential points to an existing absolute mode-`0600` token file:
205
205
 
@@ -222,7 +222,7 @@ The same Unix account can read a local credential file. This design prevents acc
222
222
 
223
223
  ## Channel interface
224
224
 
225
- The host owns decision state and launches each external channel adapter as a supervised child process. The private child protocol has these message kinds:
225
+ The server owns decision state and launches each external channel adapter as a supervised child process. The private child protocol has these message kinds:
226
226
 
227
227
  - `channel.ready`;
228
228
  - `channel.present`;
@@ -230,15 +230,15 @@ The host owns decision state and launches each external channel adapter as a sup
230
230
  - `channel.settle`; and
231
231
  - `channel.exiting`.
232
232
 
233
- Each message names the adapter epoch, channel profile, saved request or settlement record, expected revision, and stable attempt ID. The host validates and saves every state change. The child never opens SQLite, loads workflow code, changes a run directly, receives the canonical decision subject, or receives another channel's credentials.
233
+ Each message names the adapter epoch, channel profile, saved request or settlement record, expected revision, and stable attempt ID. The server validates and saves every state change. The child never opens SQLite, loads workflow code, changes a run directly, receives the canonical decision subject, or receives another channel's credentials.
234
234
 
235
235
  Channel handling is independent from workflow routing. A failed Telegram send leaves the decision available in Pi. Audience policy decides whether one successful channel is enough or whether all configured channels must receive the request.
236
236
 
237
237
  ### Pi channel
238
238
 
239
- The host creates one `decision` workflow message for the origin session. The shared extension coordinator shows it through documented `pi.sendMessage()` with no model turn. The message lists the request ID, choices, input rule, and deadline. It uses no blocking Pi dialog and no private Pi API.
239
+ The server creates one `decision` workflow message for the origin session. The shared extension coordinator shows it through documented `pi.sendMessage()` with no model turn. The message lists the request ID, choices, input rule, and deadline. It uses no blocking Pi dialog and no private Pi API.
240
240
 
241
- A verified operator answers with `/workflow answer` or the matching `piw` control. The host validates the choice and optional text, records the Pi channel as the source, and accepts only the first valid winner. Closing or reloading Pi cannot lose the request. On `session_start` or `session_tree`, the extension adopts an existing decision message or creates one new `decision` message when the pending request has no entry on the active branch.
241
+ A verified operator answers with `/workflow answer` or the matching `piw` control. The server validates the choice and optional text, records the Pi channel as the source, and accepts only the first valid winner. Closing or reloading Pi cannot lose the request. On `session_start` or `session_tree`, the extension adopts an existing decision message or creates one new `decision` message when the pending request has no entry on the active branch.
242
242
 
243
243
  ### Telegram channel
244
244
 
@@ -252,11 +252,11 @@ A choice without input submits from its button. A text choice such as `replan` w
252
252
  4. the adapter verifies the numeric user ID, chat ID, reply message ID, decision ID, and request digest; and
253
253
  5. the exact received text becomes `input.instructions`.
254
254
 
255
- The adapter does not infer a choice from ordinary chat text. Callback payloads contain short opaque IDs because Telegram limits callback data. The host's channel records map each opaque ID to the validated decision request. Credentials remain outside the database and reach only the matching supervised adapter child.
255
+ The adapter does not infer a choice from ordinary chat text. Callback payloads contain short opaque IDs because Telegram limits callback data. The server's channel records map each opaque ID to the validated decision request. Credentials remain outside the database and reach only the matching supervised adapter child.
256
256
 
257
- Telegram permits one long-polling consumer for a bot profile. The global host starts at most one adapter child for that profile and keeps the package-owned on-demand host process alive while an external decision is pending. No Pi process or adapter child owns a SQLite lease. If the host stops, the next Pi, CLI, or `piw` client starts it and the host recovers the saved channel state before it starts another adapter child. This design installs no operating-system service.
257
+ Telegram permits one long-polling consumer for a bot profile. The global server starts at most one adapter child for that profile and keeps the package-owned on-demand server process alive while an external decision is pending. No Pi process or adapter child owns a SQLite lease. If the server stops, the next Pi, CLI, or `piw` client starts it and the server recovers the saved channel state before it starts another adapter child. This design installs no operating-system service.
258
258
 
259
- The Bot API does not provide an idempotency key for `sendMessage`. Before it tells the adapter to send or settle a message, the host records the exact attempt in `effects` and `effect_attempts`. A confirmed Telegram message ID settles the effect and remains in its result. A timed-out, disconnected, or interrupted exact attempt with no proof becomes `ambiguous` and is not retried automatically. Pi remains available while the operator checks Telegram and explicitly confirms or retries the operation. This prevents blind duplicate sends without claiming exactly-once Telegram behavior.
259
+ The Bot API does not provide an idempotency key for `sendMessage`. Before it tells the adapter to send or settle a message, the server records the exact attempt in `effects` and `effect_attempts`. A confirmed Telegram message ID settles the effect and remains in its result. A timed-out, disconnected, or interrupted exact attempt with no proof becomes `ambiguous` and is not retried automatically. Pi remains available while the operator checks Telegram and explicitly confirms or retries the operation. This prevents blind duplicate sends without claiming exactly-once Telegram behavior.
260
260
 
261
261
  ## Durable decision records
262
262
 
@@ -328,7 +328,7 @@ Adoption does not change the lease, claim generation, queue state, timestamps, o
328
328
 
329
329
  This alpha change updates the current request, accepted-result, receipt, resolution, continuation, and snapshot contracts in place. Old active runs refuse resume through normal source and definition identity checks. There is no compatibility reader, migration, dual path, or new schema generation. The continuation startup fix uses existing queue and lease records. It adds no field, table, migration, or schema version. Existing compatible prepared or initialized continuations are adopted. Updated viewers label a human decision as a checkpoint, show its deadline and automatic action when present, and keep the canonical subject separate. Private channel configuration and transport identifiers remain hidden.
330
330
 
331
- The engine remains independent from Pi and Telegram. Core code owns decision contracts and validation. The host owns durable acceptance, continuation, workflow messages, and channel-child supervision. The Pi extension owns documented session presentation and controls. The Telegram adapter child owns Bot API translation. Workflow definitions own only the question, choices, audience, and routes.
331
+ The engine remains independent from Pi and Telegram. Core code owns decision contracts and validation. The server owns durable acceptance, continuation, workflow messages, and channel-child supervision. The Pi extension owns documented session presentation and controls. The Telegram adapter child owns Bot API translation. Workflow definitions own only the question, choices, audience, and routes.
332
332
 
333
333
  ## Contract impact
334
334
 
@@ -360,7 +360,7 @@ The implementation must test:
360
360
  - identical and conflicting retries;
361
361
  - crashes before and after answer acceptance and continuation creation;
362
362
  - ambiguous Telegram sends;
363
- - one supervised long-poll adapter per profile and host-restart recovery;
363
+ - one supervised long-poll adapter per profile and server-restart recovery;
364
364
  - decision cancellation and expiry;
365
365
  - included `plan-approval` routes and bounded replan loops;
366
366
  - viewer redaction; and
@@ -59,7 +59,7 @@ A request uses `pi-workflows.human-decision-request.v1`. It contains:
59
59
  | `title` | Yes | Short decision title shown by every channel. |
60
60
  | `subject` | Yes | Canonical JSON data used by the workflow. |
61
61
  | `presentation` | Yes | Human-readable content defined below. |
62
- | `audience` | Yes | Named audience resolved by the host. |
62
+ | `audience` | Yes | Named audience resolved by the server. |
63
63
  | `choices` | Yes | Typed choices and optional input contracts. |
64
64
  | `revision` | Yes | Positive decision revision. |
65
65
  | `subjectDigest` | Yes | SHA-256 digest of the canonical subject. |
@@ -216,13 +216,13 @@ The renderer:
216
216
 
217
217
  The renderer never adds an ellipsis in place of omitted decision content.
218
218
 
219
- The host saves each channel message before the adapter sends it. It records each part after an unambiguous response. If a send result is uncertain, the host marks that channel message `ambiguous` and does not retry that part or later parts automatically. Another configured channel can still answer the decision.
219
+ The server saves each channel message before the adapter sends it. It records each part after an unambiguous response. If a send result is uncertain, the server marks that channel message `ambiguous` and does not retry that part or later parts automatically. Another configured channel can still answer the decision.
220
220
 
221
221
  ### Pi
222
222
 
223
- The host creates one `decision` workflow message. The shared extension coordinator sends it through documented `pi.sendMessage()` without starting a model turn. Its custom renderer shows the complete presentation and fingerprint with the choices, input rules, request ID, and deadline. It wraps and scrolls with normal Pi custom-message behavior.
223
+ The server creates one `decision` workflow message. The shared extension coordinator sends it through documented `pi.sendMessage()` without starting a model turn. Its custom renderer shows the complete presentation and fingerprint with the choices, input rules, request ID, and deadline. It wraps and scrolls with normal Pi custom-message behavior.
224
224
 
225
- A verified operator answers through `/workflow answer` or the matching `piw` control. When Telegram or another channel accepts the decision, the host cancels an unsent Pi decision message. A sent card remains normal conversation history, while later answer controls return the saved winner. Pi Workflows does not open a blocking dialog, modify Pi core, or use undocumented TUI state.
225
+ A verified operator answers through `/workflow answer` or the matching `piw` control. When Telegram or another channel accepts the decision, the server cancels an unsent Pi decision message. A sent card remains normal conversation history, while later answer controls return the saved winner. Pi Workflows does not open a blocking dialog, modify Pi core, or use undocumented TUI state.
226
226
 
227
227
  ### Other channels
228
228
 
package/docs/MONITOR.md CHANGED
@@ -125,7 +125,7 @@ The action step returns whether the action succeeded, failed, or was blocked, wi
125
125
 
126
126
  The repair input preserves the action request, target evidence, authority, constraints, repository, and delivery limits. Existing plan approval rules still apply when the recorded contract requires them.
127
127
 
128
- Paid workers affected by a shared code or data defect must stop at safe boundaries before repair starts. Monitor preserves their durable outputs and failure evidence.
128
+ Paid runners affected by a shared code or data defect must stop at safe boundaries before repair starts. Monitor preserves their durable outputs and failure evidence.
129
129
 
130
130
  After a completed repair, Monitor runs `observe` immediately. If the same failure ID and target-state ID return, Monitor stops. It does not run the same repair cycle again.
131
131