@smthrs/control 0.0.0-stage → 1.0.0-rc.4

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 (418) hide show
  1. package/CHANGELOG.md +194 -0
  2. package/LICENSE +21 -0
  3. package/README.md +168 -2
  4. package/dist/cjs/ApprovalAuthority.d.ts +73 -0
  5. package/dist/cjs/ApprovalAuthority.d.ts.map +1 -0
  6. package/dist/cjs/ApprovalAuthority.js +62 -0
  7. package/dist/cjs/ApprovalAuthority.js.map +7 -0
  8. package/dist/cjs/Cancellation.d.ts +107 -0
  9. package/dist/cjs/Cancellation.d.ts.map +1 -0
  10. package/dist/cjs/Cancellation.js +72 -0
  11. package/dist/cjs/Cancellation.js.map +7 -0
  12. package/dist/cjs/Channels.d.ts +170 -0
  13. package/dist/cjs/Channels.d.ts.map +1 -0
  14. package/dist/cjs/Channels.js +278 -0
  15. package/dist/cjs/Channels.js.map +7 -0
  16. package/dist/cjs/Control.d.ts +202 -0
  17. package/dist/cjs/Control.d.ts.map +1 -0
  18. package/dist/cjs/Control.js +47 -0
  19. package/dist/cjs/Control.js.map +7 -0
  20. package/dist/cjs/ControlClient.d.ts +52 -0
  21. package/dist/cjs/ControlClient.d.ts.map +1 -0
  22. package/dist/cjs/ControlClient.js +191 -0
  23. package/dist/cjs/ControlClient.js.map +7 -0
  24. package/dist/cjs/ControlError.d.ts +318 -0
  25. package/dist/cjs/ControlError.d.ts.map +1 -0
  26. package/dist/cjs/ControlError.js +249 -0
  27. package/dist/cjs/ControlError.js.map +7 -0
  28. package/dist/cjs/ControlExecutor.d.ts +372 -0
  29. package/dist/cjs/ControlExecutor.d.ts.map +1 -0
  30. package/dist/cjs/ControlExecutor.js +123 -0
  31. package/dist/cjs/ControlExecutor.js.map +7 -0
  32. package/dist/cjs/ControlFacts.d.ts +454 -0
  33. package/dist/cjs/ControlFacts.d.ts.map +1 -0
  34. package/dist/cjs/ControlFacts.js +261 -0
  35. package/dist/cjs/ControlFacts.js.map +7 -0
  36. package/dist/cjs/ControlLive.d.ts +23 -0
  37. package/dist/cjs/ControlLive.d.ts.map +1 -0
  38. package/dist/cjs/ControlLive.js +1293 -0
  39. package/dist/cjs/ControlLive.js.map +7 -0
  40. package/dist/cjs/ControlRpcs.d.ts +1204 -0
  41. package/dist/cjs/ControlRpcs.d.ts.map +1 -0
  42. package/dist/cjs/ControlRpcs.js +247 -0
  43. package/dist/cjs/ControlRpcs.js.map +7 -0
  44. package/dist/cjs/ControlRuntime.d.ts +635 -0
  45. package/dist/cjs/ControlRuntime.d.ts.map +1 -0
  46. package/dist/cjs/ControlRuntime.js +744 -0
  47. package/dist/cjs/ControlRuntime.js.map +7 -0
  48. package/dist/cjs/ControlSchema.d.ts +2642 -0
  49. package/dist/cjs/ControlSchema.d.ts.map +1 -0
  50. package/dist/cjs/ControlSchema.js +634 -0
  51. package/dist/cjs/ControlSchema.js.map +7 -0
  52. package/dist/cjs/ControlServer.d.ts +51 -0
  53. package/dist/cjs/ControlServer.d.ts.map +1 -0
  54. package/dist/cjs/ControlServer.js +121 -0
  55. package/dist/cjs/ControlServer.js.map +7 -0
  56. package/dist/cjs/Credential.d.ts +136 -0
  57. package/dist/cjs/Credential.d.ts.map +1 -0
  58. package/dist/cjs/Credential.js +168 -0
  59. package/dist/cjs/Credential.js.map +7 -0
  60. package/dist/cjs/CredentialCipher.d.ts +90 -0
  61. package/dist/cjs/CredentialCipher.d.ts.map +1 -0
  62. package/dist/cjs/CredentialCipher.js +45 -0
  63. package/dist/cjs/CredentialCipher.js.map +7 -0
  64. package/dist/cjs/CredentialStore.d.ts +97 -0
  65. package/dist/cjs/CredentialStore.d.ts.map +1 -0
  66. package/dist/cjs/CredentialStore.js +81 -0
  67. package/dist/cjs/CredentialStore.js.map +7 -0
  68. package/dist/cjs/DispatchReader.d.ts +112 -0
  69. package/dist/cjs/DispatchReader.d.ts.map +1 -0
  70. package/dist/cjs/DispatchReader.js +45 -0
  71. package/dist/cjs/DispatchReader.js.map +7 -0
  72. package/dist/cjs/Health.d.ts +333 -0
  73. package/dist/cjs/Health.d.ts.map +1 -0
  74. package/dist/cjs/Health.js +311 -0
  75. package/dist/cjs/Health.js.map +7 -0
  76. package/dist/cjs/JevSessionChecker.d.ts +57 -0
  77. package/dist/cjs/JevSessionChecker.d.ts.map +1 -0
  78. package/dist/cjs/JevSessionChecker.js +113 -0
  79. package/dist/cjs/JevSessionChecker.js.map +7 -0
  80. package/dist/cjs/Lineage.d.ts +131 -0
  81. package/dist/cjs/Lineage.d.ts.map +1 -0
  82. package/dist/cjs/Lineage.js +81 -0
  83. package/dist/cjs/Lineage.js.map +7 -0
  84. package/dist/cjs/Migrations.d.ts +34 -0
  85. package/dist/cjs/Migrations.d.ts.map +1 -0
  86. package/dist/cjs/Migrations.js +60 -0
  87. package/dist/cjs/Migrations.js.map +7 -0
  88. package/dist/cjs/Monitor.d.ts +282 -0
  89. package/dist/cjs/Monitor.d.ts.map +1 -0
  90. package/dist/cjs/Monitor.js +283 -0
  91. package/dist/cjs/Monitor.js.map +7 -0
  92. package/dist/cjs/ScopedToken.d.ts +193 -0
  93. package/dist/cjs/ScopedToken.d.ts.map +1 -0
  94. package/dist/cjs/ScopedToken.js +135 -0
  95. package/dist/cjs/ScopedToken.js.map +7 -0
  96. package/dist/cjs/SqlControlRuntime.d.ts +161 -0
  97. package/dist/cjs/SqlControlRuntime.d.ts.map +1 -0
  98. package/dist/cjs/SqlControlRuntime.js +1522 -0
  99. package/dist/cjs/SqlControlRuntime.js.map +7 -0
  100. package/dist/cjs/SqlCredentialStore.d.ts +43 -0
  101. package/dist/cjs/SqlCredentialStore.d.ts.map +1 -0
  102. package/dist/cjs/SqlCredentialStore.js +113 -0
  103. package/dist/cjs/SqlCredentialStore.js.map +7 -0
  104. package/dist/cjs/Steering.d.ts +69 -0
  105. package/dist/cjs/Steering.d.ts.map +1 -0
  106. package/dist/cjs/Steering.js +49 -0
  107. package/dist/cjs/Steering.js.map +7 -0
  108. package/dist/cjs/SystemFlows.d.ts +223 -0
  109. package/dist/cjs/SystemFlows.d.ts.map +1 -0
  110. package/dist/cjs/SystemFlows.js +195 -0
  111. package/dist/cjs/SystemFlows.js.map +7 -0
  112. package/dist/cjs/WebCryptoCipher.d.ts +49 -0
  113. package/dist/cjs/WebCryptoCipher.d.ts.map +1 -0
  114. package/dist/cjs/WebCryptoCipher.js +129 -0
  115. package/dist/cjs/WebCryptoCipher.js.map +7 -0
  116. package/dist/cjs/WebhookChannel.d.ts +113 -0
  117. package/dist/cjs/WebhookChannel.d.ts.map +1 -0
  118. package/dist/cjs/WebhookChannel.js +98 -0
  119. package/dist/cjs/WebhookChannel.js.map +7 -0
  120. package/dist/cjs/index.d.ts +160 -0
  121. package/dist/cjs/index.d.ts.map +1 -0
  122. package/dist/cjs/index.js +91 -0
  123. package/dist/cjs/index.js.map +7 -0
  124. package/dist/cjs/internal/MutationBoundary.d.ts +27 -0
  125. package/dist/cjs/internal/MutationBoundary.d.ts.map +1 -0
  126. package/dist/cjs/internal/MutationBoundary.js +50 -0
  127. package/dist/cjs/internal/MutationBoundary.js.map +7 -0
  128. package/dist/cjs/internal/activeFibers.d.ts +12 -0
  129. package/dist/cjs/internal/activeFibers.d.ts.map +1 -0
  130. package/dist/cjs/internal/activeFibers.js +30 -0
  131. package/dist/cjs/internal/activeFibers.js.map +7 -0
  132. package/dist/cjs/internal/issues.d.ts +28 -0
  133. package/dist/cjs/internal/issues.d.ts.map +1 -0
  134. package/dist/cjs/internal/issues.js +34 -0
  135. package/dist/cjs/internal/issues.js.map +7 -0
  136. package/dist/cjs/internal/planning.d.ts +347 -0
  137. package/dist/cjs/internal/planning.d.ts.map +1 -0
  138. package/dist/cjs/internal/planning.js +137 -0
  139. package/dist/cjs/internal/planning.js.map +7 -0
  140. package/dist/cjs/internal/sqlSchemaErrors.d.ts +18 -0
  141. package/dist/cjs/internal/sqlSchemaErrors.d.ts.map +1 -0
  142. package/dist/cjs/internal/sqlSchemaErrors.js +40 -0
  143. package/dist/cjs/internal/sqlSchemaErrors.js.map +7 -0
  144. package/dist/cjs/migrations/0001_control_tables.d.ts +18 -0
  145. package/dist/cjs/migrations/0001_control_tables.d.ts.map +1 -0
  146. package/dist/cjs/migrations/0001_control_tables.js +115 -0
  147. package/dist/cjs/migrations/0001_control_tables.js.map +7 -0
  148. package/dist/cjs/migrations/0002_run_keys.d.ts +15 -0
  149. package/dist/cjs/migrations/0002_run_keys.d.ts.map +1 -0
  150. package/dist/cjs/migrations/0002_run_keys.js +44 -0
  151. package/dist/cjs/migrations/0002_run_keys.js.map +7 -0
  152. package/dist/cjs/migrations/0003_signal_commands.d.ts +13 -0
  153. package/dist/cjs/migrations/0003_signal_commands.d.ts.map +1 -0
  154. package/dist/cjs/migrations/0003_signal_commands.js +50 -0
  155. package/dist/cjs/migrations/0003_signal_commands.js.map +7 -0
  156. package/dist/cjs/migrations/0004_approval_decisions.d.ts +13 -0
  157. package/dist/cjs/migrations/0004_approval_decisions.d.ts.map +1 -0
  158. package/dist/cjs/migrations/0004_approval_decisions.js +45 -0
  159. package/dist/cjs/migrations/0004_approval_decisions.js.map +7 -0
  160. package/dist/cjs/migrations/0005_signal_principals.d.ts +18 -0
  161. package/dist/cjs/migrations/0005_signal_principals.d.ts.map +1 -0
  162. package/dist/cjs/migrations/0005_signal_principals.js +45 -0
  163. package/dist/cjs/migrations/0005_signal_principals.js.map +7 -0
  164. package/dist/cjs/migrations/0006_run_principals.d.ts +18 -0
  165. package/dist/cjs/migrations/0006_run_principals.d.ts.map +1 -0
  166. package/dist/cjs/migrations/0006_run_principals.js +49 -0
  167. package/dist/cjs/migrations/0006_run_principals.js.map +7 -0
  168. package/dist/cjs/migrations/0007_resume_consent.d.ts +18 -0
  169. package/dist/cjs/migrations/0007_resume_consent.d.ts.map +1 -0
  170. package/dist/cjs/migrations/0007_resume_consent.js +46 -0
  171. package/dist/cjs/migrations/0007_resume_consent.js.map +7 -0
  172. package/dist/cjs/package.json +1 -0
  173. package/dist/cjs/test/TestControl.d.ts +19 -0
  174. package/dist/cjs/test/TestControl.d.ts.map +1 -0
  175. package/dist/cjs/test/TestControl.js +62 -0
  176. package/dist/cjs/test/TestControl.js.map +7 -0
  177. package/dist/esm/ApprovalAuthority.d.ts +73 -0
  178. package/dist/esm/ApprovalAuthority.d.ts.map +1 -0
  179. package/dist/esm/ApprovalAuthority.js +72 -0
  180. package/dist/esm/ApprovalAuthority.js.map +1 -0
  181. package/dist/esm/Cancellation.d.ts +107 -0
  182. package/dist/esm/Cancellation.d.ts.map +1 -0
  183. package/dist/esm/Cancellation.js +116 -0
  184. package/dist/esm/Cancellation.js.map +1 -0
  185. package/dist/esm/Channels.d.ts +170 -0
  186. package/dist/esm/Channels.d.ts.map +1 -0
  187. package/dist/esm/Channels.js +312 -0
  188. package/dist/esm/Channels.js.map +1 -0
  189. package/dist/esm/Control.d.ts +202 -0
  190. package/dist/esm/Control.d.ts.map +1 -0
  191. package/dist/esm/Control.js +42 -0
  192. package/dist/esm/Control.js.map +1 -0
  193. package/dist/esm/ControlClient.d.ts +52 -0
  194. package/dist/esm/ControlClient.d.ts.map +1 -0
  195. package/dist/esm/ControlClient.js +217 -0
  196. package/dist/esm/ControlClient.js.map +1 -0
  197. package/dist/esm/ControlError.d.ts +318 -0
  198. package/dist/esm/ControlError.d.ts.map +1 -0
  199. package/dist/esm/ControlError.js +359 -0
  200. package/dist/esm/ControlError.js.map +1 -0
  201. package/dist/esm/ControlExecutor.d.ts +372 -0
  202. package/dist/esm/ControlExecutor.d.ts.map +1 -0
  203. package/dist/esm/ControlExecutor.js +212 -0
  204. package/dist/esm/ControlExecutor.js.map +1 -0
  205. package/dist/esm/ControlFacts.d.ts +454 -0
  206. package/dist/esm/ControlFacts.d.ts.map +1 -0
  207. package/dist/esm/ControlFacts.js +324 -0
  208. package/dist/esm/ControlFacts.js.map +1 -0
  209. package/dist/esm/ControlLive.d.ts +23 -0
  210. package/dist/esm/ControlLive.d.ts.map +1 -0
  211. package/dist/esm/ControlLive.js +1589 -0
  212. package/dist/esm/ControlLive.js.map +1 -0
  213. package/dist/esm/ControlRpcs.d.ts +1204 -0
  214. package/dist/esm/ControlRpcs.d.ts.map +1 -0
  215. package/dist/esm/ControlRpcs.js +299 -0
  216. package/dist/esm/ControlRpcs.js.map +1 -0
  217. package/dist/esm/ControlRuntime.d.ts +635 -0
  218. package/dist/esm/ControlRuntime.d.ts.map +1 -0
  219. package/dist/esm/ControlRuntime.js +808 -0
  220. package/dist/esm/ControlRuntime.js.map +1 -0
  221. package/dist/esm/ControlSchema.d.ts +2642 -0
  222. package/dist/esm/ControlSchema.d.ts.map +1 -0
  223. package/dist/esm/ControlSchema.js +1030 -0
  224. package/dist/esm/ControlSchema.js.map +1 -0
  225. package/dist/esm/ControlServer.d.ts +51 -0
  226. package/dist/esm/ControlServer.d.ts.map +1 -0
  227. package/dist/esm/ControlServer.js +145 -0
  228. package/dist/esm/ControlServer.js.map +1 -0
  229. package/dist/esm/Credential.d.ts +136 -0
  230. package/dist/esm/Credential.d.ts.map +1 -0
  231. package/dist/esm/Credential.js +190 -0
  232. package/dist/esm/Credential.js.map +1 -0
  233. package/dist/esm/CredentialCipher.d.ts +90 -0
  234. package/dist/esm/CredentialCipher.d.ts.map +1 -0
  235. package/dist/esm/CredentialCipher.js +56 -0
  236. package/dist/esm/CredentialCipher.js.map +1 -0
  237. package/dist/esm/CredentialStore.d.ts +97 -0
  238. package/dist/esm/CredentialStore.d.ts.map +1 -0
  239. package/dist/esm/CredentialStore.js +101 -0
  240. package/dist/esm/CredentialStore.js.map +1 -0
  241. package/dist/esm/DispatchReader.d.ts +112 -0
  242. package/dist/esm/DispatchReader.d.ts.map +1 -0
  243. package/dist/esm/DispatchReader.js +76 -0
  244. package/dist/esm/DispatchReader.js.map +1 -0
  245. package/dist/esm/Health.d.ts +333 -0
  246. package/dist/esm/Health.d.ts.map +1 -0
  247. package/dist/esm/Health.js +400 -0
  248. package/dist/esm/Health.js.map +1 -0
  249. package/dist/esm/JevSessionChecker.d.ts +57 -0
  250. package/dist/esm/JevSessionChecker.d.ts.map +1 -0
  251. package/dist/esm/JevSessionChecker.js +108 -0
  252. package/dist/esm/JevSessionChecker.js.map +1 -0
  253. package/dist/esm/Lineage.d.ts +131 -0
  254. package/dist/esm/Lineage.d.ts.map +1 -0
  255. package/dist/esm/Lineage.js +174 -0
  256. package/dist/esm/Lineage.js.map +1 -0
  257. package/dist/esm/Migrations.d.ts +34 -0
  258. package/dist/esm/Migrations.d.ts.map +1 -0
  259. package/dist/esm/Migrations.js +53 -0
  260. package/dist/esm/Migrations.js.map +1 -0
  261. package/dist/esm/Monitor.d.ts +282 -0
  262. package/dist/esm/Monitor.d.ts.map +1 -0
  263. package/dist/esm/Monitor.js +415 -0
  264. package/dist/esm/Monitor.js.map +1 -0
  265. package/dist/esm/ScopedToken.d.ts +193 -0
  266. package/dist/esm/ScopedToken.d.ts.map +1 -0
  267. package/dist/esm/ScopedToken.js +224 -0
  268. package/dist/esm/ScopedToken.js.map +1 -0
  269. package/dist/esm/SqlControlRuntime.d.ts +161 -0
  270. package/dist/esm/SqlControlRuntime.d.ts.map +1 -0
  271. package/dist/esm/SqlControlRuntime.js +1756 -0
  272. package/dist/esm/SqlControlRuntime.js.map +1 -0
  273. package/dist/esm/SqlCredentialStore.d.ts +43 -0
  274. package/dist/esm/SqlCredentialStore.d.ts.map +1 -0
  275. package/dist/esm/SqlCredentialStore.js +97 -0
  276. package/dist/esm/SqlCredentialStore.js.map +1 -0
  277. package/dist/esm/Steering.d.ts +69 -0
  278. package/dist/esm/Steering.d.ts.map +1 -0
  279. package/dist/esm/Steering.js +89 -0
  280. package/dist/esm/Steering.js.map +1 -0
  281. package/dist/esm/SystemFlows.d.ts +223 -0
  282. package/dist/esm/SystemFlows.d.ts.map +1 -0
  283. package/dist/esm/SystemFlows.js +198 -0
  284. package/dist/esm/SystemFlows.js.map +1 -0
  285. package/dist/esm/WebCryptoCipher.d.ts +49 -0
  286. package/dist/esm/WebCryptoCipher.d.ts.map +1 -0
  287. package/dist/esm/WebCryptoCipher.js +123 -0
  288. package/dist/esm/WebCryptoCipher.js.map +1 -0
  289. package/dist/esm/WebhookChannel.d.ts +113 -0
  290. package/dist/esm/WebhookChannel.d.ts.map +1 -0
  291. package/dist/esm/WebhookChannel.js +109 -0
  292. package/dist/esm/WebhookChannel.js.map +1 -0
  293. package/dist/esm/index.d.ts +160 -0
  294. package/dist/esm/index.d.ts.map +1 -0
  295. package/dist/esm/index.js +160 -0
  296. package/dist/esm/index.js.map +1 -0
  297. package/dist/esm/internal/MutationBoundary.d.ts +27 -0
  298. package/dist/esm/internal/MutationBoundary.d.ts.map +1 -0
  299. package/dist/esm/internal/MutationBoundary.js +40 -0
  300. package/dist/esm/internal/MutationBoundary.js.map +1 -0
  301. package/dist/esm/internal/activeFibers.d.ts +12 -0
  302. package/dist/esm/internal/activeFibers.d.ts.map +1 -0
  303. package/dist/esm/internal/activeFibers.js +17 -0
  304. package/dist/esm/internal/activeFibers.js.map +1 -0
  305. package/dist/esm/internal/issues.d.ts +28 -0
  306. package/dist/esm/internal/issues.d.ts.map +1 -0
  307. package/dist/esm/internal/issues.js +35 -0
  308. package/dist/esm/internal/issues.js.map +1 -0
  309. package/dist/esm/internal/planning.d.ts +347 -0
  310. package/dist/esm/internal/planning.d.ts.map +1 -0
  311. package/dist/esm/internal/planning.js +199 -0
  312. package/dist/esm/internal/planning.js.map +1 -0
  313. package/dist/esm/internal/sqlSchemaErrors.d.ts +18 -0
  314. package/dist/esm/internal/sqlSchemaErrors.d.ts.map +1 -0
  315. package/dist/esm/internal/sqlSchemaErrors.js +38 -0
  316. package/dist/esm/internal/sqlSchemaErrors.js.map +1 -0
  317. package/dist/esm/migrations/0001_control_tables.d.ts +18 -0
  318. package/dist/esm/migrations/0001_control_tables.d.ts.map +1 -0
  319. package/dist/esm/migrations/0001_control_tables.js +96 -0
  320. package/dist/esm/migrations/0001_control_tables.js.map +1 -0
  321. package/dist/esm/migrations/0002_run_keys.d.ts +15 -0
  322. package/dist/esm/migrations/0002_run_keys.d.ts.map +1 -0
  323. package/dist/esm/migrations/0002_run_keys.js +22 -0
  324. package/dist/esm/migrations/0002_run_keys.js.map +1 -0
  325. package/dist/esm/migrations/0003_signal_commands.d.ts +13 -0
  326. package/dist/esm/migrations/0003_signal_commands.d.ts.map +1 -0
  327. package/dist/esm/migrations/0003_signal_commands.js +26 -0
  328. package/dist/esm/migrations/0003_signal_commands.js.map +1 -0
  329. package/dist/esm/migrations/0004_approval_decisions.d.ts +13 -0
  330. package/dist/esm/migrations/0004_approval_decisions.d.ts.map +1 -0
  331. package/dist/esm/migrations/0004_approval_decisions.js +25 -0
  332. package/dist/esm/migrations/0004_approval_decisions.js.map +1 -0
  333. package/dist/esm/migrations/0005_signal_principals.d.ts +18 -0
  334. package/dist/esm/migrations/0005_signal_principals.d.ts.map +1 -0
  335. package/dist/esm/migrations/0005_signal_principals.js +27 -0
  336. package/dist/esm/migrations/0005_signal_principals.js.map +1 -0
  337. package/dist/esm/migrations/0006_run_principals.d.ts +18 -0
  338. package/dist/esm/migrations/0006_run_principals.d.ts.map +1 -0
  339. package/dist/esm/migrations/0006_run_principals.js +30 -0
  340. package/dist/esm/migrations/0006_run_principals.js.map +1 -0
  341. package/dist/esm/migrations/0007_resume_consent.d.ts +18 -0
  342. package/dist/esm/migrations/0007_resume_consent.d.ts.map +1 -0
  343. package/dist/esm/migrations/0007_resume_consent.js +27 -0
  344. package/dist/esm/migrations/0007_resume_consent.js.map +1 -0
  345. package/dist/esm/test/TestControl.d.ts +19 -0
  346. package/dist/esm/test/TestControl.d.ts.map +1 -0
  347. package/dist/esm/test/TestControl.js +30 -0
  348. package/dist/esm/test/TestControl.js.map +1 -0
  349. package/docs/README.md +189 -0
  350. package/docs/api.md +982 -0
  351. package/docs/concepts/authority.md +109 -0
  352. package/docs/concepts/cancellation.md +129 -0
  353. package/docs/concepts/lineage.md +132 -0
  354. package/docs/concepts/ownership.md +139 -0
  355. package/docs/concepts/projections.md +203 -0
  356. package/docs/concepts/receipts.md +128 -0
  357. package/docs/guides/approvals.md +284 -0
  358. package/docs/guides/cancel-and-resume.md +162 -0
  359. package/docs/guides/durable-storage.md +147 -0
  360. package/docs/guides/implement-an-executor.md +173 -0
  361. package/docs/guides/ingest-a-webhook.md +177 -0
  362. package/docs/guides/list-runs.md +160 -0
  363. package/docs/guides/monitor-runs.md +176 -0
  364. package/docs/guides/observe-health.md +147 -0
  365. package/docs/guides/postgres-tests.md +7 -0
  366. package/docs/guides/serve-over-rpc.md +220 -0
  367. package/docs/guides/signal-a-run.md +53 -0
  368. package/docs/guides/steer-a-run.md +138 -0
  369. package/docs/guides/store-credentials.md +164 -0
  370. package/docs/guides/testing.md +139 -0
  371. package/docs/guides/watch-a-run.md +154 -0
  372. package/docs/installation.md +106 -0
  373. package/docs/quickstart.md +163 -0
  374. package/docs/troubleshooting.md +208 -0
  375. package/package.json +405 -3
  376. package/src/ApprovalAuthority.ts +114 -0
  377. package/src/Cancellation.ts +172 -0
  378. package/src/Channels.ts +493 -0
  379. package/src/Control.ts +337 -0
  380. package/src/ControlClient.ts +319 -0
  381. package/src/ControlError.ts +378 -0
  382. package/src/ControlExecutor.ts +490 -0
  383. package/src/ControlFacts.ts +383 -0
  384. package/src/ControlLive.ts +2127 -0
  385. package/src/ControlRpcs.ts +443 -0
  386. package/src/ControlRuntime.ts +1601 -0
  387. package/src/ControlSchema.ts +1380 -0
  388. package/src/ControlServer.ts +182 -0
  389. package/src/Credential.ts +310 -0
  390. package/src/CredentialCipher.ts +110 -0
  391. package/src/CredentialStore.ts +152 -0
  392. package/src/DispatchReader.ts +122 -0
  393. package/src/Health.ts +591 -0
  394. package/src/JevSessionChecker.ts +127 -0
  395. package/src/Lineage.ts +203 -0
  396. package/src/Migrations.ts +56 -0
  397. package/src/Monitor.ts +600 -0
  398. package/src/ScopedToken.ts +306 -0
  399. package/src/SqlControlRuntime.ts +2478 -0
  400. package/src/SqlCredentialStore.ts +148 -0
  401. package/src/Steering.ts +96 -0
  402. package/src/SystemFlows.ts +225 -0
  403. package/src/WebCryptoCipher.ts +169 -0
  404. package/src/WebhookChannel.ts +166 -0
  405. package/src/index.ts +188 -0
  406. package/src/internal/MutationBoundary.ts +46 -0
  407. package/src/internal/activeFibers.ts +22 -0
  408. package/src/internal/issues.ts +40 -0
  409. package/src/internal/planning.ts +262 -0
  410. package/src/internal/sqlSchemaErrors.ts +37 -0
  411. package/src/migrations/0001_control_tables.ts +99 -0
  412. package/src/migrations/0002_run_keys.ts +23 -0
  413. package/src/migrations/0003_signal_commands.ts +27 -0
  414. package/src/migrations/0004_approval_decisions.ts +25 -0
  415. package/src/migrations/0005_signal_principals.ts +27 -0
  416. package/src/migrations/0006_run_principals.ts +31 -0
  417. package/src/migrations/0007_resume_consent.ts +28 -0
  418. package/src/test/TestControl.ts +47 -0
