@pikku/core 0.12.72 → 0.12.77

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 (848) hide show
  1. package/CHANGELOG.md +1171 -0
  2. package/dist/column-form.d.ts +32 -0
  3. package/dist/column-form.js +42 -0
  4. package/dist/crypto-utils.d.ts +43 -7
  5. package/dist/crypto-utils.js +163 -42
  6. package/dist/data-classification.d.ts +44 -0
  7. package/dist/dev/hot-reload.js +11 -30
  8. package/dist/dev/module-runner.d.ts +3 -7
  9. package/dist/dev/module-runner.js +4 -10
  10. package/dist/dev/reload-meta.d.ts +8 -20
  11. package/dist/dev/reload-meta.js +9 -29
  12. package/dist/errors/error-handler.d.ts +5 -30
  13. package/dist/errors/error-handler.js +16 -32
  14. package/dist/errors/errors.d.ts +32 -151
  15. package/dist/errors/errors.js +55 -157
  16. package/dist/function/abort-scope.d.ts +47 -0
  17. package/dist/function/abort-scope.js +63 -0
  18. package/dist/function/function-runner.js +37 -32
  19. package/dist/function/functions.types.d.ts +57 -136
  20. package/dist/function/functions.types.js +0 -58
  21. package/dist/function/index.d.ts +1 -1
  22. package/dist/function/list.types.d.ts +12 -62
  23. package/dist/function/list.types.js +4 -25
  24. package/dist/handle-error.d.ts +0 -13
  25. package/dist/handle-error.js +0 -18
  26. package/dist/index.d.ts +11 -5
  27. package/dist/index.js +7 -2
  28. package/dist/middleware/auth-apikey.d.ts +3 -18
  29. package/dist/middleware/auth-apikey.js +0 -17
  30. package/dist/middleware/auth-bearer.d.ts +6 -41
  31. package/dist/middleware/auth-bearer.js +5 -41
  32. package/dist/middleware/auth-cookie.d.ts +5 -27
  33. package/dist/middleware/auth-cookie.js +2 -26
  34. package/dist/middleware/cors.d.ts +7 -34
  35. package/dist/middleware/cors.js +7 -34
  36. package/dist/middleware/remote-auth.d.ts +3 -1
  37. package/dist/middleware/remote-auth.js +4 -3
  38. package/dist/middleware/telemetry.d.ts +8 -33
  39. package/dist/middleware/telemetry.js +2 -31
  40. package/dist/middleware-runner.d.ts +4 -55
  41. package/dist/middleware-runner.js +5 -74
  42. package/dist/permissions.d.ts +3 -44
  43. package/dist/permissions.js +19 -71
  44. package/dist/pikku-request.d.ts +0 -6
  45. package/dist/pikku-request.js +0 -6
  46. package/dist/pikku-state.d.ts +0 -26
  47. package/dist/pikku-state.js +2 -30
  48. package/dist/remote.d.ts +3 -5
  49. package/dist/remote.js +9 -8
  50. package/dist/schema.d.ts +5 -39
  51. package/dist/schema.js +5 -39
  52. package/dist/scopes.d.ts +4 -23
  53. package/dist/scopes.js +7 -48
  54. package/dist/secret-value.d.ts +56 -0
  55. package/dist/secret-value.js +46 -0
  56. package/dist/services/ai-agent-runner-service.d.ts +20 -0
  57. package/dist/services/ai-embedding-service.d.ts +2 -25
  58. package/dist/services/audit-service.d.ts +74 -4
  59. package/dist/services/audit-service.js +8 -7
  60. package/dist/services/content-service.d.ts +1 -46
  61. package/dist/services/credential-service.d.ts +3 -40
  62. package/dist/services/credential-wire-service.d.ts +5 -0
  63. package/dist/services/credential-wire-service.js +9 -1
  64. package/dist/services/deployment-service.d.ts +3 -9
  65. package/dist/services/email-service.d.ts +2 -1
  66. package/dist/services/gateway-service.d.ts +0 -15
  67. package/dist/services/http-personas.d.ts +80 -0
  68. package/dist/services/http-personas.js +233 -0
  69. package/dist/services/in-memory-queue-service.d.ts +0 -14
  70. package/dist/services/in-memory-queue-service.js +1 -15
  71. package/dist/services/in-memory-trigger-service.d.ts +0 -18
  72. package/dist/services/in-memory-trigger-service.js +1 -18
  73. package/dist/services/in-memory-workflow-service.d.ts +0 -16
  74. package/dist/services/in-memory-workflow-service.js +4 -33
  75. package/dist/services/index.d.ts +8 -9
  76. package/dist/services/index.js +3 -6
  77. package/dist/services/istanbul-coverage-service.d.ts +1 -5
  78. package/dist/services/istanbul-coverage-service.js +2 -8
  79. package/dist/services/jwt-service.d.ts +1 -16
  80. package/dist/services/local-content-request-handler.d.ts +29 -0
  81. package/dist/services/local-content-request-handler.js +176 -0
  82. package/dist/services/local-content.d.ts +13 -2
  83. package/dist/services/local-content.js +40 -13
  84. package/dist/services/local-gateway-service.d.ts +0 -16
  85. package/dist/services/local-gateway-service.js +2 -17
  86. package/dist/services/local-secrets.d.ts +4 -7
  87. package/dist/services/local-secrets.js +7 -7
  88. package/dist/services/logger-console.d.ts +3 -7
  89. package/dist/services/logger-console.js +3 -7
  90. package/dist/services/logger.d.ts +22 -40
  91. package/dist/services/meta-service.d.ts +23 -26
  92. package/dist/services/meta-service.js +22 -36
  93. package/dist/services/personas-service.d.ts +134 -0
  94. package/dist/services/personas-service.js +40 -0
  95. package/dist/services/pikku-user-id.js +0 -4
  96. package/dist/services/queue-webhook-service.d.ts +2 -36
  97. package/dist/services/queue-webhook-service.js +10 -42
  98. package/dist/services/scheduler-service.d.ts +1 -50
  99. package/dist/services/scheduler-service.js +0 -10
  100. package/dist/services/schema-service.d.ts +1 -24
  101. package/dist/services/scope-service.d.ts +49 -34
  102. package/dist/services/scoped-secret-service.d.ts +4 -7
  103. package/dist/services/scoped-secret-service.js +0 -4
  104. package/dist/services/secret-host-binding.d.ts +8 -0
  105. package/dist/services/secret-host-binding.js +36 -0
  106. package/dist/services/secret-service.d.ts +12 -35
  107. package/dist/services/secretless.d.ts +6 -0
  108. package/dist/services/secretless.js +21 -0
  109. package/dist/services/stub-tracker.d.ts +7 -18
  110. package/dist/services/stub-tracker.js +8 -18
  111. package/dist/services/system-role-guard.d.ts +33 -0
  112. package/dist/services/system-role-guard.js +38 -0
  113. package/dist/services/trigger-service.d.ts +0 -12
  114. package/dist/services/typed-secret-service.d.ts +5 -11
  115. package/dist/services/typed-secret-service.js +1 -7
  116. package/dist/services/v8-coverage-service.d.ts +2 -3
  117. package/dist/services/v8-coverage-service.js +1 -2
  118. package/dist/services/variables-service.d.ts +1 -8
  119. package/dist/services/webhook-service.d.ts +21 -64
  120. package/dist/services/webhook-service.js +6 -20
  121. package/dist/services/workflow-service.d.ts +3 -15
  122. package/dist/testing/service-tests.js +6 -23
  123. package/dist/time-utils.d.ts +0 -16
  124. package/dist/time-utils.js +1 -19
  125. package/dist/types/core.types.d.ts +120 -219
  126. package/dist/types/core.types.js +0 -42
  127. package/dist/types/state.types.d.ts +4 -9
  128. package/dist/utils/hmac.d.ts +4 -10
  129. package/dist/utils/hmac.js +4 -10
  130. package/dist/utils/safe-fetch.d.ts +7 -35
  131. package/dist/utils/safe-fetch.js +13 -53
  132. package/dist/utils.d.ts +1 -6
  133. package/dist/utils.js +6 -15
  134. package/dist/wirings/actor-flow/actor-flow.types.d.ts +1 -34
  135. package/dist/wirings/actor-flow/index.d.ts +0 -9
  136. package/dist/wirings/actor-flow/run-conversation.d.ts +5 -5
  137. package/dist/wirings/actor-flow/run-conversation.js +14 -7
  138. package/dist/wirings/ai-agent/ai-agent-agui.d.ts +0 -5
  139. package/dist/wirings/ai-agent/ai-agent-agui.js +46 -12
  140. package/dist/wirings/ai-agent/ai-agent-helpers.d.ts +7 -0
  141. package/dist/wirings/ai-agent/ai-agent-helpers.js +7 -0
  142. package/dist/wirings/ai-agent/ai-agent-interrupt.d.ts +153 -0
  143. package/dist/wirings/ai-agent/ai-agent-interrupt.js +256 -0
  144. package/dist/wirings/ai-agent/ai-agent-memory.js +0 -2
  145. package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +0 -9
  146. package/dist/wirings/ai-agent/ai-agent-model-config.js +1 -9
  147. package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +10 -99
  148. package/dist/wirings/ai-agent/ai-agent-prepare.js +65 -132
  149. package/dist/wirings/ai-agent/ai-agent-registry.d.ts +2 -1
  150. package/dist/wirings/ai-agent/ai-agent-registry.js +5 -1
  151. package/dist/wirings/ai-agent/ai-agent-runner.js +63 -22
  152. package/dist/wirings/ai-agent/ai-agent-stream.d.ts +25 -2
  153. package/dist/wirings/ai-agent/ai-agent-stream.js +180 -64
  154. package/dist/wirings/ai-agent/ai-agent.types.d.ts +124 -4
  155. package/dist/wirings/ai-agent/index.d.ts +6 -4
  156. package/dist/wirings/ai-agent/index.js +5 -4
  157. package/dist/wirings/ai-agent/voice-input.d.ts +59 -1
  158. package/dist/wirings/ai-agent/voice-input.js +90 -12
  159. package/dist/wirings/ai-agent/voice-output.d.ts +69 -1
  160. package/dist/wirings/ai-agent/voice-output.js +162 -50
  161. package/dist/wirings/channel/channel-common.d.ts +7 -20
  162. package/dist/wirings/channel/channel-common.js +7 -21
  163. package/dist/wirings/channel/channel-handler.js +25 -6
  164. package/dist/wirings/channel/channel-host-rpc.d.ts +25 -0
  165. package/dist/wirings/channel/channel-host-rpc.js +38 -0
  166. package/dist/wirings/channel/channel-middleware-runner.d.ts +0 -12
  167. package/dist/wirings/channel/channel-middleware-runner.js +0 -12
  168. package/dist/wirings/channel/channel-rpc-registry.d.ts +31 -0
  169. package/dist/wirings/channel/channel-rpc-registry.js +89 -0
  170. package/dist/wirings/channel/channel-rpc-responder.d.ts +15 -0
  171. package/dist/wirings/channel/channel-rpc-responder.js +71 -0
  172. package/dist/wirings/channel/channel-rpc-service.d.ts +40 -0
  173. package/dist/wirings/channel/channel-rpc-service.js +106 -0
  174. package/dist/wirings/channel/channel-rpc-validators.d.ts +14 -0
  175. package/dist/wirings/channel/channel-rpc-validators.js +30 -0
  176. package/dist/wirings/channel/channel-rpc.d.ts +5 -0
  177. package/dist/wirings/channel/channel-rpc.js +5 -0
  178. package/dist/wirings/channel/channel-rpc.types.d.ts +90 -0
  179. package/dist/wirings/channel/channel-rpc.types.js +50 -0
  180. package/dist/wirings/channel/channel-runner.d.ts +0 -4
  181. package/dist/wirings/channel/channel-runner.js +0 -14
  182. package/dist/wirings/channel/channel-store.d.ts +0 -10
  183. package/dist/wirings/channel/channel.types.d.ts +12 -1
  184. package/dist/wirings/channel/define-channel-routes.d.ts +0 -20
  185. package/dist/wirings/channel/define-channel-routes.js +0 -20
  186. package/dist/wirings/channel/eventhub-service.d.ts +0 -18
  187. package/dist/wirings/channel/index.d.ts +4 -1
  188. package/dist/wirings/channel/index.js +2 -0
  189. package/dist/wirings/channel/local/local-channel-runner.js +3 -1
  190. package/dist/wirings/channel/local/local-eventhub-service.d.ts +0 -33
  191. package/dist/wirings/channel/local/local-eventhub-service.js +2 -36
  192. package/dist/wirings/channel/log-channels.d.ts +0 -4
  193. package/dist/wirings/channel/log-channels.js +0 -4
  194. package/dist/wirings/channel/pikku-abstract-channel-handler.js +6 -0
  195. package/dist/wirings/channel/serverless/serverless-channel-runner.js +2 -5
  196. package/dist/wirings/cli/channel/cli-approval.d.ts +41 -0
  197. package/dist/wirings/cli/channel/cli-approval.js +81 -0
  198. package/dist/wirings/cli/channel/cli-channel-runner.d.ts +0 -4
  199. package/dist/wirings/cli/channel/cli-channel-runner.js +3 -25
  200. package/dist/wirings/cli/channel/cli-raw-channel-runner.d.ts +47 -9
  201. package/dist/wirings/cli/channel/cli-raw-channel-runner.js +24 -16
  202. package/dist/wirings/cli/channel/cli-raw-client-runner.d.ts +38 -0
  203. package/dist/wirings/cli/channel/cli-raw-client-runner.js +129 -0
  204. package/dist/wirings/cli/channel/index.d.ts +5 -0
  205. package/dist/wirings/cli/channel/index.js +2 -0
  206. package/dist/wirings/cli/cli-runner.d.ts +20 -20
  207. package/dist/wirings/cli/cli-runner.js +28 -89
  208. package/dist/wirings/cli/cli.types.d.ts +14 -3
  209. package/dist/wirings/cli/command-parser.d.ts +1 -10
  210. package/dist/wirings/cli/command-parser.js +10 -87
  211. package/dist/wirings/cli/define-cli-commands.d.ts +1 -17
  212. package/dist/wirings/cli/define-cli-commands.js +1 -17
  213. package/dist/wirings/credential/credential.types.d.ts +0 -12
  214. package/dist/wirings/credential/define-credential.d.ts +48 -0
  215. package/dist/wirings/credential/define-credential.js +47 -0
  216. package/dist/wirings/credential/index.d.ts +1 -1
  217. package/dist/wirings/credential/index.js +1 -1
  218. package/dist/wirings/credential/validate-credential-definitions.d.ts +2 -4
  219. package/dist/wirings/gateway/gateway-runner.d.ts +1 -20
  220. package/dist/wirings/gateway/gateway-runner.js +8 -105
  221. package/dist/wirings/gateway/gateway.types.d.ts +7 -80
  222. package/dist/wirings/http/http-routes.d.ts +0 -63
  223. package/dist/wirings/http/http-routes.js +0 -63
  224. package/dist/wirings/http/http-runner.d.ts +0 -99
  225. package/dist/wirings/http/http-runner.js +9 -165
  226. package/dist/wirings/http/http.types.d.ts +14 -55
  227. package/dist/wirings/http/log-http-routes.d.ts +0 -4
  228. package/dist/wirings/http/log-http-routes.js +0 -4
  229. package/dist/wirings/http/pikku-fetch-http-request.d.ts +0 -40
  230. package/dist/wirings/http/pikku-fetch-http-request.js +0 -58
  231. package/dist/wirings/http/pikku-fetch-http-response.js +0 -3
  232. package/dist/wirings/http/routers/path-to-regex.js +2 -13
  233. package/dist/wirings/http/web-request.d.ts +0 -8
  234. package/dist/wirings/http/web-request.js +25 -17
  235. package/dist/wirings/mcp/mcp-runner.d.ts +1 -4
  236. package/dist/wirings/mcp/mcp-runner.js +1 -14
  237. package/dist/wirings/mcp/mcp.types.d.ts +2 -35
  238. package/dist/wirings/oauth2/oauth2.types.d.ts +0 -28
  239. package/dist/wirings/oauth2/oauth2.types.js +0 -3
  240. package/dist/wirings/persona/define-personas.d.ts +32 -0
  241. package/dist/wirings/persona/define-personas.js +31 -0
  242. package/dist/wirings/persona/index.d.ts +21 -0
  243. package/dist/wirings/persona/index.js +17 -0
  244. package/dist/wirings/persona/persona-email.d.ts +37 -0
  245. package/dist/wirings/persona/persona-email.js +69 -0
  246. package/dist/wirings/persona/persona-environments.d.ts +45 -0
  247. package/dist/wirings/persona/persona-environments.js +81 -0
  248. package/dist/wirings/persona/persona-mailbox.d.ts +101 -0
  249. package/dist/wirings/persona/persona-mailbox.js +53 -0
  250. package/dist/wirings/persona/persona.types.d.ts +136 -0
  251. package/dist/wirings/persona/persona.types.js +1 -0
  252. package/dist/wirings/persona/validate-personas.d.ts +53 -0
  253. package/dist/wirings/persona/validate-personas.js +94 -0
  254. package/dist/wirings/queue/index.d.ts +3 -0
  255. package/dist/wirings/queue/index.js +2 -3
  256. package/dist/wirings/queue/queue-identity.d.ts +28 -0
  257. package/dist/wirings/queue/queue-identity.js +103 -0
  258. package/dist/wirings/queue/queue-runner.d.ts +0 -19
  259. package/dist/wirings/queue/queue-runner.js +9 -30
  260. package/dist/wirings/queue/queue.types.d.ts +20 -90
  261. package/dist/wirings/queue/register-queue-helper.d.ts +0 -12
  262. package/dist/wirings/queue/register-queue-helper.js +0 -11
  263. package/dist/wirings/queue/signed-queue-service.d.ts +17 -0
  264. package/dist/wirings/queue/signed-queue-service.js +42 -0
  265. package/dist/wirings/queue/validate-worker-config.d.ts +2 -23
  266. package/dist/wirings/queue/validate-worker-config.js +0 -14
  267. package/dist/wirings/role/define-system-role.d.ts +32 -0
  268. package/dist/wirings/role/define-system-role.js +31 -0
  269. package/dist/wirings/role/index.d.ts +3 -0
  270. package/dist/wirings/role/index.js +2 -0
  271. package/dist/wirings/role/role.types.d.ts +43 -0
  272. package/dist/wirings/role/role.types.js +1 -0
  273. package/dist/wirings/role/validate-role-definitions.d.ts +21 -0
  274. package/dist/wirings/role/validate-role-definitions.js +71 -0
  275. package/dist/wirings/rpc/addon-runner.d.ts +0 -19
  276. package/dist/wirings/rpc/addon-runner.js +0 -51
  277. package/dist/wirings/rpc/remote-addon-auth.d.ts +3 -13
  278. package/dist/wirings/rpc/remote-addon-auth.js +7 -11
  279. package/dist/wirings/rpc/rpc-runner.d.ts +11 -18
  280. package/dist/wirings/rpc/rpc-runner.js +88 -105
  281. package/dist/wirings/rpc/rpc-types.d.ts +7 -6
  282. package/dist/wirings/rpc/wire-addon.d.ts +25 -0
  283. package/dist/wirings/rpc/wire-addon.js +62 -0
  284. package/dist/wirings/rpc/wire-remote-addon.d.ts +3 -28
  285. package/dist/wirings/rpc/wire-remote-addon.js +0 -8
  286. package/dist/wirings/scheduler/log-schedulers.d.ts +0 -4
  287. package/dist/wirings/scheduler/log-schedulers.js +0 -4
  288. package/dist/wirings/scheduler/scheduler-runner.d.ts +0 -1
  289. package/dist/wirings/scheduler/scheduler-runner.js +0 -1
  290. package/dist/wirings/scheduler/scheduler.types.d.ts +1 -14
  291. package/dist/wirings/scope/define-scope.d.ts +32 -0
  292. package/dist/wirings/scope/define-scope.js +31 -0
  293. package/dist/wirings/scope/index.d.ts +1 -1
  294. package/dist/wirings/scope/index.js +1 -1
  295. package/dist/wirings/scope/scope.types.d.ts +7 -9
  296. package/dist/wirings/scope/validate-scope-definitions.d.ts +2 -21
  297. package/dist/wirings/scope/validate-scope-definitions.js +3 -21
  298. package/dist/wirings/secret/index.d.ts +1 -1
  299. package/dist/wirings/secret/index.js +1 -1
  300. package/dist/wirings/secret/secret.types.d.ts +19 -15
  301. package/dist/wirings/secret/secret.types.js +1 -1
  302. package/dist/wirings/secret/validate-secret-definitions.d.ts +2 -4
  303. package/dist/wirings/trigger/trigger-runner.d.ts +0 -27
  304. package/dist/wirings/trigger/trigger-runner.js +1 -24
  305. package/dist/wirings/trigger/trigger.types.d.ts +1 -82
  306. package/dist/wirings/trigger/trigger.types.js +0 -34
  307. package/dist/wirings/variable/index.d.ts +1 -1
  308. package/dist/wirings/variable/index.js +1 -1
  309. package/dist/wirings/variable/validate-variable-definitions.d.ts +2 -4
  310. package/dist/wirings/variable/variable.types.d.ts +1 -13
  311. package/dist/wirings/variable/variable.types.js +1 -1
  312. package/dist/wirings/virtual-user/index.d.ts +30 -0
  313. package/dist/wirings/virtual-user/index.js +10 -0
  314. package/dist/wirings/virtual-user/prepare-virtual-user-run.d.ts +54 -0
  315. package/dist/wirings/virtual-user/prepare-virtual-user-run.js +49 -0
  316. package/dist/wirings/virtual-user/run-virtual-user.d.ts +92 -0
  317. package/dist/wirings/virtual-user/run-virtual-user.js +478 -0
  318. package/dist/wirings/virtual-user/virtual-user-agents.d.ts +38 -0
  319. package/dist/wirings/virtual-user/virtual-user-agents.js +24 -0
  320. package/dist/wirings/virtual-user/virtual-user-catalogue.d.ts +92 -0
  321. package/dist/wirings/virtual-user/virtual-user-catalogue.js +134 -0
  322. package/dist/wirings/virtual-user/virtual-user-derive.d.ts +26 -0
  323. package/dist/wirings/virtual-user/virtual-user-derive.js +137 -0
  324. package/dist/wirings/virtual-user/virtual-user-dispositions.d.ts +79 -0
  325. package/dist/wirings/virtual-user/virtual-user-dispositions.js +128 -0
  326. package/dist/wirings/virtual-user/virtual-user-intents.d.ts +78 -0
  327. package/dist/wirings/virtual-user/virtual-user-intents.js +142 -0
  328. package/dist/wirings/virtual-user/virtual-user-rng.d.ts +24 -0
  329. package/dist/wirings/virtual-user/virtual-user-rng.js +44 -0
  330. package/dist/wirings/virtual-user/virtual-user-run-store.d.ts +90 -0
  331. package/dist/wirings/virtual-user/virtual-user-run-store.js +1 -0
  332. package/dist/wirings/virtual-user/virtual-user-target.d.ts +21 -0
  333. package/dist/wirings/virtual-user/virtual-user-target.js +34 -0
  334. package/dist/wirings/virtual-user/virtual-user.types.d.ts +199 -0
  335. package/dist/wirings/virtual-user/virtual-user.types.js +8 -0
  336. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +19 -15
  337. package/dist/wirings/workflow/dsl/workflow-runner.d.ts +0 -4
  338. package/dist/wirings/workflow/dsl/workflow-runner.js +0 -4
  339. package/dist/wirings/workflow/feature.d.ts +0 -19
  340. package/dist/wirings/workflow/feature.js +0 -19
  341. package/dist/wirings/workflow/graph/graph-node.d.ts +0 -98
  342. package/dist/wirings/workflow/graph/graph-node.js +0 -34
  343. package/dist/wirings/workflow/graph/graph-runner.js +6 -41
  344. package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +0 -4
  345. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +0 -58
  346. package/dist/wirings/workflow/graph/workflow-graph.types.js +0 -6
  347. package/dist/wirings/workflow/index.d.ts +5 -7
  348. package/dist/wirings/workflow/index.js +3 -17
  349. package/dist/wirings/workflow/pikku-scenario-service.d.ts +87 -5
  350. package/dist/wirings/workflow/pikku-scenario-service.js +204 -43
  351. package/dist/wirings/workflow/pikku-workflow-service.d.ts +7 -459
  352. package/dist/wirings/workflow/pikku-workflow-service.js +58 -551
  353. package/dist/wirings/workflow/run-timeline.d.ts +0 -47
  354. package/dist/wirings/workflow/run-timeline.js +0 -22
  355. package/dist/wirings/workflow/scenario-cookie-jar.d.ts +0 -23
  356. package/dist/wirings/workflow/scenario-cookie-jar.js +0 -16
  357. package/dist/wirings/workflow/scenario-poll.d.ts +0 -15
  358. package/dist/wirings/workflow/scenario-poll.js +0 -12
  359. package/dist/wirings/workflow/scenario-prose.d.ts +0 -28
  360. package/dist/wirings/workflow/scenario-prose.js +1 -19
  361. package/dist/wirings/workflow/scenario-step-guards.d.ts +0 -13
  362. package/dist/wirings/workflow/scenario-step-guards.js +1 -14
  363. package/dist/wirings/workflow/scenario-step.types.d.ts +84 -12
  364. package/dist/wirings/workflow/scenario-step.types.js +5 -1
  365. package/dist/wirings/workflow/scenario-surface.d.ts +16 -0
  366. package/dist/wirings/workflow/scenario-surface.js +56 -0
  367. package/dist/wirings/workflow/workflow-invocation-id.d.ts +0 -18
  368. package/dist/wirings/workflow/workflow-invocation-id.js +2 -22
  369. package/dist/wirings/workflow/workflow-queue-workers.d.ts +0 -20
  370. package/dist/wirings/workflow/workflow-queue-workers.js +0 -19
  371. package/dist/wirings/workflow/workflow.types.d.ts +5 -195
  372. package/knowledge/decisions/index.md +19 -0
  373. package/knowledge/decisions/internals/a-secret-that-fails-to-decrypt-fails-the-whole-read.md +49 -0
  374. package/knowledge/decisions/internals/a-virtual-user-run-is-not-a-workflow-and-not-a-queued-job.md +48 -0
  375. package/knowledge/decisions/internals/actor-flow-conversations-seed-a-hidden-kickoff-message.md +23 -0
  376. package/knowledge/decisions/internals/actor-flow-drives-the-target-through-a-transport-seam.md +24 -0
  377. package/knowledge/decisions/internals/actor-flow-verdicts-are-llm-self-evaluations.md +25 -0
  378. package/knowledge/decisions/internals/addon-package-roots-resolve-by-walking-node-module-search-paths.md +26 -0
  379. package/knowledge/decisions/internals/addon-singleton-services-are-cached-per-namespace-not-per-package.md +33 -0
  380. package/knowledge/decisions/internals/addon-workflow-names-are-prefixed-with-the-consumer-namespace.md +28 -0
  381. package/knowledge/decisions/internals/ai-agent-agui-bridge-obeys-the-client-ordering-contract.md +29 -0
  382. package/knowledge/decisions/internals/ai-agent-audio-chunks-carry-the-format-the-provider-returned.md +20 -0
  383. package/knowledge/decisions/internals/ai-agent-credential-suspensions-hide-the-tool-result.md +26 -0
  384. package/knowledge/decisions/internals/ai-agent-delegate-and-supervise-hide-different-text.md +26 -0
  385. package/knowledge/decisions/internals/ai-agent-llm-tool-arguments-have-nulls-stripped.md +23 -0
  386. package/knowledge/decisions/internals/ai-agent-model-config-stays-a-single-resolution-seam.md +25 -0
  387. package/knowledge/decisions/internals/ai-agent-onerror-hooks-cannot-change-the-failure.md +22 -0
  388. package/knowledge/decisions/internals/ai-agent-runner-methods-must-keep-their-receiver.md +22 -0
  389. package/knowledge/decisions/internals/ai-agent-stream-persistence-is-best-effort.md +27 -0
  390. package/knowledge/decisions/internals/ai-agent-sub-agents-inherit-the-parent-context-block.md +26 -0
  391. package/knowledge/decisions/internals/ai-agent-tool-execute-failures-are-logged-unconditionally.md +25 -0
  392. package/knowledge/decisions/internals/ai-agent-voice-input-transcribes-audio-parts-in-place.md +22 -0
  393. package/knowledge/decisions/internals/ai-agent-working-memory-is-persisted-only-when-valid.md +25 -0
  394. package/knowledge/decisions/internals/channel-message-handlers-accept-three-config-shapes.md +30 -0
  395. package/knowledge/decisions/internals/channel-middleware-caches-only-statically-resolved-middleware.md +31 -0
  396. package/knowledge/decisions/internals/channel-state-is-per-socket-session-state-is-per-user.md +29 -0
  397. package/knowledge/decisions/internals/channel-user-id-is-persisted-after-onconnect-middleware-runs.md +28 -0
  398. package/knowledge/decisions/internals/cli-option-names-are-camelcase-in-state-and-kebab-on-the-command-line.md +27 -0
  399. package/knowledge/decisions/internals/cli-parse-errors-are-routed-by-message-prefix.md +28 -0
  400. package/knowledge/decisions/internals/cli-stdout-is-reserved-for-machine-readable-output.md +34 -0
  401. package/knowledge/decisions/internals/cli-unknown-long-options-warn-instead-of-failing.md +29 -0
  402. package/knowledge/decisions/internals/core-column-form-is-an-axis-of-its-own.md +84 -0
  403. package/knowledge/decisions/internals/core-data-classification-brand-is-an-optional-property.md +41 -0
  404. package/knowledge/decisions/internals/core-function-runner-restores-the-wire-fields-it-overwrites.md +44 -0
  405. package/knowledge/decisions/internals/core-hot-reload-merges-generated-meta-never-replaces-it.md +39 -0
  406. package/knowledge/decisions/internals/core-hot-reload-owns-its-module-registry.md +42 -0
  407. package/knowledge/decisions/internals/core-middleware-order-is-scope-then-priority.md +39 -0
  408. package/knowledge/decisions/internals/core-schema-defaults-apply-on-every-transport.md +43 -0
  409. package/knowledge/decisions/internals/core-scopes-are-an-and-gate-separate-from-permissions.md +38 -0
  410. package/knowledge/decisions/internals/core-state-is-a-global-map-written-only-at-registration-time.md +44 -0
  411. package/knowledge/decisions/internals/email-meta-is-read-uncached-because-codegen-rewrites-it-mid-session.md +27 -0
  412. package/knowledge/decisions/internals/gateway-adapters-resolve-lazily-and-are-promise-cached.md +32 -0
  413. package/knowledge/decisions/internals/gateway-webhook-challenges-echo-bytes-not-json.md +28 -0
  414. package/knowledge/decisions/internals/gateway-wiring-is-a-meta-wiring-over-http-and-channels.md +31 -0
  415. package/knowledge/decisions/internals/generated-src-paths-in-pikku-meta-are-absolute.md +26 -0
  416. package/knowledge/decisions/internals/http-request-bodies-are-read-once-and-shared.md +32 -0
  417. package/knowledge/decisions/internals/http-route-groups-cascade-config-in-a-fixed-order.md +28 -0
  418. package/knowledge/decisions/internals/http-router-matches-normalized-paths-but-returns-registered-ones.md +30 -0
  419. package/knowledge/decisions/internals/http-runner-logs-through-a-trace-scoped-logger-functions-do-not.md +26 -0
  420. package/knowledge/decisions/internals/http-set-cookie-headers-are-appended-never-joined.md +28 -0
  421. package/knowledge/decisions/internals/http-sse-streams-flush-headers-only-after-middleware.md +32 -0
  422. package/knowledge/decisions/internals/http-wiring-without-metadata-is-skipped-not-fatal.md +26 -0
  423. package/knowledge/decisions/internals/in-a-scenario-a-4xx-is-data-not-an-exception.md +25 -0
  424. package/knowledge/decisions/internals/in-memory-workflow-history-aliases-the-live-step-object.md +26 -0
  425. package/knowledge/decisions/internals/index.md +117 -0
  426. package/knowledge/decisions/internals/istanbul-statement-counts-attach-to-the-start-line-only.md +25 -0
  427. package/knowledge/decisions/internals/local-trigger-and-gateway-services-assume-a-single-process.md +26 -0
  428. package/knowledge/decisions/internals/node-only-builtins-are-imported-dynamically.md +24 -0
  429. package/knowledge/decisions/internals/one-project-shape-check-two-validators.md +53 -0
  430. package/knowledge/decisions/internals/queue-group-concurrency-keeps-one-shared-queue-fair.md +28 -0
  431. package/knowledge/decisions/internals/queue-jobs-always-carry-an-explicit-attempts-count.md +27 -0
  432. package/knowledge/decisions/internals/remote-addons-dispatch-over-http-instead-of-local-meta.md +31 -0
  433. package/knowledge/decisions/internals/rpc-names-resolve-through-package-scope-before-root.md +32 -0
  434. package/knowledge/decisions/internals/scenario-agent-calls-sign-in-on-401-only.md +27 -0
  435. package/knowledge/decisions/internals/scenario-meta-lives-apart-from-app-meta-but-merges-when-read-off-disk.md +26 -0
  436. package/knowledge/decisions/internals/scenario-steps-return-drained-response-records.md +27 -0
  437. package/knowledge/decisions/internals/scenarios-live-in-files-named-for-them.md +48 -0
  438. package/knowledge/decisions/internals/scope-roots-may-be-co-declared-by-an-addon-and-its-host-app.md +30 -0
  439. package/knowledge/decisions/internals/serverless-channel-disconnect-must-tolerate-a-missing-channel.md +28 -0
  440. package/knowledge/decisions/internals/the-dev-queue-copies-prod-timing-and-serialization-semantics.md +30 -0
  441. package/knowledge/decisions/internals/the-embedding-model-is-pinned-per-service-and-doc-query-embedding-is-split.md +29 -0
  442. package/knowledge/decisions/internals/the-in-memory-workflow-service-is-inline-only-and-single-process.md +27 -0
  443. package/knowledge/decisions/internals/the-kek-salt-is-scoped-to-the-key-version.md +40 -0
  444. package/knowledge/decisions/internals/the-schema-service-is-never-stubbed.md +26 -0
  445. package/knowledge/decisions/internals/trigger-declaration-is-split-from-trigger-source.md +33 -0
  446. package/knowledge/decisions/internals/typed-secret-service-caches-for-the-process-lifetime.md +26 -0
  447. package/knowledge/decisions/internals/validate-checks-personas-through-a-shared-module.md +43 -0
  448. package/knowledge/decisions/internals/webhook-delivery-history-records-every-attempt-best-effort.md +26 -0
  449. package/knowledge/decisions/internals/webhook-service-collaborators-are-constructor-args-not-locator-lookups.md +25 -0
  450. package/knowledge/decisions/internals/whether-a-run-is-inline-is-read-from-the-run-record.md +58 -0
  451. package/knowledge/decisions/internals/workflow-approval-expiry-is-decided-from-a-recorded-deadline.md +34 -0
  452. package/knowledge/decisions/internals/workflow-core-never-imports-a-browser-driver.md +42 -0
  453. package/knowledge/decisions/internals/workflow-dsl-meta-separates-runtime-expressions-from-literals.md +38 -0
  454. package/knowledge/decisions/internals/workflow-features-resolve-scenarios-by-object-identity.md +29 -0
  455. package/knowledge/decisions/internals/workflow-graph-inline-and-queued-runs-share-one-planner.md +42 -0
  456. package/knowledge/decisions/internals/workflow-graph-node-notes-are-excluded-from-the-graph-hash.md +25 -0
  457. package/knowledge/decisions/internals/workflow-inline-runs-report-their-run-id-before-they-can-fail.md +29 -0
  458. package/knowledge/decisions/internals/workflow-invocation-id-is-the-dedupe-key-not-step-id.md +43 -0
  459. package/knowledge/decisions/internals/workflow-queued-step-dispatch-requires-an-explicit-opt-in.md +29 -0
  460. package/knowledge/decisions/internals/workflow-queues-are-per-workflow-by-default.md +42 -0
  461. package/knowledge/decisions/internals/workflow-repeated-step-names-get-an-ordinal-suffix.md +33 -0
  462. package/knowledge/decisions/internals/workflow-replay-reads-its-steps-once-and-caches-only-the-immutable-half.md +32 -0
  463. package/knowledge/decisions/internals/workflow-retries-are-owned-by-the-workflow-not-the-queue.md +31 -0
  464. package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md +39 -0
  465. package/knowledge/decisions/internals/workflow-run-mirror-is-never-a-source-of-truth.md +29 -0
  466. package/knowledge/decisions/internals/workflow-run-polling-backs-off-to-the-callers-ceiling.md +33 -0
  467. package/knowledge/decisions/internals/workflow-run-timeline-is-a-pure-fold-over-durable-history.md +37 -0
  468. package/knowledge/decisions/internals/workflow-scenario-assertions-never-retry-and-record-one-step.md +50 -0
  469. package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md +43 -0
  470. package/knowledge/decisions/internals/workflow-scenario-prose-is-rendered-from-typed-calls-not-parsed-from-english.md +32 -0
  471. package/knowledge/decisions/internals/workflow-scenario-quarantine-reason-lives-in-code.md +18 -0
  472. package/knowledge/decisions/internals/workflow-scenario-step-targets-are-string-literals-for-the-inspector.md +34 -0
  473. package/knowledge/decisions/internals/workflow-step-compensation-runs-as-its-own-durable-step.md +26 -0
  474. package/knowledge/decisions/internals/workflow-step-dispatch-failure-is-transient-not-a-run-failure.md +33 -0
  475. package/knowledge/decisions/internals/workflow-step-lock-is-held-only-to-claim-the-step.md +27 -0
  476. package/knowledge/decisions/internals/workflow-step-rpc-name-is-provenance-only.md +34 -0
  477. package/knowledge/decisions/internals/workflow-suspend-and-approval-reasons-are-durable-step-identities.md +38 -0
  478. package/knowledge/decisions/internals/workflow-suspended-runs-keep-their-in-process-context.md +30 -0
  479. package/knowledge/decisions/security/a-dropped-audit-write-is-always-logged.md +26 -0
  480. package/knowledge/decisions/security/actor-flow-missing-approval-decisions-default-to-denied.md +22 -0
  481. package/knowledge/decisions/security/actor-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md +27 -0
  482. package/knowledge/decisions/security/actor-sign-in-only-works-for-actor-flagged-users.md +27 -0
  483. package/knowledge/decisions/security/addon-auth-and-tags-only-tighten.md +43 -0
  484. package/knowledge/decisions/security/addon-config-gates-apply-only-at-the-namespaced-rpc-boundary.md +52 -0
  485. package/knowledge/decisions/security/addon-scopes-are-resolved-where-the-function-runs.md +46 -0
  486. package/knowledge/decisions/security/ai-agent-approval-forwarding-requires-a-symbol-brand.md +27 -0
  487. package/knowledge/decisions/security/ai-agent-credential-requests-are-symbol-branded.md +37 -0
  488. package/knowledge/decisions/security/ai-agent-gate-requires-a-session-only-when-auth-is-true.md +31 -0
  489. package/knowledge/decisions/security/ai-agent-ownership-failures-never-echo-the-resource.md +23 -0
  490. package/knowledge/decisions/security/ai-agent-resume-re-runs-the-authorization-gate.md +22 -0
  491. package/knowledge/decisions/security/ai-agent-sessionless-deployments-have-no-thread-ownership.md +39 -0
  492. package/knowledge/decisions/security/ai-agent-thread-ownership-composes-the-session-principal.md +30 -0
  493. package/knowledge/decisions/security/ai-agent-tool-filtering-reads-the-live-function-config.md +24 -0
  494. package/knowledge/decisions/security/an-empty-owners-constraint-matches-nothing.md +30 -0
  495. package/knowledge/decisions/security/an-exposed-ungated-function-is-a-codegen-warning.md +49 -0
  496. package/knowledge/decisions/security/console-addon-privileged-functions-gate-themselves.md +76 -0
  497. package/knowledge/decisions/security/core-safe-fetch-blocks-ssrf-by-host-literal-not-dns.md +39 -0
  498. package/knowledge/decisions/security/core-secrets-use-a-per-secret-dek-wrapped-by-a-kek.md +37 -0
  499. package/knowledge/decisions/security/gateway-handlers-run-through-the-function-runner-gate.md +31 -0
  500. package/knowledge/decisions/security/gateway-middleware-sessions-must-be-bridged-onto-the-wire.md +30 -0
  501. package/knowledge/decisions/security/global-permissions-and-function-permissions-are-independent-gates.md +40 -0
  502. package/knowledge/decisions/security/http-error-detail-is-withheld-from-clients-in-production.md +33 -0
  503. package/knowledge/decisions/security/http-request-bodies-are-bounded-before-they-are-buffered.md +46 -0
  504. package/knowledge/decisions/security/index.md +55 -0
  505. package/knowledge/decisions/security/mcp-internal-error-details-are-double-gated-on-production.md +27 -0
  506. package/knowledge/decisions/security/passphrases-are-stretched-key-material-is-expanded.md +40 -0
  507. package/knowledge/decisions/security/permission-auth-filtering-requires-live-permission-functions.md +31 -0
  508. package/knowledge/decisions/security/pikku-carries-actor-scopes-as-data-and-the-app-grants-them.md +26 -0
  509. package/knowledge/decisions/security/queue-job-identities-are-signed-at-enqueue.md +69 -0
  510. package/knowledge/decisions/security/queue-jobs-carry-the-producers-pikku-user-id.md +39 -0
  511. package/knowledge/decisions/security/remote-addon-tokens-are-client-credentials-not-mesh-trust.md +34 -0
  512. package/knowledge/decisions/security/scaffold-features-are-authenticated-unless-opted-out.md +49 -0
  513. package/knowledge/decisions/security/scenario-step-functions-are-never-externally-invocable.md +30 -0
  514. package/knowledge/decisions/security/scope-resolution-happens-at-the-session-boundary-and-sync-never-deletes.md +28 -0
  515. package/knowledge/decisions/security/self-authentication-is-declared-not-detected.md +34 -0
  516. package/knowledge/decisions/security/signed-content-urls-bind-the-request-path.md +37 -0
  517. package/knowledge/decisions/security/webhook-bodies-are-signed-before-they-are-enqueued.md +25 -0
  518. package/knowledge/decisions/security/workflow-actor-steps-always-use-the-real-transport.md +34 -0
  519. package/knowledge/decisions/security/workflow-approval-payloads-are-validated-on-replay-inside-the-workflow.md +40 -0
  520. package/knowledge/decisions/security/workflow-queued-steps-rehydrate-their-session-from-the-run-wire.md +32 -0
  521. package/knowledge/decisions/security/workflow-scenario-sessions-are-isolated-per-actor-and-per-scenario.md +32 -0
  522. package/knowledge/decisions/security/workflow-scenario-steps-are-never-network-invocable.md +31 -0
  523. package/knowledge/index.md +24 -0
  524. package/knowledge/questions/index.md +15 -0
  525. package/package.json +6 -2
  526. package/run-tests.sh +0 -0
  527. package/src/column-form.test.ts +97 -0
  528. package/src/column-form.ts +58 -0
  529. package/src/crypto-utils.test.ts +460 -19
  530. package/src/crypto-utils.ts +306 -59
  531. package/src/data-classification.ts +45 -7
  532. package/src/dev/hot-reload.test.ts +0 -4
  533. package/src/dev/hot-reload.ts +11 -30
  534. package/src/dev/module-runner.ts +7 -32
  535. package/src/dev/reload-meta.ts +9 -29
  536. package/src/errors/error-handler.ts +20 -35
  537. package/src/errors/error.test.ts +30 -1
  538. package/src/errors/errors.ts +73 -157
  539. package/src/function/abort-scope.test.ts +97 -0
  540. package/src/function/abort-scope.ts +80 -0
  541. package/src/function/function-runner.test.ts +0 -7
  542. package/src/function/function-runner.ts +62 -32
  543. package/src/function/functions.types.ts +95 -138
  544. package/src/function/index.ts +1 -0
  545. package/src/function/list.types.test.ts +3 -25
  546. package/src/function/list.types.ts +12 -62
  547. package/src/handle-error.ts +0 -18
  548. package/src/index.ts +84 -3
  549. package/src/middleware/auth-apikey.test.ts +0 -1
  550. package/src/middleware/auth-apikey.ts +0 -17
  551. package/src/middleware/auth-bearer.test.ts +3 -5
  552. package/src/middleware/auth-bearer.ts +5 -41
  553. package/src/middleware/auth-cookie.test.ts +0 -6
  554. package/src/middleware/auth-cookie.ts +2 -26
  555. package/src/middleware/cors.test.ts +34 -0
  556. package/src/middleware/cors.ts +12 -33
  557. package/src/middleware/remote-auth.test.ts +26 -10
  558. package/src/middleware/remote-auth.ts +11 -3
  559. package/src/middleware/telemetry.ts +2 -31
  560. package/src/middleware-runner.test.ts +0 -2
  561. package/src/middleware-runner.ts +5 -74
  562. package/src/permissions.test.ts +30 -0
  563. package/src/permissions.ts +24 -74
  564. package/src/pikku-request.ts +0 -6
  565. package/src/pikku-state.ts +2 -30
  566. package/src/production-barrels-stay-lean.test.ts +110 -0
  567. package/src/remote.test.ts +173 -0
  568. package/src/remote.ts +18 -8
  569. package/src/schema.ts +5 -39
  570. package/src/scopes.ts +7 -48
  571. package/src/secret-value.test.ts +204 -0
  572. package/src/secret-value.ts +111 -0
  573. package/src/services/ai-agent-runner-service.ts +20 -0
  574. package/src/services/ai-embedding-service.ts +3 -25
  575. package/src/services/audit-service.ts +88 -11
  576. package/src/services/content-service.ts +1 -46
  577. package/src/services/credential-service.ts +3 -40
  578. package/src/services/credential-wire-service.test.ts +0 -2
  579. package/src/services/credential-wire-service.ts +9 -1
  580. package/src/services/deployment-service.ts +3 -9
  581. package/src/services/email-service.ts +3 -1
  582. package/src/services/gateway-service.ts +0 -15
  583. package/src/services/{http-scenario-actors-converse.test.ts → http-personas-converse.test.ts} +38 -9
  584. package/src/services/{http-scenario-actors.test.ts → http-personas.test.ts} +39 -22
  585. package/src/services/{http-scenario-actors.ts → http-personas.ts} +85 -45
  586. package/src/services/in-memory-queue-service.ts +1 -15
  587. package/src/services/in-memory-trigger-service.ts +1 -18
  588. package/src/services/in-memory-workflow-service.test.ts +0 -13
  589. package/src/services/in-memory-workflow-service.ts +4 -38
  590. package/src/services/index.ts +23 -18
  591. package/src/services/istanbul-coverage-service.ts +2 -8
  592. package/src/services/jwt-service.ts +1 -16
  593. package/src/services/local-content-request-handler.test.ts +202 -0
  594. package/src/services/local-content-request-handler.ts +267 -0
  595. package/src/services/local-content.test.ts +159 -27
  596. package/src/services/local-content.ts +55 -23
  597. package/src/services/local-gateway-service.ts +2 -17
  598. package/src/services/local-secrets.test.ts +20 -5
  599. package/src/services/local-secrets.ts +15 -11
  600. package/src/services/logger-console.test.ts +0 -1
  601. package/src/services/logger-console.ts +3 -7
  602. package/src/services/logger.ts +31 -46
  603. package/src/services/meta-service.test.ts +1 -5
  604. package/src/services/meta-service.ts +41 -61
  605. package/src/services/{scenario-actors-service.ts → personas-service.ts} +48 -43
  606. package/src/services/pikku-user-id.ts +0 -4
  607. package/src/services/queue-webhook-service.test.ts +2 -1
  608. package/src/services/queue-webhook-service.ts +10 -42
  609. package/src/services/scheduler-service.ts +1 -50
  610. package/src/services/schema-service.ts +1 -24
  611. package/src/services/scope-service.ts +50 -34
  612. package/src/services/scoped-secret-service.ts +4 -7
  613. package/src/services/secret-host-binding.test.ts +138 -0
  614. package/src/services/secret-host-binding.ts +51 -0
  615. package/src/services/secret-service.ts +12 -35
  616. package/src/services/secretless.test.ts +54 -0
  617. package/src/services/secretless.ts +29 -0
  618. package/src/services/stub-tracker.ts +8 -18
  619. package/src/services/system-role-guard.test.ts +93 -0
  620. package/src/services/system-role-guard.ts +71 -0
  621. package/src/services/trigger-service.ts +0 -12
  622. package/src/services/typed-secret-service.ts +12 -14
  623. package/src/services/v8-coverage-service.ts +3 -6
  624. package/src/services/variables-service.ts +1 -8
  625. package/src/services/webhook-service.ts +23 -64
  626. package/src/services/workflow-service.ts +3 -20
  627. package/src/testing/service-tests.ts +6 -32
  628. package/src/time-utils.ts +1 -19
  629. package/src/types/core.types.ts +137 -229
  630. package/src/types/state.types.ts +7 -9
  631. package/src/utils/hmac.ts +4 -10
  632. package/src/utils/safe-fetch.ts +13 -54
  633. package/src/utils.test.ts +11 -2
  634. package/src/utils.ts +6 -15
  635. package/src/wirings/actor-flow/actor-flow.types.ts +1 -34
  636. package/src/wirings/actor-flow/index.ts +0 -9
  637. package/src/wirings/actor-flow/run-conversation.test.ts +11 -6
  638. package/src/wirings/actor-flow/run-conversation.ts +19 -12
  639. package/src/wirings/ai-agent/ai-agent-agui.test.ts +91 -10
  640. package/src/wirings/ai-agent/ai-agent-agui.ts +49 -17
  641. package/src/wirings/ai-agent/ai-agent-helpers.ts +20 -0
  642. package/src/wirings/ai-agent/ai-agent-interrupt.test.ts +842 -0
  643. package/src/wirings/ai-agent/ai-agent-interrupt.ts +399 -0
  644. package/src/wirings/ai-agent/ai-agent-memory.ts +0 -2
  645. package/src/wirings/ai-agent/ai-agent-model-config.ts +1 -9
  646. package/src/wirings/ai-agent/ai-agent-prepare.test.ts +202 -31
  647. package/src/wirings/ai-agent/ai-agent-prepare.ts +89 -139
  648. package/src/wirings/ai-agent/ai-agent-registry.test.ts +191 -6
  649. package/src/wirings/ai-agent/ai-agent-registry.ts +18 -1
  650. package/src/wirings/ai-agent/ai-agent-resume-authorization.test.ts +0 -2
  651. package/src/wirings/ai-agent/ai-agent-runner.test.ts +11 -9
  652. package/src/wirings/ai-agent/ai-agent-runner.ts +85 -35
  653. package/src/wirings/ai-agent/ai-agent-stream.test.ts +205 -103
  654. package/src/wirings/ai-agent/ai-agent-stream.ts +224 -76
  655. package/src/wirings/ai-agent/ai-agent-thread-ownership.test.ts +301 -0
  656. package/src/wirings/ai-agent/ai-agent.types.ts +130 -5
  657. package/src/wirings/ai-agent/index.ts +37 -3
  658. package/src/wirings/ai-agent/voice-input.test.ts +137 -7
  659. package/src/wirings/ai-agent/voice-input.ts +96 -12
  660. package/src/wirings/ai-agent/voice-output.test.ts +512 -0
  661. package/src/wirings/ai-agent/voice-output.ts +243 -56
  662. package/src/wirings/channel/channel-common.ts +15 -20
  663. package/src/wirings/channel/channel-handler.test.ts +50 -0
  664. package/src/wirings/channel/channel-handler.ts +32 -11
  665. package/src/wirings/channel/channel-host-rpc.test.ts +150 -0
  666. package/src/wirings/channel/channel-host-rpc.ts +69 -0
  667. package/src/wirings/channel/channel-middleware-runner.test.ts +0 -1
  668. package/src/wirings/channel/channel-middleware-runner.ts +0 -12
  669. package/src/wirings/channel/channel-rpc-registry.ts +116 -0
  670. package/src/wirings/channel/channel-rpc-responder.ts +117 -0
  671. package/src/wirings/channel/channel-rpc-service.ts +146 -0
  672. package/src/wirings/channel/channel-rpc-validators.ts +65 -0
  673. package/src/wirings/channel/channel-rpc.test.ts +820 -0
  674. package/src/wirings/channel/channel-rpc.ts +5 -0
  675. package/src/wirings/channel/channel-rpc.types.ts +150 -0
  676. package/src/wirings/channel/channel-runner.ts +0 -14
  677. package/src/wirings/channel/channel-store.ts +0 -10
  678. package/src/wirings/channel/channel.types.ts +19 -8
  679. package/src/wirings/channel/define-channel-routes.ts +0 -20
  680. package/src/wirings/channel/eventhub-service.ts +0 -18
  681. package/src/wirings/channel/index.ts +35 -0
  682. package/src/wirings/channel/local/local-channel-handler.ts +3 -1
  683. package/src/wirings/channel/local/local-channel-runner.test.ts +0 -10
  684. package/src/wirings/channel/local/local-channel-runner.ts +3 -1
  685. package/src/wirings/channel/local/local-eventhub-service.test.ts +0 -13
  686. package/src/wirings/channel/local/local-eventhub-service.ts +2 -37
  687. package/src/wirings/channel/log-channels.ts +0 -4
  688. package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +83 -2
  689. package/src/wirings/channel/pikku-abstract-channel-handler.ts +7 -0
  690. package/src/wirings/channel/serverless/serverless-channel-runner.ts +2 -5
  691. package/src/wirings/cli/channel/cli-approval.test.ts +177 -0
  692. package/src/wirings/cli/channel/cli-approval.ts +135 -0
  693. package/src/wirings/cli/channel/cli-channel-runner.ts +4 -26
  694. package/src/wirings/cli/channel/cli-raw-channel-runner.test.ts +169 -0
  695. package/src/wirings/cli/channel/cli-raw-channel-runner.ts +59 -16
  696. package/src/wirings/cli/channel/cli-raw-client-runner.test.ts +480 -0
  697. package/src/wirings/cli/channel/cli-raw-client-runner.ts +185 -0
  698. package/src/wirings/cli/channel/index.ts +13 -0
  699. package/src/wirings/cli/cli-runner.test.ts +0 -1
  700. package/src/wirings/cli/cli-runner.ts +46 -88
  701. package/src/wirings/cli/cli.types.ts +14 -3
  702. package/src/wirings/cli/command-parser.test.ts +0 -4
  703. package/src/wirings/cli/command-parser.ts +11 -91
  704. package/src/wirings/cli/define-cli-commands.ts +1 -17
  705. package/src/wirings/credential/credential.types.ts +0 -12
  706. package/src/wirings/credential/{wire-credential.ts → define-credential.ts} +7 -7
  707. package/src/wirings/credential/index.ts +1 -1
  708. package/src/wirings/credential/validate-credential-definitions.ts +2 -4
  709. package/src/wirings/gateway/gateway-runner.test.ts +1 -21
  710. package/src/wirings/gateway/gateway-runner.ts +8 -110
  711. package/src/wirings/gateway/gateway.types.ts +7 -80
  712. package/src/wirings/http/http-routes.test.ts +0 -3
  713. package/src/wirings/http/http-routes.ts +0 -86
  714. package/src/wirings/http/http-runner.test.ts +0 -1
  715. package/src/wirings/http/http-runner.ts +8 -167
  716. package/src/wirings/http/http.types.ts +15 -62
  717. package/src/wirings/http/log-http-routes.ts +0 -4
  718. package/src/wirings/http/pikku-fetch-http-request.test.ts +2 -10
  719. package/src/wirings/http/pikku-fetch-http-request.ts +0 -58
  720. package/src/wirings/http/pikku-fetch-http-response.test.ts +1 -1
  721. package/src/wirings/http/pikku-fetch-http-response.ts +0 -3
  722. package/src/wirings/http/routers/path-to-regex.test.ts +4 -17
  723. package/src/wirings/http/routers/path-to-regex.ts +2 -13
  724. package/src/wirings/http/web-request.test.ts +33 -2
  725. package/src/wirings/http/web-request.ts +30 -17
  726. package/src/wirings/mcp/mcp-endpoint-registry.test.ts +0 -1
  727. package/src/wirings/mcp/mcp-runner.ts +2 -17
  728. package/src/wirings/mcp/mcp.types.ts +7 -42
  729. package/src/wirings/oauth2/oauth2.types.ts +0 -30
  730. package/src/wirings/persona/define-personas.ts +33 -0
  731. package/src/wirings/persona/index.ts +62 -0
  732. package/src/wirings/persona/persona-email.ts +87 -0
  733. package/src/wirings/persona/persona-environments.test.ts +183 -0
  734. package/src/wirings/persona/persona-environments.ts +138 -0
  735. package/src/wirings/persona/persona-mailbox.ts +156 -0
  736. package/src/wirings/persona/persona.test.ts +220 -0
  737. package/src/wirings/persona/persona.types.ts +142 -0
  738. package/src/wirings/persona/validate-personas.ts +133 -0
  739. package/src/wirings/queue/index.ts +13 -3
  740. package/src/wirings/queue/queue-identity.test.ts +454 -0
  741. package/src/wirings/queue/queue-identity.ts +176 -0
  742. package/src/wirings/queue/queue-runner.ts +12 -31
  743. package/src/wirings/queue/queue.types.ts +25 -90
  744. package/src/wirings/queue/register-queue-helper.ts +0 -14
  745. package/src/wirings/queue/signed-queue-service.ts +60 -0
  746. package/src/wirings/queue/validate-worker-config.ts +2 -28
  747. package/src/wirings/role/define-system-role.ts +33 -0
  748. package/src/wirings/role/index.ts +13 -0
  749. package/src/wirings/role/role.test.ts +104 -0
  750. package/src/wirings/role/role.types.ts +47 -0
  751. package/src/wirings/role/validate-role-definitions.ts +93 -0
  752. package/src/wirings/rpc/addon-auth-tags.test.ts +223 -0
  753. package/src/wirings/rpc/addon-runner.ts +0 -56
  754. package/src/wirings/rpc/addon-scopes.test.ts +225 -0
  755. package/src/wirings/rpc/remote-addon-auth.ts +9 -16
  756. package/src/wirings/rpc/rpc-runner.test.ts +192 -6
  757. package/src/wirings/rpc/rpc-runner.ts +145 -127
  758. package/src/wirings/rpc/rpc-types.ts +11 -6
  759. package/src/wirings/rpc/wire-addon.test.ts +43 -1
  760. package/src/wirings/rpc/wire-addon.ts +99 -0
  761. package/src/wirings/rpc/wire-remote-addon.ts +9 -29
  762. package/src/wirings/scheduler/log-schedulers.ts +0 -4
  763. package/src/wirings/scheduler/scheduler-runner.test.ts +1 -8
  764. package/src/wirings/scheduler/scheduler-runner.ts +0 -2
  765. package/src/wirings/scheduler/scheduler.types.ts +1 -14
  766. package/src/wirings/scope/{wire-scope.ts → define-scope.ts} +5 -6
  767. package/src/wirings/scope/index.ts +1 -1
  768. package/src/wirings/scope/scope.test.ts +1 -2
  769. package/src/wirings/scope/scope.types.ts +7 -9
  770. package/src/wirings/scope/validate-scope-definitions.ts +3 -21
  771. package/src/wirings/secret/index.ts +1 -1
  772. package/src/wirings/secret/secret.types.ts +19 -15
  773. package/src/wirings/secret/validate-secret-definitions.ts +2 -4
  774. package/src/wirings/trigger/trigger-runner.ts +1 -27
  775. package/src/wirings/trigger/trigger.types.ts +1 -82
  776. package/src/wirings/variable/index.ts +1 -1
  777. package/src/wirings/variable/validate-variable-definitions.ts +2 -4
  778. package/src/wirings/variable/variable.types.ts +1 -13
  779. package/src/wirings/virtual-user/index.ts +88 -0
  780. package/src/wirings/virtual-user/prepare-virtual-user-run.test.ts +115 -0
  781. package/src/wirings/virtual-user/prepare-virtual-user-run.ts +95 -0
  782. package/src/wirings/virtual-user/run-virtual-user.test.ts +765 -0
  783. package/src/wirings/virtual-user/run-virtual-user.ts +671 -0
  784. package/src/wirings/virtual-user/virtual-user-agents.test.ts +65 -0
  785. package/src/wirings/virtual-user/virtual-user-agents.ts +57 -0
  786. package/src/wirings/virtual-user/virtual-user-catalogue.test.ts +215 -0
  787. package/src/wirings/virtual-user/virtual-user-catalogue.ts +184 -0
  788. package/src/wirings/virtual-user/virtual-user-derive.test.ts +398 -0
  789. package/src/wirings/virtual-user/virtual-user-derive.ts +173 -0
  790. package/src/wirings/virtual-user/virtual-user-dispositions.test.ts +63 -0
  791. package/src/wirings/virtual-user/virtual-user-dispositions.ts +213 -0
  792. package/src/wirings/virtual-user/virtual-user-intents.test.ts +208 -0
  793. package/src/wirings/virtual-user/virtual-user-intents.ts +185 -0
  794. package/src/wirings/virtual-user/virtual-user-rng.test.ts +72 -0
  795. package/src/wirings/virtual-user/virtual-user-rng.ts +50 -0
  796. package/src/wirings/virtual-user/virtual-user-run-store.ts +98 -0
  797. package/src/wirings/virtual-user/virtual-user-target.ts +47 -0
  798. package/src/wirings/virtual-user/virtual-user.types.ts +219 -0
  799. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +19 -20
  800. package/src/wirings/workflow/dsl/workflow-runner.ts +0 -4
  801. package/src/wirings/workflow/feature.ts +0 -19
  802. package/src/wirings/workflow/graph/graph-node.ts +0 -136
  803. package/src/wirings/workflow/graph/graph-runner.test.ts +20 -19
  804. package/src/wirings/workflow/graph/graph-runner.ts +6 -41
  805. package/src/wirings/workflow/graph/wire-workflow-graph.ts +0 -4
  806. package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -58
  807. package/src/wirings/workflow/index.ts +10 -44
  808. package/src/wirings/workflow/pikku-scenario-service.ts +235 -61
  809. package/src/wirings/workflow/pikku-workflow-service.test.ts +0 -39
  810. package/src/wirings/workflow/pikku-workflow-service.ts +77 -674
  811. package/src/wirings/workflow/run-timeline.test.ts +7 -19
  812. package/src/wirings/workflow/run-timeline.ts +0 -56
  813. package/src/wirings/workflow/scenario-cookie-jar.test.ts +0 -1
  814. package/src/wirings/workflow/scenario-cookie-jar.ts +0 -25
  815. package/src/wirings/workflow/scenario-expectations.test.ts +2 -7
  816. package/src/wirings/workflow/scenario-hooks.test.ts +2 -7
  817. package/src/wirings/workflow/scenario-poll.test.ts +0 -2
  818. package/src/wirings/workflow/scenario-poll.ts +0 -15
  819. package/src/wirings/workflow/scenario-prose.test.ts +5 -7
  820. package/src/wirings/workflow/scenario-prose.ts +1 -29
  821. package/src/wirings/workflow/scenario-service.test.ts +2 -10
  822. package/src/wirings/workflow/scenario-step-guards.ts +1 -14
  823. package/src/wirings/workflow/scenario-step.test.ts +163 -19
  824. package/src/wirings/workflow/scenario-step.types.ts +94 -12
  825. package/src/wirings/workflow/scenario-surface.test.ts +146 -0
  826. package/src/wirings/workflow/scenario-surface.ts +71 -0
  827. package/src/wirings/workflow/workflow-dispatch-durability.test.ts +14 -15
  828. package/src/wirings/workflow/workflow-dispatch-payload.test.ts +0 -4
  829. package/src/wirings/workflow/workflow-inline-authority.test.ts +169 -0
  830. package/src/wirings/workflow/workflow-invocation-id.test.ts +0 -2
  831. package/src/wirings/workflow/workflow-invocation-id.ts +2 -22
  832. package/src/wirings/workflow/workflow-mirror.test.ts +0 -7
  833. package/src/wirings/workflow/workflow-on-error.test.ts +0 -9
  834. package/src/wirings/workflow/workflow-queue-workers.ts +0 -21
  835. package/src/wirings/workflow/workflow-replay-snapshot.test.ts +8 -7
  836. package/src/wirings/workflow/workflow-retry-policy.test.ts +0 -5
  837. package/src/wirings/workflow/workflow-run-context.test.ts +5 -10
  838. package/src/wirings/workflow/workflow-run-polling.test.ts +0 -5
  839. package/src/wirings/workflow/workflow-step-ordinal.test.ts +19 -4
  840. package/src/wirings/workflow/workflow-step-session.test.ts +0 -7
  841. package/src/wirings/workflow/workflow.types.ts +5 -201
  842. package/tsconfig.tsbuildinfo +1 -1
  843. package/tsconfig.type-tests.json +12 -0
  844. package/src/middleware/timeout.ts +0 -22
  845. package/src/pikku-response.ts +0 -5
  846. package/src/wirings/mcp/mcp-endpoint-registry.test.d.ts +0 -1
  847. package/src/wirings/workflow/dsl/index.ts +0 -36
  848. package/src/wirings/workflow/graph/index.ts +0 -15
@@ -0,0 +1,43 @@
1
+ ---
2
+ type: decision
3
+ title: Scenario lifecycle hooks are a scenario-only affordance and never mask the failure they follow
4
+ description: A durable workflow replays, so a callback that reruns each replay has no honest meaning there
5
+ tags: workflow
6
+ ---
7
+
8
+ # Scenario lifecycle hooks are a scenario-only affordance and never mask the failure they follow
9
+
10
+ `PikkuScenarioService.scenarioHooks` (`pikku-scenario-service.ts`) returns hooks
11
+ only when `workflowMeta.source === 'scenario'`. A plain workflow is durable and
12
+ resumable, so a `before`/`after` callback that reran on every replay would have
13
+ no honest meaning — hooks exist for scenarios because a scenario run is a single
14
+ pass by a single external process.
15
+
16
+ A hook is not a pikku function: it has no id, no meta and no schema, so it
17
+ cannot go through `runPikkuFunc` and the runner records nothing for it. It gets
18
+ exactly what the scenario body gets — the same wire (which is how it reaches the
19
+ app through `actors`) and singleton services composed with this invocation's
20
+ wire services — and nothing else. `ScenarioHookError` keeps the original error
21
+ as `cause`, so the failure that actually happened is never lost behind the label
22
+ saying which phase it happened in.
23
+
24
+ `onAfterRunFunc` returns early on the `interrupted` outcome, because the run is
25
+ suspended or waiting and teardown would fire mid-flight. When the scenario has
26
+ already failed for its own reason, an `after`-hook failure is attached as
27
+ `cause` and logged rather than replacing the headline; only a teardown failure
28
+ after a *passing* scenario fails the run.
29
+
30
+ At the feature level (`workflow.types.ts`, `CoreFeature`), hooks run once around
31
+ the whole group — `before → a → b → c → after` — not per scenario. That is the
32
+ one thing a feature deliberately cannot express: gherkin's `Background:` runs
33
+ per scenario, and per-scenario setup is the scenario's own `before`.
34
+
35
+ `setScenarioEnvironment` on the same service is per-service, not per-run, for a
36
+ related reason: a runner process targets exactly one environment for every
37
+ scenario it executes, so threading it through each run would only create ways
38
+ for two runs in one process to disagree.
39
+
40
+ **What this rules out:** offering hooks on plain workflows, routing a hook
41
+ through `runPikkuFunc` so it gets recorded as a step, running `after` on an
42
+ interrupted run, letting a teardown failure overwrite the scenario's own
43
+ failure, or reinterpreting feature hooks as per-scenario `Background:`.
@@ -0,0 +1,32 @@
1
+ ---
2
+ type: decision
3
+ title: Scenario prose is rendered out of typed calls, not parsed into them
4
+ description: The inversion of cucumber — a readable report with no regex step registry to maintain
5
+ tags: workflow
6
+ ---
7
+
8
+ # Scenario prose is rendered out of typed calls, not parsed into them
9
+
10
+ `scenario-prose.ts` renders the English sentence a reporter shows for a scenario
11
+ step. It is the inversion of cucumber: instead of parsing English into a call
12
+ through a registry of regexes, the call is typed and the English is rendered out
13
+ of it. The readable report survives without anyone maintaining a step-definition
14
+ registry, and a step that no longer exists cannot leave a dangling phrase behind.
15
+
16
+ `renderScenarioProse` fills a step's `template` from the input the step was
17
+ actually called with, so the sentence names the values under test — "sees
18
+ @pikku/addon-todos" rather than "sees an addon in the gallery" three times over.
19
+ A placeholder with no recorded value renders as nothing and the surrounding
20
+ whitespace collapses, so an omitted optional input reads as a shorter sentence
21
+ rather than leaking a literal `{state}` into the report. `template` is
22
+ deliberately distinct from `description`: `description` documents what the step
23
+ does, `template` is what a reader of the report sees, and it falls back to
24
+ `description` when absent.
25
+
26
+ It lives in `@pikku/core` rather than in the CLI so the CLI reporter and the
27
+ console render the same sentence for the same step.
28
+
29
+ **What this rules out:** adding a gherkin parser or regex step registry,
30
+ rendering prose in the CLI reporter or console instead of core (the two would
31
+ drift), collapsing `template` into `description`, or making a missing
32
+ placeholder value render as the raw placeholder.
@@ -0,0 +1,18 @@
1
+ ---
2
+ type: decision
3
+ title: A quarantined scenario states its reason in code, not in a CI invocation
4
+ description: `skip` carries the why next to the scenario it applies to, and naming the scenario explicitly still runs it
5
+ tags: workflow
6
+ ---
7
+
8
+ # A quarantined scenario states its reason in code, not in a CI invocation
9
+
10
+ `WorkflowsMeta`'s `skip` field (`workflow.types.ts`) is a string, not a boolean.
11
+ A scenario held out of a default run has to say why, and stating the reason in
12
+ code keeps the quarantine next to the scenario it applies to rather than buried
13
+ in a CI invocation nobody reads. A skipped scenario is still runnable — naming
14
+ it explicitly with `--flows` runs it regardless — so quarantine is a default,
15
+ not a disablement.
16
+
17
+ **What this rules out:** turning `skip` into a boolean flag, moving the skip
18
+ list into CI configuration, or making a skipped scenario unrunnable.
@@ -0,0 +1,34 @@
1
+ ---
2
+ type: decision
3
+ title: Scenario step targets are string literals so the inspector can read them statically
4
+ description: `step/given/when/then` mirror `do`'s RPC shape because the extractor reads a literal, not an imported symbol
5
+ tags: workflow
6
+ ---
7
+
8
+ # Scenario step targets are string literals so the inspector can read them statically
9
+
10
+ `ScenarioStepInvocation` in `dsl/workflow-dsl.types.ts`, and the `step`,
11
+ `given`, `when` and `then` members of `PikkuScenarioWire`, all take
12
+ `(stepName, stepFunc: string, data?, options?)` — deliberately the same shape as
13
+ `WorkflowWireDoRPC`. The target is a string, not an imported symbol, because
14
+ the Pikku inspector is static analysis: it reads the argument as a literal and
15
+ does not resolve identifiers. Type safety comes back at the edges — the
16
+ generated `TypedScenario` narrows these over `FlattenedScenarioStepMap`.
17
+
18
+ `given`/`when`/`then` are pure sugar over `step`; the phase only changes the
19
+ prose a reporter renders (`scenario-prose.ts`), never what executes.
20
+
21
+ The prose direction is itself the decision: rather than parsing English into a
22
+ call the way cucumber does, `composeStepProse` renders English out of a typed
23
+ call, so a readable report survives without a regex registry paying for it. It
24
+ lives in core so the CLI reporter and the console render the same sentence for
25
+ the same step, and `renderStepTemplate` fills `{placeholders}` from the input
26
+ the step was actually called with — "sees @pikku/addon-todos" rather than the
27
+ same generic sentence three times. A placeholder with no recorded value renders
28
+ as nothing and the surrounding whitespace collapses, so an omitted optional
29
+ input reads as a shorter sentence rather than leaking a literal `{state}`.
30
+
31
+ **What this rules out:** changing `stepFunc` to accept the imported step config,
32
+ reordering the arguments away from `do`'s shape, giving `given`/`when`/`then`
33
+ behaviour of their own, or moving prose rendering into the CLI where the console
34
+ would drift from it.
@@ -0,0 +1,26 @@
1
+ ---
2
+ type: decision
3
+ title: A step's compensation handler runs as a durable step of its own, and never compensates itself
4
+ description: A refund or rollback must not fire twice on replay, so `onError` is recorded as `<step>:onError` with retries disabled
5
+ tags: workflow
6
+ ---
7
+
8
+ # A step's compensation handler runs as a durable step of its own, and never compensates itself
9
+
10
+ `runStepCompensation` in `pikku-workflow-service.ts` invokes a failed step's
11
+ `onError` RPC through `rpcStep` under the name `<stepName>:onError` rather than
12
+ calling it directly. Durability is the point: a compensation handler is
13
+ typically a refund or a rollback, and a bare invoke would fire again on every
14
+ replay that walks past the failed step. Recorded as a step, the second replay
15
+ finds it `succeeded` and returns the cached result.
16
+
17
+ It runs with `{ retries: 0 }` and its own `onError` is deliberately not
18
+ forwarded — a compensation handler cannot itself compensate. `onError` mirrors a
19
+ graph node's: the handler receives `{ error: { message } }`, and the original
20
+ error is still thrown afterwards, so the workflow fails either way. This is
21
+ compensation, not recovery.
22
+
23
+ **What this rules out:** invoking the `onError` RPC inline "since it's just
24
+ cleanup", giving it the workflow's default retry count, chaining a second
25
+ `onError` onto it, or swallowing the original error because the handler
26
+ succeeded.
@@ -0,0 +1,33 @@
1
+ ---
2
+ type: decision
3
+ title: A failed workflow step dispatch is transient infrastructure, not a run failure
4
+ description: Queue-unreachable errors leave the run running and the step pending so the orchestrator replays; marking the run failed loses it
5
+ tags: workflow
6
+ ---
7
+
8
+ # A failed workflow step dispatch is transient infrastructure, not a run failure
9
+
10
+ `WorkflowDispatchException` (`pikku-workflow-service.ts`) means the queue itself
11
+ could not accept the job — pg-boss momentarily down, the transport unreachable —
12
+ not that the step's own logic failed. Everywhere it surfaces (`dispatchStep`,
13
+ `sleepStep`, `startWorkflow`, `orchestrateWorkflow`) the run is left untouched:
14
+ the step stays `pending`, the run stays `running`, and the orchestrator job is
15
+ rethrown so the queue redelivers it and the workflow replays from its snapshot.
16
+
17
+ The ordering inside `rpcStep` and `sleepStep` is load-bearing: dispatch happens
18
+ BEFORE the step is marked `scheduled`. If the step were marked `scheduled`
19
+ first and the dispatch then failed, the next replay would see `scheduled`,
20
+ pause, and wait forever for a job that was never enqueued.
21
+
22
+ Redelivery is always safe because an orchestrator job is idempotent: it replays
23
+ the workflow from the snapshot and every already-completed step returns its
24
+ cached result rather than running again. The per-job `attempts` that
25
+ `resolveStepJobOptions` always emits is what makes redelivery happen at all — it
26
+ overrides a queue configured with `retry_limit 0`, so the workflow's retry
27
+ policy survives a conservative queue configuration.
28
+
29
+ **What this rules out:** folding `WorkflowDispatchException` into the generic
30
+ catch that calls `updateRunStatus(runId, 'failed', ...)`, swallowing it so the
31
+ run silently stalls, or reordering `setStepScheduled` above `dispatchStep` /
32
+ `scheduleSleep` to "keep the status writes together". Each strands or kills a
33
+ run that a redelivered orchestrator tick would have recovered on its own.
@@ -0,0 +1,27 @@
1
+ ---
2
+ type: decision
3
+ title: A workflow step lock is held only to claim the step, never across its execution
4
+ description: Holding the advisory lock — and its pooled connection — across step work exhausted the connection pool and self-deadlocked
5
+ tags: workflow
6
+ ---
7
+
8
+ # A workflow step lock is held only to claim the step, never across its execution
9
+
10
+ `executeWorkflowStep` in `pikku-workflow-service.ts` takes `withStepLock` for an
11
+ atomic check-and-mark-running only: it reads the step, returns `null` if the
12
+ step already `succeeded` or is already `running` (another worker owns it),
13
+ starts a fresh attempt if it `failed`, and otherwise marks it `running`. The
14
+ lock is then released, and the actual work plus result persistence run outside
15
+ it.
16
+
17
+ The guard is what makes that safe — once a step is `running`, any concurrent
18
+ worker returns early. The alternative was tried and failed: holding the advisory
19
+ lock, and therefore its pooled connection, across `executeGraphStep` (network
20
+ I/O plus further pool queries) let concurrent steps exhaust the connection pool
21
+ and self-deadlock.
22
+
23
+ **What this rules out:** widening the `withStepLock` callback to cover RPC
24
+ invocation, child-workflow start, `setStepResult` or `resumeWorkflow` — the
25
+ "obviously safer" refactor that reintroduces the deadlock. If a stronger
26
+ guarantee is ever needed it has to come from the claim itself, not from a longer
27
+ lock hold.
@@ -0,0 +1,34 @@
1
+ ---
2
+ type: decision
3
+ title: A workflow step's recorded `rpcName` is provenance only — nothing dispatches off it
4
+ description: It exists so a reader can join a runtime step row back to the declaration that produced it, especially when the durable name was built in a loop
5
+ tags: workflow
6
+ ---
7
+
8
+ # A workflow step's recorded `rpcName` is provenance only — nothing dispatches off it
9
+
10
+ `insertStepState` and `inlineStep` in `pikku-workflow-service.ts` record the
11
+ name a step was dispatched by: an RPC for a `workflow.do` step, a step function
12
+ for a scenario step, `null` for a closure. Nothing in the engine dispatches off
13
+ that value — it is stored so a reader can join a step back to the function that
14
+ ran it.
15
+
16
+ It earns its keep when the durable step name was built at runtime. A scenario
17
+ step called in a loop reaches the run as, say, `sees @pikku/addon-todos` while
18
+ it was declared as ``sees ${packageName}``; the recorded step-function name is
19
+ then the only way to join that row back to its declaration. `inlineStep` also
20
+ records the `data` the step was called with for the same reason: a reporter
21
+ renders each step's prose from it, so two calls to one step stay
22
+ distinguishable by what they were asked to check.
23
+
24
+ Step lineage is recorded alongside it. `fromStepName` is the predecessor that
25
+ scheduled a step — the walked transition — captured by `rpcStep`/`inlineStep`
26
+ *before* `nextStepKey` advances the lineage, and surfaced to a step as
27
+ `fromInvocationId`. In a cyclic graph `a → b → a → c`, the second `a` therefore
28
+ carries `b`'s id, which is what lets the walked path be reconstructed from the
29
+ chain alone.
30
+
31
+ **What this rules out:** treating the recorded name as the dispatch target,
32
+ dropping it for closure steps "since it is always null", capturing
33
+ `lastStepName` after `nextStepKey` has run, or omitting `data` on inline steps —
34
+ each breaks either the join back to source or the reconstructed path.
@@ -0,0 +1,38 @@
1
+ ---
2
+ type: decision
3
+ title: A suspend or approval `reason` is the step's durable identity, not just a message
4
+ description: The reason is namespaced and used raw as the step key, so it must be derived deterministically across replays
5
+ tags: workflow
6
+ ---
7
+
8
+ # A suspend or approval `reason` is the step's durable identity, not just a message
9
+
10
+ `getSuspendStepName` and `getApprovalStepName` in `pikku-workflow-service.ts`
11
+ derive a step key from the `reason` string — `__workflow_suspend:<reason>` and
12
+ `__workflow_approval:<reason>`. Each distinct reason is therefore its own step
13
+ row, which is what lets one workflow hold several independent suspends
14
+ (wait-for-build, then wait-for-approval) and lets a dynamic reason inside a loop
15
+ work exactly like a dynamic `do()` step name. The two prefixes are separate
16
+ namespaces so a suspend, an approval, and a `do`/`sleep` step of the same name
17
+ cannot collide.
18
+
19
+ Because the reason IS the identity, it must be derived deterministically: the
20
+ same replay must produce the same reason at the same point, or the run mints a
21
+ new suspend instead of finding the one it is waiting on. This is the same
22
+ contract as `do()` and `sleep()` step names.
23
+
24
+ An approval additionally stores its record under a run-state key built by
25
+ `approvalStateKey`, which hex-encodes the step name. The Mongo backend restricts
26
+ state keys to `/^[a-zA-Z0-9_]+$/` while a reason is arbitrary human text, and
27
+ one key per gate means two gates resolving concurrently cannot clobber each
28
+ other through a read-modify-write.
29
+
30
+ One consequence to know about: `approveStep`'s optional `reason` argument
31
+ addresses the *first* reach of a gate only. If a gate is reached again on a
32
+ later loop iteration, `nextStepKey` gives that row a `#N` suffix, and there is
33
+ currently no way for a caller to name it.
34
+
35
+ **What this rules out:** deriving a reason from a timestamp, a random id or
36
+ anything else that varies between replays; sharing one namespace (or one
37
+ run-state key) between suspends and approvals; and storing the reason raw as a
38
+ run-state key, which breaks on any backend that constrains key characters.
@@ -0,0 +1,30 @@
1
+ ---
2
+ type: decision
3
+ title: A suspended workflow run keeps its in-process context; only terminal runs release it
4
+ description: `suspended` is absent from the terminal set on purpose, and a context is dropped only when nothing is holding it open
5
+ tags: workflow
6
+ ---
7
+
8
+ # A suspended workflow run keeps its in-process context; only terminal runs release it
9
+
10
+ `WORKFLOW_TERMINAL_STATES` in `pikku-workflow-service.ts` is
11
+ `completed | failed | cancelled`. `suspended` is deliberately absent: a
12
+ suspended run stops a poll loop but can still be resumed, so anything the
13
+ process holds for it — the run context, an extension's per-run state such as a
14
+ scenario's live actor clients — has to survive. `WORKFLOW_END_STATES`, which
15
+ `awaitRunEnd` uses to stop reading, does include `suspended`, because a poller
16
+ should not wait on a run that needs an external nudge. The two sets are not
17
+ interchangeable.
18
+
19
+ `releaseContext` drops a `RunContext` only when neither `inline` nor `replay`
20
+ still holds it open, so an inline run mid-replay is never torn out from under
21
+ itself. `updateRunStatus` releases on a terminal status because queued runs
22
+ never pass through the inline path that would otherwise do it — without that,
23
+ their context would be held for the life of the process. A long-lived server
24
+ orchestrates many runs, so anything kept per run has to be released when that
25
+ run stops executing here (`workflow-run-context.test.ts`).
26
+
27
+ **What this rules out:** adding `suspended` to `WORKFLOW_TERMINAL_STATES`,
28
+ collapsing the two state sets into one, or making `releaseContext`
29
+ unconditional — the first two discard state a resume still needs, the third
30
+ frees a context that an in-flight replay is still walking.
@@ -0,0 +1,26 @@
1
+ ---
2
+ type: decision
3
+ title: A dropped audit write is always logged
4
+ description: The no-op audit service falls back to the singleton logger when the wire carries none, so an unconfigured audit call is never silent
5
+ tags: services
6
+ ---
7
+
8
+ # A dropped audit write is always logged
9
+
10
+ The no-op `AuditService` in `packages/core/src/services/audit-service.ts` is what
11
+ a function gets when it calls `audit.write()` without `audit: true` set on it.
12
+ Its `write` discards the event — but before it does, it warns once, and it looks
13
+ for a logger in two places: the wire's own, then the singleton passed to the
14
+ constructor.
15
+
16
+ The fallback is the point. Wires frequently do not carry a logger, and with only
17
+ `this.wire.logger` the warning would itself be dropped whenever the wire is bare.
18
+ An audit call that silently does nothing is the worst available outcome: the
19
+ function believes it is producing an audit trail, the trail does not exist, and
20
+ nothing anywhere says so. The warning names the function and the fix, and fires
21
+ once per instance so it cannot flood a hot path.
22
+
23
+ **What this rules out:** narrowing the logger lookup to a single source,
24
+ downgrading the warning to `debug`, or removing it as noise from a service whose
25
+ whole job is to do nothing. If this class stops warning, an unconfigured audit
26
+ call becomes undetectable.
@@ -0,0 +1,22 @@
1
+ ---
2
+ type: decision
3
+ title: An actor's missing approval decision defaults to denied
4
+ description: Every pending tool call gets an explicit decision; an id the persona LLM omitted is denied, so a dropped field can never read as consent
5
+ tags: actor-flow
6
+ ---
7
+
8
+ # An actor's missing approval decision defaults to denied
9
+
10
+ `decideApprovals` in
11
+ `packages/core/src/wirings/actor-flow/run-conversation.ts` maps over the
12
+ target agent's `pendingApprovals`, not over the decisions the persona LLM
13
+ returned. Any `toolCallId` the model omitted, hallucinated, or renamed resolves
14
+ to `approved: false`.
15
+
16
+ The persona's decision comes from a structured LLM call, and structured output
17
+ is not guaranteed to be complete. Iterating the model's array instead would make
18
+ an omission indistinguishable from silence — and silence would let a scenario
19
+ approve a destructive tool call nobody decided on, then pass.
20
+
21
+ **What this rules out:** building the decision list from the LLM's `decisions`
22
+ array, and defaulting an unmatched call to `true` to keep a conversation moving.
@@ -0,0 +1,27 @@
1
+ ---
2
+ type: decision
3
+ title: Actor sign-in is proven by Set-Cookie, not a non-empty jar
4
+ description: HttpScenarioActor tracks its own signedIn flag and requires the sign-in response itself to set a cookie, because a populated jar proves nothing
5
+ tags: services
6
+ ---
7
+
8
+ # Actor sign-in is proven by Set-Cookie, not a non-empty jar
9
+
10
+ `HttpScenarioActor` (`packages/core/src/services/http-scenario-actors.ts`) keeps
11
+ a private `signedIn` boolean rather than inferring the session from its cookie
12
+ jar, and `login()` throws when the sign-in response carries no `Set-Cookie`
13
+ header even though the response was a 2xx.
14
+
15
+ A cookie jar cannot answer "did sign-in happen". A target app may set a cookie on
16
+ any request — a CSRF token, an anonymous session, a locale — so a non-empty jar
17
+ after a failed or skipped sign-in looks exactly like a successful one. What
18
+ actually proves a session was established is *this* response setting a cookie. A
19
+ 2xx alone is not enough either: an endpoint that returns 200 while quietly
20
+ declining to issue a session would leave the actor running every subsequent
21
+ request unauthenticated, and the scenario would report the resulting refusals as
22
+ genuine permission failures.
23
+
24
+ **What this rules out:** replacing `signedIn` with a `jar.isEmpty()` check,
25
+ dropping the `getSetCookie().length === 0` guard as redundant with `res.ok`, and
26
+ treating `signOut()` as jar-clearing only — it must reset the flag too, or the
27
+ next call proceeds believing it has a session.
@@ -0,0 +1,27 @@
1
+ ---
2
+ type: decision
3
+ title: Actor sign-in only works for actor-flagged users
4
+ description: The scenario actor secret mints sessions for user rows flagged actor and nothing else, so holding it never impersonates a real user
5
+ tags: services
6
+ ---
7
+
8
+ # Actor sign-in only works for actor-flagged users
9
+
10
+ `HttpScenarioActorsConfig.secret`
11
+ (`packages/core/src/services/http-scenario-actors.ts`) is a shared impersonation
12
+ secret: `HttpScenarioActor.login` POSTs `{ email, name, secret }` to
13
+ `/auth/sign-in/actor` and gets back a session. That looks like a master key, and
14
+ it deliberately is not one.
15
+
16
+ The Better Auth actor plugin on the other end upserts and signs in only user rows
17
+ flagged `actor: true`. Presenting the secret with a real customer's email does not
18
+ mint that customer's session — it is refused. The `actor` flag also flows into the
19
+ minted session, so audits and analytics can tell scenario traffic from human
20
+ traffic after the fact. The blast radius of a leaked actor secret is therefore the
21
+ synthetic actor population, not the user table.
22
+
23
+ **What this rules out:** widening the sign-in endpoint to accept any email "so
24
+ scenarios can test as a real user", and treating the actor secret as equivalent to
25
+ a session-signing key. It also rules out dropping the `actor` flag from the minted
26
+ session — the audit trail's ability to separate synthetic from real activity
27
+ depends on it.
@@ -0,0 +1,43 @@
1
+ ---
2
+ type: decision
3
+ title: Addon auth and tags only tighten, and resolve where the function runs
4
+ description: wireAddon auth and tags are applied in runPikkuFunc like scopes, but auth:false is ignored and tags resolve against the consuming app's tag groups rather than the addon package's
5
+ tags: addon, auth, tags, authorization
6
+ ---
7
+
8
+ # Addon auth and tags only tighten, and resolve where the function runs
9
+
10
+ `wireAddon({ auth, tags })` was read only by `resolveAddonFunction` in
11
+ `rpc-runner.ts`, which covers the `namespace:function` RPC form alone. Every
12
+ direct wiring — the inspector writes the addon's package name onto http,
13
+ channel, schedule, queue, cli, trigger, gateway and mcp wirings — reached
14
+ `runPikkuFunc` with a `packageName` and neither value. That is the same hole
15
+ [addon scopes](./addon-scopes-are-resolved-where-the-function-runs.md) had, and
16
+ it is closed the same way: `runPikkuFunc` resolves both from the addon config.
17
+
18
+ `auth` merges as an OR and `auth: false` is ignored. The RPC path treats it as a
19
+ default (`addonConfig?.auth ?? options.requiresAuth`) because there the addon
20
+ config is the only statement of intent. On a direct wiring the route already
21
+ carries its own `auth`, so honouring `false` would let an addon *weaken* a gate
22
+ the app wrote — the inverse of what a wiring-level declaration should be able to
23
+ do. An addon may require a session the wiring did not; it may never waive one
24
+ the wiring did.
25
+
26
+ Tags resolve against the **root** tag groups, not the addon package's. A tag on
27
+ `wireAddon` is written by the consuming app, and `addTagMiddleware('admin', …)`
28
+ in that app registers under the root package. `combineMiddleware` looks tag
29
+ metadata up under the `packageName` it is given, which for an addon function is
30
+ the addon's own namespace — where the app's middleware does not exist. Resolving
31
+ addon tags to concrete middleware before the call and passing them as
32
+ `wireMiddleware` is what keeps `wireAddon({ tags: ['admin'] })` from being
33
+ silently inert, which is the failure mode the whole gate exists to avoid.
34
+
35
+ A function's own tags are unaffected: the inspector already emits them as
36
+ `{ type: 'tag' }` entries on the function and wiring meta, resolved under the
37
+ package that declared them. The `tags` argument `runPikkuFunc` accepts is
38
+ separate and still unused on every path.
39
+
40
+ **What this rules out:** honouring `auth: false` from an addon on a direct
41
+ wiring; resolving addon tags under the addon's `packageName`; and folding addon
42
+ tags into `funcInheritedMiddleware`, which would resolve them in the wrong
43
+ namespace and double-apply the function's own tags.
@@ -0,0 +1,52 @@
1
+ ---
2
+ type: decision
3
+ title: Addon auth and tag gates apply wherever the function runs, including inside the addon
4
+ description: wireAddon's auth and tags moved from the namespaced RPC boundary into runPikkuFunc, so they also apply to direct wirings and to bare intra-addon calls
5
+ tags: rpc, addon, auth
6
+ ---
7
+
8
+ # Addon auth and tag gates apply wherever the function runs, including inside the addon
9
+
10
+ `ContextAwareRPCService.invokeAddonFunction` used to be the only place that
11
+ applied an addon's `addonConfig.auth` and `addonConfig.tags`, making them a
12
+ perimeter control on `rpc('namespace:fn')`. That perimeter had a hole in it: the
13
+ inspector writes the addon's package name onto http, channel, schedule, queue,
14
+ cli, trigger, gateway and mcp wirings, and every one of those runners calls
15
+ `runPikkuFunc` directly without resolving a namespace. A consumer who wrote
16
+ `wireAddon({ auth: true })` and then wired an addon function to a route got no
17
+ gate at all.
18
+
19
+ Both values now resolve in `runPikkuFunc`, the one point every path shares —
20
+ the same move, for the same reason, as
21
+ [addon scopes](./addon-scopes-are-resolved-where-the-function-runs.md). See
22
+ [addon auth and tags only tighten](./addon-auth-and-tags-only-tighten.md) for
23
+ the merge rules.
24
+
25
+ This replaces a consequence an earlier decision accepted: a bare `rpc('fn')`
26
+ made from inside an addon now re-applies the gate, because it reaches
27
+ `runPikkuFunc` with the addon's `packageName` like any other call. The earlier
28
+ reasoning — that the perimeter had already been passed, so re-checking would
29
+ gate internal calls on a consumer-facing setting — held only while the perimeter
30
+ was real. Once a direct wiring could enter the addon without passing any gate,
31
+ "already inside" stopped being something the runtime could infer, and the choice
32
+ became re-checking or trusting an entry that may never have happened.
33
+
34
+ In practice an intra-addon call inherits the entry point's session, so the auth
35
+ check passes wherever the entry was itself authenticated. What it does break is
36
+ an addon that wires `auth: true` and also runs its own sessionless internal
37
+ work — a scheduled task or queue worker inside the addon calling a sibling. Such
38
+ an addon should carry authorization on the function via
39
+ `pikkuFunc({ permissions })`, which has always been enforced on every path,
40
+ rather than on the consumer-facing `wireAddon` setting.
41
+
42
+ Re-checking was chosen over provenance because the marker that would make
43
+ "already inside" knowable — set by the runtime, unsettable by any caller outside
44
+ the process, threaded through all eight runners — is a design problem of its
45
+ own, and shipping it inside a security fix would have meant landing an untested
46
+ trust signal alongside the gate that depends on it. Adding that marker is
47
+ tracked separately; until it exists, re-checking is the only option that does
48
+ not trust an entry which may never have happened.
49
+
50
+ **What this rules out:** treating `addonConfig.auth` as a perimeter-only
51
+ control; and inferring "already inside the addon" from the wire, which a direct
52
+ wiring does not set.
@@ -0,0 +1,46 @@
1
+ ---
2
+ type: decision
3
+ title: Addon scopes are resolved where the function runs
4
+ description: wireAddon scopes are merged inside runPikkuFunc rather than at namespace resolution, because most wirings reach an addon function without ever resolving a namespace
5
+ tags: addon, scopes, authorization
6
+ ---
7
+
8
+ # Addon scopes are resolved where the function runs
9
+
10
+ `wireAddon({ scopes })` names scopes every function in the addon's package
11
+ requires. `runPikkuFunc` calls `resolveAddonScopes(packageName,
12
+ addonInstance?.namespace)` and unions the result with the function's own
13
+ `scopes` before `verifyScopes`.
14
+
15
+ The obvious home for this is `resolveAddonFunction` in `rpc-runner.ts`, next to
16
+ where `auth` and `tags` are already merged from the addon config — but that
17
+ covers only the `namespace:function` RPC form. An addon function is reachable
18
+ without any namespace resolution: the inspector's `resolveAddonName` writes the
19
+ addon's package name onto the wiring meta whenever a wiring's `func` is an
20
+ identifier imported from a wired addon, and every runner (`http-runner`,
21
+ `mcp-runner`, channel, scheduler, queue, cli, trigger, gateway) then passes that
22
+ `packageName` straight to `runPikkuFunc`. `refHTTP` / `refChannel` / `refCLI`
23
+ contracts do the same through `registerHTTPRouteMeta`. A gate at namespace
24
+ resolution would leave every one of those doors open while reading as complete,
25
+ which is worse than no gate. `runPikkuFunc` is the one point all of them share.
26
+
27
+ Merging is a union, not an override, because `firstUnsatisfied` in `scopes.ts`
28
+ requires every listed scope. An addon scope is therefore an additional
29
+ requirement and can only narrow access — an addon can never weaken a function
30
+ that declares stricter scopes of its own. `ref('namespace:fn')` routes are
31
+ gated for the same reason from the other direction: the generated wrapper is a
32
+ local function that calls `rpc.invoke`, so the addon's scopes attach on the
33
+ inner call rather than the route.
34
+
35
+ When the caller carries an `addonInstance`, its namespace selects that
36
+ instance's scopes exactly. The direct-wiring paths know only a package name, so
37
+ `resolveAddonScopes` unions the scopes of every namespace the package is wired
38
+ under. One package wired twice with different scopes is rare; taking the
39
+ stricter reading keeps the unnamed path from becoming the weak one.
40
+
41
+ **What this rules out:** gating addon functions in `resolveAddonFunction`,
42
+ `resolveNamespace`, or any per-wiring runner; treating addon scopes as a
43
+ default that a function's own `scopes` replaces; resolving a package's scopes
44
+ by first matching namespace, the way `findAddonNamespaceForPackage` resolves
45
+ services; and reusing this for `wireRemoteAddon`, whose functions execute on the
46
+ host and are gated there.
@@ -0,0 +1,27 @@
1
+ ---
2
+ type: decision
3
+ title: Only a Symbol-branded framework result can request tool approval
4
+ description: Approval markers are trusted from the APPROVAL_REQUIRED Symbol on a forwardsApproval tool, never from a JSON key an LLM could emit
5
+ tags: ai-agent
6
+ ---
7
+
8
+ # Only a Symbol-branded framework result can request tool approval
9
+
10
+ `checkForApprovals` in
11
+ `packages/core/src/wirings/ai-agent/ai-agent-stream.ts` honours a forwarded
12
+ approval only when both hold: the tool declares `forwardsApproval` (set solely by
13
+ framework code on the sub-agent delegating tools built in
14
+ `ai-agent-prepare.ts`), and its result carries the `APPROVAL_REQUIRED` unique
15
+ Symbol. The companion `__approvalRequired` string key exists for transport, but
16
+ is never what the decision reads.
17
+
18
+ A tool result is attacker-influenceable — a retrieved document, a third-party API
19
+ response, or a sub-agent's LLM-shaped `result.object`. All of those are plain
20
+ JSON, and plain JSON cannot carry a Symbol. Trusting the string key would let any
21
+ ordinary tool conjure a suspension and an approval prompt showing a tool name and
22
+ arguments of its choosing.
23
+
24
+ **What this rules out:** checking `'__approvalRequired' in result` as the
25
+ condition; replacing the Symbol with a string or numeric sentinel so results
26
+ survive JSON serialization; and setting `forwardsApproval` from user-supplied
27
+ tool configuration rather than from framework code.
@@ -0,0 +1,37 @@
1
+ ---
2
+ type: decision
3
+ title: Credential requests are trusted only when Symbol-branded
4
+ description: The string key is a wire field; the Symbol is the capability, and only core can mint it
5
+ tags: ai-agent
6
+ ---
7
+
8
+ # Credential requests are trusted only when Symbol-branded
9
+
10
+ A tool result asking the run to suspend and prompt for a credential is honoured
11
+ only when it carries the `CREDENTIAL_REQUIRED` Symbol minted in
12
+ `ai-agent-prepare.ts`. `checkForCredentialRequests` in `ai-agent-stream.ts`
13
+ tests for that Symbol, never for the `__credentialRequired` string key that
14
+ travels beside it on the wire.
15
+
16
+ The distinction is the whole security property. Tool results are frequently
17
+ attacker-influenceable — a retrieved document, an echo from a third-party API,
18
+ LLM-authored content round-tripping through a tool — and any of those can carry
19
+ a string key. None can carry a Symbol, because a Symbol has no literal form and
20
+ does not survive JSON. Without the brand, an influenced tool result could
21
+ suspend the run and push a `credential-request` event with an attacker-chosen
22
+ `connectUrl`, which the client renders as a "Connect" button: a phishing
23
+ primitive inside the product's own UI. This mirrors the `APPROVAL_REQUIRED`
24
+ brand, which exists for the identical reason one function over.
25
+
26
+ The brand survives because the object is passed by reference the whole way —
27
+ core's `buildToolDefs` wrapper returns it, the Vercel adapter's `aiTool` hands
28
+ it back verbatim, and the AI SDK puts the raw value on the stream part rather
29
+ than the JSON form it builds separately for the model.
30
+
31
+ **What this rules out:** widening the check to `'__credentialRequired' in
32
+ result` for convenience, or introducing any path where a credential request is
33
+ reconstructed from parsed JSON rather than passed by reference — either one
34
+ silently converts the gate into a formality. Note the inverse holds for the
35
+ `credentialFilteredChannel` suppression later in the same file: that one
36
+ deliberately matches the *string* key, because it hides tool results from the
37
+ client and a broader match leaks less, not more.