@@ -0,0 +1,109 @@
1
+ ---
2
+ title: "Authority, not execution"
3
+ description: "Why the control plane records decisions instead of running work, the three ports that keep that split honest, and what a composition looks like with each of them present or absent."
4
+ sidebar:
5
+ order: 1
6
+ ---
7
+
8
+ `Control` decides. It does not run anything.
9
+
10
+ Every operation the service exposes either records an intent or reads back
11
+ evidence. `plan` writes a reviewable card. `approve` resolves a durable token
12
+ and installs a grant. `cancel` writes a request and an attribution. `watch`
13
+ replays a journal it did not write. Nothing in this package executes a flow,
14
+ opens a step, or interprets a graph.
15
+
16
+ That is not a limitation to work around. It is what lets one control plane
17
+ answer for runs that several processes own, on machines it cannot reach, in a
18
+ database it shares with an engine it never imports.
19
+
20
+ ## The three ports
21
+
22
+ A host chooses an implementation of each seam, and the seams are what make the
23
+ plane portable.
24
+
25
+ | Port | Question it answers | Implementations here |
26
+ | ----------------- | ----------------------------------------------------------------------- | ------------------------------------------------------- |
27
+ | `ControlRuntime` | Where do plans, tokens, grants, idempotency records, and run rows live? | `ControlRuntime.layerMemory`, `SqlControlRuntime.layer` |
28
+ | `ControlExecutor` | Who actually runs the work, and what did they do with my request? | `ControlExecutor.makeNoop`, your own |
29
+ | `Journal` | Where is the evidence of what was decided? | [`@smthrs/journal`](/api/journal) |
30
+
31
+ `ControlLive.layer` is the implementation over those three plus the
32
+ [notification queue](/api/notifications) a steer travels through and the
33
+ [registry](/api/registry) a flow listing reads.
34
+
35
+ Both runtimes are held to one
36
+ [shared contract suite](https://github.com/smithersai/smithers/blob/main/packages/smithers/control/test/ControlContract.ts),
37
+ so a behavior you observe against the memory runtime is a behavior the durable
38
+ one owes you.
39
+
40
+ ## The executor is optional, and the absence is a real composition
41
+
42
+ `ControlLive` reads `ControlExecutor` through `Effect.serviceOption`. A
43
+ composition with no executor is not broken; it is a plane that starts nothing:
44
+
45
+ - `run` on an approved plan still mints the run row, still journals
46
+ `control.run.accepted`, and then releases the row as `control.run.pending`,
47
+ because nothing here took the launch.
48
+ - `cancel` still writes its attribution and still interrupts a fiber this
49
+ process is driving, but nothing reaches an engine row in another database.
50
+ - `signal` still records the fact, and no wait point is completed by this call.
51
+ - `resume` and `run` with a Resume input join or claim control-launched runs
52
+ and journal `control.run.resume`. A caller or journal subscriber must drive
53
+ the execution. Explicit resume does not offer work through
54
+ `ControlExecutor.resumeRun`. A run a live host parked is handed to that
55
+ host as a `requestResume` delegation that carries the operator's consent.
56
+ - A node-approval decision records a durable `requestResume` delegation.
57
+ Without an executor, it remains available for the owning host's next poll.
58
+
59
+ That is the shape a monitor, a dashboard, or a read-only operator tool has, and
60
+ it is what [`examples/src/38-monitor-and-alert.ts`](https://github.com/smithersai/smithers/blob/main/examples/src/38-monitor-and-alert.ts)
61
+ builds on purpose.
62
+
63
+ ## Two run tables, one journal
64
+
65
+ A control run row and an engine run row are different documents about the same
66
+ work, and they do not collide by accident: the plane keeps its own
67
+ `flows_runs`, and the engine keeps its own. The [`smthrs` CLI](/api/cli) runs
68
+ them as two files, `.flows/control.db` and `.flows/engine.db`.
69
+
70
+ They share the journal, and that is what makes `watch` worth having: one stream
71
+ carries `control.run.accepted` and `flows.engine.attempt-started` in the order
72
+ they happened.
73
+
74
+ Sharing one database instead is a deployment choice with consequences, because
75
+ `SqlControlRuntime` reads the engine's own columns for several projections:
76
+
77
+ | Projection | Column or entry it reads |
78
+ | ------------------------------------------------- | ----------------------------------------------------- |
79
+ | `RunSummary.waitingReason` | `flows_runs.waiting_reason` |
80
+ | Engine-created children and forks in `list` | `flows_run_parents`, `flows.time-travel.fork-created` |
81
+ | `RunSummary.cancellation` with `source: "engine"` | `cancel_requested_at_ms`, `flows.engine.interrupted` |
82
+
83
+ Give the control runtime and the engine one `SqlClient` and those projections
84
+ fill in. Keep them apart and the projections are empty, while cancellation
85
+ still converges, because the request travels through the `ControlExecutor` port
86
+ and the owning driver settles from it.
87
+
88
+ ## What the plane owes a caller
89
+
90
+ Three properties hold across every implementation of every port, and the rest
91
+ of this package exists to keep them:
92
+
93
+ 1. **Every mutation is idempotent under its key.** A retry answers the first
94
+ call's receipt rather than doing the work twice. See
95
+ [Receipts and idempotency](./receipts.md).
96
+ 2. **Every mutation is attributed.** The runtime stamps a principal, and a
97
+ server stamps the one it authenticated rather than the one a client claimed.
98
+ 3. **Every mutation leaves evidence beside the state it changed.** The journal
99
+ entry and the state write commit together, so a reader cannot see one
100
+ without the other.
101
+
102
+ ## Where to go next
103
+
104
+ - [Receipts and idempotency](./receipts.md): what a receipt means, and what a
105
+ second ask is worth.
106
+ - [Ownership, fences, and claims](./ownership.md): why a mutation can answer
107
+ `ClaimLost`, and what a park releases.
108
+ - [Journal projections](./projections.md): how `watch` turns entries into
109
+ `ControlEvent` values.
@@ -0,0 +1,129 @@
1
+ ---
2
+ title: "Cancellation attribution"
3
+ description: "A durable cancellation is anonymous on its own. How the journal adds back who asked and why, the three sources in the order they rank, and why a cascade inherits its ancestor's principal."
4
+ sidebar:
5
+ order: 6
6
+ ---
7
+
8
+ A durable cancellation records that somebody asked and when, and nothing else.
9
+ `flows_runs.cancel_requested_at_ms` is one number. It cannot say who, why, or
10
+ whether this run was asked for by name rather than swept up in an ancestor's
11
+ cascade.
12
+
13
+ `RunSummary.cancellation` is the attribution the journal adds back:
14
+
15
+ | Field | Meaning |
16
+ | -------------- | ------------------------------------------------------------------------- |
17
+ | `requestedAt` | When the cancellation was asked for. |
18
+ | `source` | `control`, `cascade`, or `engine`. |
19
+ | `principal` | Who asked. Present on a `control` source and on the `cascade` it started. |
20
+ | `reason` | Why, as the operator stated it. |
21
+ | `cascadedFrom` | The cancelled ancestor this run was swept up with. |
22
+
23
+ `control` is an operator asking through this plane, and it is the only source
24
+ that can name a principal. `cascade` is a run swept up in an ancestor's
25
+ cancellation. `engine` is everything the runtime decided on its own account: a
26
+ lease expiry, a budget, a supervisor.
27
+
28
+ ## The three sources, in order
29
+
30
+ `Cancellation.attribute` is the fold, and a run's own evidence outranks its
31
+ ancestors':
32
+
33
+ 1. **A `control.run.cancel-requested` entry names this run.** Somebody asked
34
+ for it by name, and the entry says who and why.
35
+ 2. **A cancelled ancestor exists.** The run reports `cascade`, names the
36
+ nearest cancelled ancestor, and inherits that ancestor's principal and
37
+ reason. The honest answer to "who cancelled this child" is the operator who
38
+ cancelled its parent.
39
+ 3. **Neither.** The engine cancelled the run on its own account. There is no
40
+ principal to report, and inventing one would be worse than saying nothing.
41
+
42
+ A run counts as cancelled when any of three things is true: the run store's
43
+ `cancel_requested_at_ms` is set, the engine journaled
44
+ `flows.engine.interrupted` with outcome `cancelled`, or an attributed request
45
+ names the run. The third matters because a control plane cancelling a run it
46
+ owns interrupts the fiber rather than writing the request column, and its
47
+ journal entry is the whole record.
48
+
49
+ ```ts
50
+ import * as Cancellation from "@smthrs/control/Cancellation"
51
+
52
+ const attributed = Cancellation.attribute({
53
+ runs: [
54
+ { runId: "run-1", cancelRequestedAt: 10 },
55
+ { runId: "run-2", parentRunId: "run-1", cancelledAt: 12 }
56
+ ],
57
+ requests: new Map([[
58
+ "run-1",
59
+ { requestedAt: 10, principal: { id: "ada", kind: "user", stampedAt: 10 }, reason: "budget" }
60
+ ]])
61
+ })
62
+
63
+ attributed.get("run-1")
64
+ // { requestedAt: 10, source: "control", principal: { id: "ada", ... }, reason: "budget" }
65
+ attributed.get("run-2")
66
+ // { requestedAt: 12, source: "cascade", principal: { id: "ada", ... }, reason: "budget", cascadedFrom: "run-1" }
67
+ ```
68
+
69
+ ## Why the fold is pure and scope-independent
70
+
71
+ `attribute` reads whatever evidence it is handed and never issues a query, so
72
+ the caller chooses how much to read. `SqlControlRuntime` uses two scopes:
73
+
74
+ - A **listing** folds the whole database, because every row is going to be
75
+ answered for anyway.
76
+ - **Reading one run** folds that run and its ancestor chain, which is the
77
+ smallest scope that can still answer the question.
78
+
79
+ Cascade is a fact about a run's ancestors, so it cannot be decided one row at a
80
+ time: the request that cancelled a child may be several rounds up the chain.
81
+ Reading one run therefore costs one recursive walk over `parent_run_id` plus
82
+ one spawn-edge read per nesting level, and never grows with the size of the
83
+ database. That is what keeps the cost of steering or cancelling a run
84
+ independent of how many runs exist.
85
+
86
+ The ancestor walk carries a visited set. A cyclic parent chain is not reachable
87
+ through the engine's own cycle detection, but a projection that hung on corrupt
88
+ ancestry would take the control plane down with it.
89
+
90
+ ## Where the attribution is written
91
+
92
+ `cancel` writes the principal and the reason onto its
93
+ `control.run.cancel-requested` entry, inside the mutation's own transaction, so
94
+ a cancellation cannot commit anonymously. `resume` records the same pair on its
95
+ `control.run.resume` entry.
96
+
97
+ The request, attribution, and acceptance receipt commit before the local fiber
98
+ is interrupted. Cancellation then awaits its finalizers without holding the
99
+ mutation semaphore or journal transaction, so cleanup can signal another run
100
+ or use the same durable writer. A second transaction rechecks the original
101
+ ownership fence and commits the terminal status and event together. A terminal
102
+ outcome reached during cleanup is preserved. If cleanup loses ownership, the
103
+ durable request remains for the owner or a later cancel attempt.
104
+
105
+ Attribution is keyed on the request being newly recorded. `cancel` re-executes
106
+ on every ask, so attributing every ask would journal one
107
+ `control.run.cancel-requested` per ask for a single cancellation. The executor
108
+ answers `already-requested` when the engine column was set before this call
109
+ arrived, and that answer suppresses the second record.
110
+
111
+ A cancel whose executor reports that the engine row has already settled writes
112
+ no attribution, because nobody cancelled anything, and reconciles the control
113
+ row onto the engine's own status instead. Nothing else converges the two rows,
114
+ so a control row left disagreeing with a settled engine row would list the run
115
+ as live forever.
116
+
117
+ Over RPC the `Cancel` procedure carries the reason and refuses a caller-named
118
+ principal. The server stamps the identity it authenticated, so a remote
119
+ operator states why and never states who. The principal's `stampedAt` records
120
+ when that authentication happened; it is evidence about an external event,
121
+ never a value any decision is replayed from.
122
+
123
+ ## Where to go next
124
+
125
+ - [Cancel a run, and restart one](../guides/cancel-and-resume.md): the verb,
126
+ and what each receipt means.
127
+ - [Run lineage](./lineage.md): the ancestor chain a cascade walks.
128
+ - [Store control state in a database](../guides/durable-storage.md): the only
129
+ runtime that fills `RunSummary.cancellation` in.
@@ -0,0 +1,132 @@
1
+ ---
2
+ title: "Run lineage"
3
+ description: "The one vocabulary four ancestry records project onto: child, fork, and continuation, where each is written, which record wins, and how watch derives exactly one lineage delta per edge."
4
+ sidebar:
5
+ order: 5
6
+ ---
7
+
8
+ A run's ancestry is recorded by whoever created it, in four different places:
9
+ the run row's `parent_run_id`, `lineage_id`, and `round_ordinal` columns; the
10
+ `flows_run_parents` edge a spawn writes; the `created` and `handed-off` run
11
+ decisions the engine journals; and the `fork-created` marker time travel writes
12
+ on a forked child.
13
+
14
+ `Lineage` owns the one vocabulary all four project onto, and the pure functions
15
+ that do the projecting, so the durable runtime and the watch stream cannot
16
+ disagree about what a run's ancestry means.
17
+
18
+ ## The vocabulary
19
+
20
+ `Origin` has three values, and a run with no ancestor has no origin at all:
21
+
22
+ | Origin | What it means |
23
+ | -------------- | ---------------------------------------------- |
24
+ | `child` | Another run spawned it. |
25
+ | `fork` | It was branched off a parent frame. |
26
+ | `continuation` | It is a later round of one trampoline lineage. |
27
+
28
+ A rewind is deliberately absent. It truncates a run in place and creates none,
29
+ so it is a thing that happened to a run rather than a reason a run exists.
30
+
31
+ `Lineage.originOf` is the derivation, and it is pure:
32
+
33
+ ```ts
34
+ import * as Lineage from "@smthrs/control/Lineage"
35
+
36
+ Lineage.originOf({ parentRunId: "run-1" }) // "child"
37
+ Lineage.originOf({ parentRunId: "run-1", forked: true }) // "fork"
38
+ Lineage.originOf({ parentRunId: "run-1", roundOrdinal: 2 }) // "continuation"
39
+ Lineage.originOf({}) // undefined
40
+ ```
41
+
42
+ A fork wins over a plain child because a fork records `parent_run_id` too.
43
+ Without the marker, every fork would be reported as an ordinary child.
44
+
45
+ ## What a run summary reports
46
+
47
+ `RunSummary` carries all of it under one vocabulary:
48
+
49
+ | Field | Source | Meaning |
50
+ | -------------- | ------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
51
+ | `parentRunId` | `flows_runs.parent_run_id`, else the `flows_run_parents` spawn edge | The run this one branched from: its spawner, the run it was forked off, or the previous trampoline round. |
52
+ | `lineageId` | `flows_runs.lineage_id` | The trampoline lineage this run is a round of. |
53
+ | `roundOrdinal` | `flows_runs.round_ordinal` | Which round. Absent means a lineage of one, read as round 0 of itself. |
54
+ | `origin` | derived | `child`, `fork`, or `continuation`. |
55
+
56
+ The projection reads both recording places because the engine uses both.
57
+ `parent_run_id` is the trampoline chain: the round before this one. A run that
58
+ another run _spawned_ writes nothing in its own row, because the edge lives in
59
+ the `flows_run_parents` graph that cycle detection walks. A projection that
60
+ read the column alone would report every child of every run as an orphan.
61
+
62
+ The column wins when a row has both. That is round 1 of a run that was itself
63
+ spawned: its nearest ancestor is the round before it.
64
+
65
+ ## The delta `watch` derives
66
+
67
+ Three journal entries disclose an edge, and each names a different pair:
68
+
69
+ | Entry | Producer | Delta |
70
+ | ---------------------------------------------------------------------------------- | ------------------------------------------- | ------------------------------------------------------------------------- |
71
+ | `flows.engine.run-decision` with `decision: "created"` at round 0 or with no round | [`@smthrs/engine-store`](/api/engine-store) | `{ runId, parentRunId, origin: "child" }` |
72
+ | `flows.engine.run-decision` with `decision: "handed-off"` | [`@smthrs/engine-store`](/api/engine-store) | `{ runId, parentRunId, lineageId, roundOrdinal, origin: "continuation" }` |
73
+ | `flows.time-travel.fork-created` | [`@smthrs/time-travel`](/api/time-travel) | `{ runId, parentRunId, origin: "fork" }` |
74
+
75
+ The handoff is what carries a trampoline, and a continuation round's own
76
+ `created` decision is deliberately skipped. The engine journals both in one
77
+ transaction: it creates the next round with
78
+ `{decision: "created", lineageId, roundOrdinal, parentExecutionId}` and records
79
+ `{decision: "handed-off", nextExecutionId}` on the round that finished. Both
80
+ name the same pair, so deriving from both would report one run as a `child` of
81
+ its predecessor on one entry and a `continuation` of it on the other.
82
+
83
+ The handoff is the one kept, because it reaches a consumer watching the run
84
+ that hands off, which is the run an operator is already following when a
85
+ trampoline advances. Exactly one delta therefore names each continuation round,
86
+ whichever round of the lineage the consumer is watching.
87
+
88
+ ```ts
89
+ Lineage.derive({
90
+ sequence: 12,
91
+ kind: Lineage.runDecisionEventType,
92
+ runId: "run-1",
93
+ occurredAt: 1_700_000_000_000,
94
+ payload: { decision: "handed-off", nextExecutionId: "run-2", lineageId: "run-1", roundOrdinal: 1 }
95
+ })
96
+ // {
97
+ // sequence: 12,
98
+ // kind: "control.run.lineage",
99
+ // runId: "run-1",
100
+ // occurredAt: 1700000000000,
101
+ // payload: { runId: "run-2", parentRunId: "run-1", lineageId: "run-1", roundOrdinal: 1, origin: "continuation" }
102
+ // }
103
+ ```
104
+
105
+ Everything else derives nothing. This is a projection over entries the control
106
+ plane did not write, so an entry it does not recognize is not an error, and a
107
+ `created` decision that names no parent discloses no ancestry.
108
+
109
+ ## Selecting on lineage
110
+
111
+ `list` filters on the same fields, so an operator can ask both ancestry
112
+ questions:
113
+
114
+ ```ts
115
+ const children = yield * control.list({ _tag: "runs", filters: { parentRunId: "run-17" } })
116
+ const rounds = yield * control.list({ _tag: "runs", filters: { lineageId: "run-17" } })
117
+ ```
118
+
119
+ The durable listing covers every row in `flows_runs`, not only the runs the
120
+ control plane launched itself. A child, a fork, and a later trampoline round
121
+ are all created by the engine straight into the run store, and a plane that
122
+ listed only its own launches could not answer what a run spawned. Runs the
123
+ plane launched keep launch order; the rest follow in creation order. A run
124
+ whose `state_json` is not a control summary is projected from the run row's own
125
+ columns instead, with the engine's `flowName` as its `flowId`.
126
+
127
+ ## Where to go next
128
+
129
+ - [Find runs and page through them](../guides/list-runs.md): the filters as a
130
+ task.
131
+ - [Watch a run's events](../guides/watch-a-run.md): where the delta arrives.
132
+ - [Time travel on smithers.sh](/docs/concepts/time-travel/): what makes a fork.
@@ -0,0 +1,139 @@
1
+ ---
2
+ title: "Ownership, fences, and claims"
3
+ description: "How a fence makes every owner-sensitive write a compare-and-swap, what a park releases, why a resume can be scoped to runs this plane launched, and how a resume delegation reaches the process that can act on it."
4
+ sidebar:
5
+ order: 3
6
+ ---
7
+
8
+ Several processes share one control database, and only one of them may be
9
+ driving a given run. Ownership is how the plane decides which, and a **fence**
10
+ is the token that decides it.
11
+
12
+ A fence is a serialized owner identity: a host id, a process id, and a nonce
13
+ that is regenerated on every claim. Every owner-sensitive write presents its
14
+ fence, and the runtime turns that into a single SQL compare-and-swap, so a
15
+ stale writer loses the `UPDATE` rather than racing a read-then-write. A fence
16
+ taken before a park is not the fence held after the resume that follows it, and
17
+ the stale one is refused.
18
+
19
+ When a write presents a fence the row has moved past, the plane answers
20
+ [`ClaimLost`](../troubleshooting.md).
21
+
22
+ ## Status is ownership, spelled for an operator
23
+
24
+ `SqlControlRuntime` maps the control plane's vocabulary onto the run store's:
25
+
26
+ | Control status | Run store status | Ownership |
27
+ | ------------------------------------- | ---------------- | -------------------- |
28
+ | `accepted`, `running` | `running` | Held by this process |
29
+ | `accepted` after an executor declines | `suspended` | Released |
30
+ | `parked`, `waiting-approval` | `suspended` | Released |
31
+ | `cancelled`, `completed`, `failed` | same | Released, terminal |
32
+
33
+ A claim writes `accepted`. `Control.run` promotes it to `running` when its
34
+ executor takes the launch; an explicit resume leaves it `accepted` until the
35
+ driver writes another status. An `ownerId` distinguishes an owned `accepted`
36
+ run from a released pending launch. Losing a claim to an owned `accepted` or
37
+ `running` row means a live peer holds it.
38
+
39
+ The authoritative `RunSummary` is written into the row's `state_json` by the
40
+ same fenced `UPDATE` that moves the status, so a projection can never be read
41
+ out of step with the lifecycle.
42
+
43
+ ## A park releases the row, and records who parked it
44
+
45
+ A parked execution releases its owner columns. That is what makes it resumable
46
+ at all, and it is also why every process sharing the database can see the park.
47
+
48
+ The fence the park was written under is kept in `RunSummary.parkedBy`, and only
49
+ on a park. It is the one thing left on the row that says which host parked the
50
+ run, so that host recognizes its own park and a short-lived process that would
51
+ drive the run and then exit can tell the execution is not its to take up.
52
+
53
+ `RunSummary.waitingReason` is the other half of the picture, and the control
54
+ plane only ever reads it. The engine writes it when it parks a run and clears
55
+ it on the wake, so an operator park written through
56
+ `ControlRuntime.writeStatus(runId, fence, "parked")` leaves the column empty.
57
+ An empty column is exactly how an operator park is told apart from an engine
58
+ park, and several behaviors turn on that:
59
+
60
+ | `waitingReason` | A steer arriving | A monitor's reading |
61
+ | ---------------- | ---------------- | ------------------- |
62
+ | `event` | Resumes the run | Ordinary park |
63
+ | `released` | Resumes the run | Ordinary park |
64
+ | `approval` | Leaves it parked | `awaiting-human` |
65
+ | `timer`, `quota` | Leaves it parked | Ordinary park |
66
+ | absent | Leaves it parked | `awaiting-human` |
67
+
68
+ ## Claim scope: launched, or any
69
+
70
+ `ControlRuntime.resume` joins a non-terminal run whose fence this process
71
+ still holds, including an `accepted` run. A join preserves the original fence.
72
+ An `accepted` run released by `releasePending` is claimable under a new fence.
73
+
74
+ `scope: "launched"` restricts claims to runs recorded in `control_runs`, the
75
+ shared index of control-launched runs. Both `Control.resume` and `Control.run`
76
+ with a Resume input, plus every steer wake, pass this scope. An engine-created
77
+ child, fork, or later trampoline round keeps its own continuation and driver.
78
+
79
+ `scope: "any"`, also the runtime default, is a trusted low-level runtime
80
+ capability for hosts that can drive the claimed execution. It is not the
81
+ public Control resume contract.
82
+
83
+ ## Explicit resume records a journal intent
84
+
85
+ Both public resume spellings journal `control.run.resume`. A suspended run
86
+ outside the launch index remains unclaimed; the receipt is `Accepted` after
87
+ the journal intent is recorded. A live peer's owned run fails with `ClaimLost`.
88
+ A caller or journal subscriber must drive the execution, including after a
89
+ successful claim. An `Accepted` receipt does not establish that work started.
90
+
91
+ Explicit resume never calls `ControlExecutor.resumeRun`. A run the caller can
92
+ claim creates no `pendingResumes` entry.
93
+
94
+ A run a live host parked is the exception. `resume` may take a park only after
95
+ a same-host probe proves the parking process dead. Otherwise the runtime
96
+ refuses with `ClaimLost` naming the host in `parkedBy`, and `resume` hands the
97
+ restart to that host. It journals `control.run.resume` with `handedTo` and
98
+ records a `requestResume` delegation whose `consent` is that entry's journal
99
+ sequence. The receipt is `Accepted` with `handedTo`. The parking host takes the
100
+ delegation up on its next poll, records the per-release retry permission under
101
+ that sequence, and re-drives the run. See
102
+ [Cancel a run, and restart one](../guides/cancel-and-resume.md#a-run-a-live-host-parked).
103
+
104
+ ## Node approval records a durable resume delegation
105
+
106
+ A decision on an in-run approval restarts the run server-side, and the process
107
+ that decides is usually not the process hosting the execution: an operator's
108
+ `smthrs approvals approve`, a gateway, a second CLI.
109
+
110
+ So the intent is recorded durably rather than published in process:
111
+
112
+ 1. `requestResume(runId)` writes the delegation and returns its sequence.
113
+ `RunSummary.pendingResume` reports that sequence while it is outstanding.
114
+ An approval delegation carries no `consent`: it is background intent, and
115
+ it keeps an operator's consent that no host has taken up yet.
116
+ 2. The plane offers it to its own executor through `ControlExecutor.resumeRun`.
117
+ An executor that answers `resuming` has claimed the row and is driving, so
118
+ the delegation is cleared with `clearResume(runId, sequence)`.
119
+ 3. An executor that answers `unknown` leaves the delegation standing.
120
+ `pendingResumes` is what every host polls, and a run parked by a process
121
+ that has since exited is taken up by whichever host can drive it once the
122
+ delegation has gone unanswered for the run store's heartbeat staleness
123
+ window.
124
+
125
+ The sequence check is what makes the clear safe. A resume requested between the
126
+ read and the clear has a higher sequence and survives, so the host takes it up
127
+ on its next tick instead of losing it.
128
+
129
+ A settled run's delegation is never reported: no host will ever take it up, and
130
+ reporting it forever would turn a finished run into an unbounded backlog.
131
+
132
+ ## Where to go next
133
+
134
+ - [Cancel a run, and restart one](../guides/cancel-and-resume.md): the verbs
135
+ that meet these rules head on.
136
+ - [Connect an execution engine](../guides/implement-an-executor.md): the port
137
+ that turns a delegation into a running fiber.
138
+ - [Ownership on smithers.sh](/docs/concepts/ownership/): the same fence, from
139
+ the engine's side.