@pikku/core 0.12.139 → 0.12.142

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 (253) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/dist/errors/errors.d.ts +1 -1
  3. package/dist/errors/errors.js +1 -1
  4. package/dist/function/function-meta.types.d.ts +6 -6
  5. package/dist/function/functions.types.d.ts +2 -2
  6. package/dist/lifecycle.d.ts +6 -0
  7. package/dist/lifecycle.js +58 -0
  8. package/dist/services/audit-service.d.ts +4 -4
  9. package/dist/services/feature-flag-service.d.ts +3 -3
  10. package/dist/services/{http-personas.d.ts → http-virtual-users.d.ts} +25 -47
  11. package/dist/services/{http-personas.js → http-virtual-users.js} +29 -53
  12. package/dist/services/index.d.ts +2 -2
  13. package/dist/services/index.js +1 -1
  14. package/dist/services/meta-service.d.ts +6 -6
  15. package/dist/services/meta-service.js +8 -8
  16. package/dist/{wirings/workflow → services}/scenario-cookie-jar.d.ts +2 -0
  17. package/dist/{wirings/workflow → services}/scenario-cookie-jar.js +18 -14
  18. package/dist/services/scoped-secret-service.d.ts +1 -0
  19. package/dist/services/scoped-secret-service.js +3 -0
  20. package/dist/services/secret-service.d.ts +6 -0
  21. package/dist/services/system-role-guard.d.ts +1 -1
  22. package/dist/services/typed-secret-service.d.ts +1 -0
  23. package/dist/services/typed-secret-service.js +7 -0
  24. package/dist/services/virtual-user-sign-in.d.ts +52 -0
  25. package/dist/services/virtual-user-sign-in.js +80 -0
  26. package/dist/services/virtual-user-statement.d.ts +31 -0
  27. package/dist/services/virtual-user-statement.js +24 -0
  28. package/dist/services/{personas-service.d.ts → virtual-users-service.d.ts} +25 -23
  29. package/dist/services/{personas-service.js → virtual-users-service.js} +3 -3
  30. package/dist/testing/service-tests/secret-service-tests.js +9 -0
  31. package/dist/types/core.types.d.ts +11 -11
  32. package/dist/utils.d.ts +2 -5
  33. package/dist/utils.js +1 -38
  34. package/dist/wirings/cli/cli-runner.js +24 -9
  35. package/dist/wirings/http/http-runner.js +4 -0
  36. package/dist/wirings/http/http.types.d.ts +1 -0
  37. package/dist/wirings/http/pikku-fetch-http-response.d.ts +1 -0
  38. package/dist/wirings/http/pikku-fetch-http-response.js +12 -0
  39. package/dist/wirings/http/web-request.js +7 -0
  40. package/dist/wirings/role/define-system-role.d.ts +1 -1
  41. package/dist/wirings/role/define-system-role.js +1 -1
  42. package/dist/wirings/{actor-flow/actor-flow.types.d.ts → virtual-user/conversation/conversation.types.d.ts} +5 -5
  43. package/dist/wirings/virtual-user/conversation/index.d.ts +2 -0
  44. package/dist/wirings/virtual-user/conversation/run-conversation.d.ts +36 -0
  45. package/dist/wirings/{actor-flow → virtual-user/conversation}/run-conversation.js +30 -30
  46. package/dist/wirings/virtual-user/define-virtual-users.d.ts +32 -0
  47. package/dist/wirings/{persona/define-personas.js → virtual-user/define-virtual-users.js} +9 -9
  48. package/dist/wirings/virtual-user/index.d.ts +30 -7
  49. package/dist/wirings/virtual-user/index.js +23 -4
  50. package/dist/wirings/virtual-user/prepare-virtual-user-run.d.ts +8 -8
  51. package/dist/wirings/virtual-user/prepare-virtual-user-run.js +9 -9
  52. package/dist/wirings/virtual-user/run-virtual-user.d.ts +6 -6
  53. package/dist/wirings/virtual-user/run-virtual-user.js +10 -10
  54. package/dist/wirings/{persona/validate-personas.d.ts → virtual-user/validate-virtual-users.d.ts} +11 -11
  55. package/dist/wirings/{persona/validate-personas.js → virtual-user/validate-virtual-users.js} +24 -24
  56. package/dist/wirings/virtual-user/virtual-user-agents.d.ts +7 -7
  57. package/dist/wirings/virtual-user/virtual-user-agents.js +2 -2
  58. package/dist/wirings/{persona/persona-app-scopes.d.ts → virtual-user/virtual-user-app-scopes.d.ts} +10 -10
  59. package/dist/wirings/{persona/persona-app-scopes.js → virtual-user/virtual-user-app-scopes.js} +12 -12
  60. package/dist/wirings/virtual-user/virtual-user-catalogue.d.ts +3 -3
  61. package/dist/wirings/virtual-user/virtual-user-catalogue.js +2 -2
  62. package/dist/wirings/{persona/persona.types.d.ts → virtual-user/virtual-user-declaration.types.d.ts} +24 -24
  63. package/dist/wirings/virtual-user/virtual-user-derive.js +13 -7
  64. package/dist/wirings/virtual-user/virtual-user-dispositions.d.ts +1 -1
  65. package/dist/wirings/{persona/persona-email.d.ts → virtual-user/virtual-user-email.d.ts} +11 -11
  66. package/dist/wirings/{persona/persona-email.js → virtual-user/virtual-user-email.js} +19 -19
  67. package/dist/wirings/{persona/persona-environments.d.ts → virtual-user/virtual-user-environments.d.ts} +10 -10
  68. package/dist/wirings/{persona/persona-environments.js → virtual-user/virtual-user-environments.js} +21 -21
  69. package/dist/wirings/virtual-user/virtual-user-intents.d.ts +3 -3
  70. package/dist/wirings/virtual-user/virtual-user-intents.js +3 -3
  71. package/dist/wirings/{persona/persona-mailbox.d.ts → virtual-user/virtual-user-mailbox.d.ts} +4 -4
  72. package/dist/wirings/virtual-user/virtual-user-run-store.d.ts +4 -4
  73. package/dist/wirings/virtual-user/virtual-user-scaffold.d.ts +42 -61
  74. package/dist/wirings/virtual-user/virtual-user-scaffold.js +69 -117
  75. package/dist/wirings/virtual-user/virtual-user-schedule-store.d.ts +15 -15
  76. package/dist/wirings/virtual-user/virtual-user-schedule.d.ts +6 -6
  77. package/dist/wirings/virtual-user/virtual-user-schedule.js +11 -11
  78. package/dist/wirings/virtual-user/virtual-user-target.d.ts +6 -6
  79. package/dist/wirings/virtual-user/virtual-user-target.js +5 -5
  80. package/dist/wirings/virtual-user/virtual-user.types.d.ts +11 -11
  81. package/dist/wirings/virtual-user/virtual-user.types.js +1 -1
  82. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +9 -9
  83. package/dist/wirings/workflow/pikku-scenario-service.d.ts +28 -28
  84. package/dist/wirings/workflow/pikku-scenario-service.js +77 -77
  85. package/dist/wirings/workflow/pikku-workflow-service.d.ts +2 -2
  86. package/dist/wirings/workflow/pikku-workflow-service.js +4 -4
  87. package/dist/wirings/workflow/scenario-prose.d.ts +8 -8
  88. package/dist/wirings/workflow/scenario-prose.js +12 -8
  89. package/dist/wirings/workflow/scenario-run.types.d.ts +13 -13
  90. package/dist/wirings/workflow/scenario-step.types.d.ts +23 -23
  91. package/dist/wirings/workflow/workflow.types.d.ts +2 -2
  92. package/knowledge/decisions/index.md +0 -2
  93. package/knowledge/decisions/internals/a-credential-name-declared-twice-must-agree-on-schema-and-type.md +29 -0
  94. package/knowledge/decisions/internals/a-grant-can-name-a-scope-declared-without-its-addon.md +29 -0
  95. package/knowledge/decisions/internals/a-scheduled-task-writes-its-caller-session-before-it-runs.md +22 -0
  96. package/knowledge/decisions/internals/a-secret-set-in-memory-shadows-the-variable-of-the-same-name.md +28 -0
  97. package/knowledge/decisions/internals/a-virtual-user-acts-through-invokeraw-so-a-refusal-is-data.md +32 -0
  98. package/knowledge/decisions/internals/a-virtual-user-cadence-is-a-row-not-a-timer.md +12 -12
  99. package/knowledge/decisions/internals/a-virtual-user-converse-signs-in-before-its-first-turn.md +24 -0
  100. package/knowledge/decisions/internals/a-virtual-user-email-is-computed-with-the-run-id-as-a-sub-address.md +34 -0
  101. package/knowledge/decisions/internals/a-virtual-user-run-is-not-a-workflow-but-it-needs-a-trigger.md +2 -2
  102. package/knowledge/decisions/internals/an-agent-is-offered-under-its-registry-key-and-only-within-the-virtual-users-scopes.md +27 -0
  103. package/knowledge/decisions/internals/an-oauth2-credential-implies-an-optional-app-secret.md +26 -0
  104. package/knowledge/decisions/internals/analytics-identity-resolvers-run-in-declared-order.md +22 -0
  105. package/knowledge/decisions/internals/feature-flag-declarations-refuse-an-empty-anyof-and-conflicting-scopes.md +22 -0
  106. package/knowledge/decisions/internals/feature-flags-fail-open-and-never-enforce-access.md +28 -0
  107. package/knowledge/decisions/internals/flag-sync-rewrites-only-the-declared-text.md +24 -0
  108. package/knowledge/decisions/internals/in-a-scenario-a-4xx-is-data-not-an-exception.md +3 -3
  109. package/knowledge/decisions/internals/index.md +46 -31
  110. package/knowledge/decisions/internals/one-project-shape-check-two-validators.md +10 -10
  111. package/knowledge/decisions/internals/role-names-cannot-contain-the-scope-separator.md +30 -0
  112. package/knowledge/decisions/internals/scenario-agent-calls-sign-in-on-401-only.md +23 -19
  113. package/knowledge/decisions/internals/scenario-steps-return-drained-response-records.md +2 -2
  114. package/knowledge/decisions/internals/scenarios-live-in-files-named-for-them.md +12 -12
  115. package/knowledge/decisions/internals/the-core-scope-validator-refuses-separator-wildcard-and-empty-segments.md +22 -0
  116. package/knowledge/decisions/internals/the-pikku-user-id-resolves-in-a-fixed-order.md +24 -0
  117. package/knowledge/decisions/internals/{the-actor-prompt-says-json-because-of-json-object-mode.md → the-virtual-user-prompt-says-json-because-of-json-object-mode.md} +4 -4
  118. package/knowledge/decisions/internals/{the-persona-runtime-is-exported-from-the-persona-entry-point.md → the-virtual-user-runtime-is-exported-from-the-virtual-user-entry-point.md} +8 -8
  119. package/knowledge/decisions/internals/validate-checks-virtual-users-through-a-shared-module.md +43 -0
  120. package/knowledge/decisions/internals/{actor-flow-drives-the-target-through-a-transport-seam.md → virtual-user-conversation-drives-the-target-through-a-transport-seam.md} +6 -6
  121. package/knowledge/decisions/internals/virtual-user-conversation-verdicts-are-llm-self-evaluations.md +25 -0
  122. package/knowledge/decisions/internals/virtual-user-conversations-seed-a-hidden-kickoff-message.md +23 -0
  123. package/knowledge/decisions/internals/virtual-users-are-declared-in-one-definevirtualusers-call-per-codebase.md +30 -0
  124. package/knowledge/decisions/internals/workflow-core-never-imports-a-browser-driver.md +5 -5
  125. package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md +2 -2
  126. package/knowledge/decisions/internals/workflow-scenario-assertions-never-retry-and-record-one-step.md +4 -4
  127. package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md +1 -1
  128. package/knowledge/decisions/internals/workflow-scenario-prose-is-rendered-from-typed-calls-not-parsed-from-english.md +2 -2
  129. package/knowledge/decisions/internals/workflow-scenario-step-targets-are-string-literals-for-the-inspector.md +1 -1
  130. package/knowledge/decisions/internals/workflow-suspended-runs-keep-their-in-process-context.md +1 -1
  131. package/knowledge/decisions/security/a-bearer-token-checked-against-a-secret-reads-it-per-request.md +26 -0
  132. package/knowledge/decisions/security/a-call-without-a-session-raises-missing-session-not-forbidden.md +20 -0
  133. package/knowledge/decisions/security/a-caller-cookie-wins-over-the-jar-for-the-same-name.md +23 -0
  134. package/knowledge/decisions/security/a-channel-lifecycle-acts-as-the-socket-upgrade-session.md +16 -0
  135. package/knowledge/decisions/security/a-channel-requires-a-session-unless-it-says-auth-false.md +26 -0
  136. package/knowledge/decisions/security/a-credential-read-path-follows-its-declared-type-not-absence.md +32 -0
  137. package/knowledge/decisions/security/a-credential-type-is-a-literal-the-inspector-checks-at-declaration.md +27 -0
  138. package/knowledge/decisions/security/a-first-party-cookie-is-written-only-after-its-purposes-consent.md +33 -0
  139. package/knowledge/decisions/security/a-readonly-session-reaches-only-readonly-functions.md +25 -0
  140. package/knowledge/decisions/security/a-scaffold-flag-says-a-surface-exists-not-who-may-call-it.md +10 -5
  141. package/knowledge/decisions/security/a-scheduled-virtual-user-run-needs-no-admin-at-run-time.md +27 -0
  142. package/knowledge/decisions/security/a-scoped-credential-view-is-limited-to-declared-names.md +26 -0
  143. package/knowledge/decisions/security/a-scoped-secret-view-reads-only-declared-keys-and-never-writes.md +25 -0
  144. package/knowledge/decisions/security/a-secret-is-sent-only-to-the-hosts-it-declares.md +29 -0
  145. package/knowledge/decisions/security/a-step-can-name-an-identity-no-virtual-user-holds-through-per-call-headers.md +25 -0
  146. package/knowledge/decisions/security/a-stopped-run-by-id-skips-the-ownership-check.md +24 -0
  147. package/knowledge/decisions/security/a-vault-secret-redacts-on-serialization-and-throws-on-coercion.md +29 -0
  148. package/knowledge/decisions/security/a-virtual-user-catalogue-entry-is-filtered-by-scope-and-approval-is-denied-by-default.md +30 -0
  149. package/knowledge/decisions/security/a-virtual-user-environment-fails-closed.md +38 -0
  150. package/knowledge/decisions/security/a-virtual-user-never-runs-against-production.md +23 -0
  151. package/knowledge/decisions/security/a-virtual-user-reads-its-roles-from-the-apps-own-rpc-before-better-auth.md +27 -0
  152. package/knowledge/decisions/security/a-virtual-user-run-treats-an-unresolved-environment-as-production.md +41 -0
  153. package/knowledge/decisions/security/a-virtual-user-scopes-are-expanded-from-its-roles-once-at-run-preparation.md +25 -0
  154. package/knowledge/decisions/security/a-virtual-user-whose-roles-drift-from-the-declaration-refuses-to-run.md +32 -0
  155. package/knowledge/decisions/security/addon-screen-scopes-hide-and-do-not-enforce.md +20 -0
  156. package/knowledge/decisions/security/an-addon-header-can-only-narrow-the-session.md +26 -0
  157. package/knowledge/decisions/security/an-addon-instance-reads-only-the-secrets-and-credentials-it-is-named.md +33 -0
  158. package/knowledge/decisions/security/an-addon-may-reach-only-itself-and-the-addons-it-uses.md +16 -0
  159. package/knowledge/decisions/security/an-api-key-is-jwt-decoded-into-the-session.md +26 -0
  160. package/knowledge/decisions/security/an-external-virtual-user-caller-presents-one-signed-statement.md +38 -0
  161. package/knowledge/decisions/security/an-inbound-webhook-source-dispatches-only-verified-requests.md +31 -0
  162. package/knowledge/decisions/security/an-mcp-call-with-no-http-request-stays-anonymous.md +18 -0
  163. package/knowledge/decisions/security/an-omitted-user-id-addresses-the-platform-credential.md +32 -0
  164. package/knowledge/decisions/security/analytics-identity-is-stamped-from-the-session-not-the-event.md +24 -0
  165. package/knowledge/decisions/security/app-access-is-a-scope-tree-synthesised-from-virtual-users.md +26 -0
  166. package/knowledge/decisions/security/approval-policy-decides-who-answers-a-tool-call.md +27 -0
  167. package/knowledge/decisions/security/auth-false-on-a-session-function-warns-and-still-requires-one.md +25 -0
  168. package/knowledge/decisions/security/bearer-token-hashes-are-unpeppered-sha256.md +18 -0
  169. package/knowledge/decisions/security/consent-is-read-from-a-cookie-and-a-recognised-denial-counts-as-refusal.md +29 -0
  170. package/knowledge/decisions/security/cors-defaults-to-any-origin-and-refuses-the-wildcard-with-credentials.md +22 -0
  171. package/knowledge/decisions/security/credential-backends-share-one-conformance-suite-for-per-user-isolation.md +29 -0
  172. package/knowledge/decisions/security/each-stage-has-one-virtual-user-key-pair.md +27 -0
  173. package/knowledge/decisions/security/hmac-verification-fails-closed-on-empty-inputs.md +25 -0
  174. package/knowledge/decisions/security/index.md +88 -24
  175. package/knowledge/decisions/security/local-content-refuses-private-buckets-under-the-public-segment.md +21 -0
  176. package/knowledge/decisions/security/mail-is-allowlisted-before-a-virtual-user-run-sees-it.md +38 -0
  177. package/knowledge/decisions/security/mcp-resources-tools-and-prompts-take-sessionless-functions.md +18 -0
  178. package/knowledge/decisions/security/origin-locked-routes-match-the-origin-exactly.md +22 -0
  179. package/knowledge/decisions/security/oss-auth-works-without-pikku-studio-cloud.md +26 -0
  180. package/knowledge/decisions/security/outbound-webhooks-use-an-allowlist-when-configured.md +24 -0
  181. package/knowledge/decisions/security/pikku-carries-virtual-user-scopes-as-data-and-the-app-grants-them.md +35 -0
  182. package/knowledge/decisions/security/scoped-content-access-is-a-root-folder-with-longest-prefix-grants.md +31 -0
  183. package/knowledge/decisions/security/services-without-secrets-get-a-throwing-secrets-accessor.md +22 -0
  184. package/knowledge/decisions/security/shared-guards-refuse-to-mutate-or-shadow-a-system-role.md +34 -0
  185. package/knowledge/decisions/security/signed-uploads-are-verified-by-the-same-check-as-signed-reads.md +26 -0
  186. package/knowledge/decisions/security/system-role-scopes-must-be-declared-with-define-scope.md +24 -0
  187. package/knowledge/decisions/security/system-roles-are-additive-and-immutable.md +16 -0
  188. package/knowledge/decisions/security/the-channel-rpc-does-not-send-the-callers-session.md +21 -0
  189. package/knowledge/decisions/security/the-remote-jobs-inbox-fails-closed-without-a-secret.md +24 -0
  190. package/knowledge/decisions/security/the-remote-rpc-gate-fails-closed-and-binds-the-token-to-its-function.md +34 -0
  191. package/knowledge/decisions/security/the-workflow-status-stream-rechecks-ownership-on-every-poll.md +16 -0
  192. package/knowledge/decisions/security/two-credentials-on-one-key-must-share-a-read-mode.md +29 -0
  193. package/knowledge/decisions/security/verified-bearer-claims-are-pass-through-data-that-core-never-fills.md +23 -0
  194. package/knowledge/decisions/security/virtual-user-catalogue-excludes-the-machinery-that-runs-virtual-users.md +25 -0
  195. package/knowledge/decisions/security/{actor-flow-missing-approval-decisions-default-to-denied.md → virtual-user-conversation-missing-approval-decisions-default-to-denied.md} +7 -7
  196. package/knowledge/decisions/security/virtual-user-run-records-are-gated-behind-a-read-scope.md +18 -0
  197. package/knowledge/decisions/security/virtual-user-sign-in-does-not-exist-in-production.md +25 -0
  198. package/knowledge/decisions/security/virtual-user-sign-in-has-one-door.md +42 -0
  199. package/knowledge/decisions/security/{actor-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md → virtual-user-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md} +10 -8
  200. package/knowledge/decisions/security/virtual-user-sign-in-only-works-for-virtual-user-flagged-users.md +29 -0
  201. package/knowledge/decisions/security/workflow-helper-functions-are-sessionless-by-declaration.md +18 -0
  202. package/knowledge/decisions/security/{workflow-scenario-sessions-are-isolated-per-actor-and-per-scenario.md → workflow-scenario-sessions-are-isolated-per-virtual-user-and-per-scenario.md} +6 -6
  203. package/knowledge/decisions/security/workflow-scenario-steps-are-never-network-invocable.md +5 -5
  204. package/knowledge/decisions/security/{workflow-actor-steps-always-use-the-real-transport.md → workflow-virtual-user-steps-always-use-the-real-transport.md} +11 -11
  205. package/knowledge/decisions/security/writing-a-virtual-user-schedule-is-gated-by-its-own-scope.md +18 -0
  206. package/knowledge/index.md +0 -2
  207. package/knowledge/questions/a-bearer-jwt-with-no-identity-becomes-a-session.md +24 -0
  208. package/knowledge/questions/dev-quick-login-as-impersonation.md +25 -0
  209. package/knowledge/questions/does-a-delayed-rpc-run-as-the-session-it-was-scheduled-with.md +26 -0
  210. package/knowledge/questions/does-a-user-id-with-a-colon-read-another-users-credentials.md +27 -0
  211. package/knowledge/questions/does-a-wirecli-command-need-a-session-by-default.md +26 -0
  212. package/knowledge/questions/does-an-adversarial-in-scope-success-count-as-a-finding.md +26 -0
  213. package/knowledge/questions/does-approve-step-need-the-run-owners-session-or-the-gates-approvers.md +34 -0
  214. package/knowledge/questions/does-cors-origin-true-reflect-any-origin-with-credentials.md +20 -0
  215. package/knowledge/questions/does-skip-user-session-do-anything-on-a-channel.md +24 -0
  216. package/knowledge/questions/does-the-store-session-match-the-other-two.md +19 -0
  217. package/knowledge/questions/index.md +25 -2
  218. package/knowledge/questions/is-the-agent-score-worker-reachable-without-a-session.md +21 -0
  219. package/knowledge/questions/live-scheduled-tests-may-write.md +19 -0
  220. package/knowledge/questions/provision-virtual-users-has-no-caller-in-this-repo.md +23 -0
  221. package/knowledge/questions/remote-secret-refuses-requests-without-a-remote-token-on-every-path.md +32 -0
  222. package/knowledge/questions/should-a-middleware-set-session-persist-to-the-store.md +25 -0
  223. package/knowledge/questions/should-a-scoped-secret-view-throw-from-has-secret-for-a-disallowed-key.md +23 -0
  224. package/knowledge/questions/should-a-wrong-bearer-token-be-anonymous-or-refused.md +35 -0
  225. package/knowledge/questions/should-an-empty-webhook-signing-secret-send-unsigned.md +23 -0
  226. package/knowledge/questions/should-http-virtual-user-sessions-reset-between-scenarios-in-one-run.md +27 -0
  227. package/knowledge/questions/should-the-cookie-jar-scope-cookies-to-the-api-origin.md +26 -0
  228. package/knowledge/questions/should-voice-input-fetch-audio-urls-without-a-host-allowlist.md +20 -0
  229. package/knowledge/questions/staging-impersonation-rules.md +27 -0
  230. package/knowledge/questions/virtual-user-keys-on-cloud-stages-are-pikku-studios-to-build.md +34 -0
  231. package/knowledge/questions/virtual-user-statement-replay-is-per-process.md +20 -0
  232. package/knowledge/questions/what-an-impersonated-session-carries.md +22 -0
  233. package/package.json +3 -3
  234. package/src/public-surface.json +43 -47
  235. package/dist/services/persona-actor-secret.d.ts +0 -38
  236. package/dist/services/persona-actor-secret.js +0 -39
  237. package/dist/services/persona-sign-in.d.ts +0 -117
  238. package/dist/services/persona-sign-in.js +0 -154
  239. package/dist/wirings/actor-flow/index.d.ts +0 -2
  240. package/dist/wirings/actor-flow/run-conversation.d.ts +0 -36
  241. package/dist/wirings/persona/define-personas.d.ts +0 -32
  242. package/dist/wirings/persona/index.d.ts +0 -23
  243. package/dist/wirings/persona/index.js +0 -19
  244. package/knowledge/decisions/internals/actor-flow-conversations-seed-a-hidden-kickoff-message.md +0 -23
  245. package/knowledge/decisions/internals/actor-flow-verdicts-are-llm-self-evaluations.md +0 -25
  246. package/knowledge/decisions/internals/validate-checks-personas-through-a-shared-module.md +0 -43
  247. package/knowledge/decisions/security/actor-sign-in-only-works-for-actor-flagged-users.md +0 -31
  248. package/knowledge/decisions/security/an-actor-credential-is-derived-per-persona.md +0 -42
  249. package/knowledge/decisions/security/pikku-carries-actor-scopes-as-data-and-the-app-grants-them.md +0 -26
  250. /package/dist/wirings/{actor-flow/actor-flow.types.js → virtual-user/conversation/conversation.types.js} +0 -0
  251. /package/dist/wirings/{actor-flow → virtual-user/conversation}/index.js +0 -0
  252. /package/dist/wirings/{persona/persona.types.js → virtual-user/virtual-user-declaration.types.js} +0 -0
  253. /package/dist/wirings/{persona/persona-mailbox.js → virtual-user/virtual-user-mailbox.js} +0 -0
@@ -27,10 +27,10 @@ export { SCENARIO_SURFACES } from './scenario-step.types.js';
27
27
  // Which of a step's bindings run: one for an action, every witness for a `then`
28
28
  export { resolveScenarioSurfaces } from './scenario-surface.js';
29
29
  export { pollUntil } from './scenario-poll.js';
30
- export { createCookieJar } from './scenario-cookie-jar.js';
30
+ export { createCookieJar } from '../../services/scenario-cookie-jar.js';
31
31
  export { composeStepProse, renderStepTemplate } from './scenario-prose.js';
32
32
  export { requireScenarioEnv } from './scenario-step-guards.js';
33
- // The readers themselves live on `@pikku/core/persona`
33
+ // The readers themselves live on `@pikku/core/virtual-user`
34
34
  /**
35
35
  * A workflow service with the scenario capability attached — the two lines
36
36
  * `pikku scenario run` needs, in one call so no caller has to remember that the
@@ -68,7 +68,7 @@ addError(ScenarioHookError, {
68
68
  * Two witnesses of the same `then` disagreed.
69
69
  *
70
70
  * This is the failure the whole additive-witness design exists to produce: the
71
- * system of record is right and the surface the actor was looking at is not, or
71
+ * system of record is right and the surface the virtual user was looking at is not, or
72
72
  * the other way round. Both observations go in the message, because either one
73
73
  * alone reads as a passing assertion.
74
74
  */
@@ -105,24 +105,24 @@ addError(ScenarioBrowserUnavailable, {
105
105
  message: 'No browser provider is registered.',
106
106
  });
107
107
  /**
108
- * A step that is driven by a persona was dispatched without one.
108
+ * A step that is driven by a virtual user was dispatched without one.
109
109
  *
110
110
  * Raised before the body runs rather than partway through it: the step declared
111
- * that it needs an actor — by having a `browser` binding, which cannot be
112
- * provisioned without a window to open, or by `actor: true` — so a call site
111
+ * that it needs a virtual user — by having a `browser` binding, which cannot be
112
+ * provisioned without a window to open, or by `virtualUser: true` — so a call site
113
113
  * that omits one is a mistake at the call site.
114
114
  */
115
- export class ScenarioActorRequired extends PikkuError {
115
+ export class ScenarioVirtualUserRequired extends PikkuError {
116
116
  stepFunc;
117
117
  constructor(stepFunc) {
118
- super(`[scenario] step '${stepFunc}' is driven by a persona but was called without an actor. ` +
119
- `Pass { actor: actors.<name> } so it runs as that persona.`);
118
+ super(`[scenario] step '${stepFunc}' is driven by a virtual user but was called without a virtual user. ` +
119
+ `Pass { virtualUser: virtualUsers.<name> } so it runs as that virtual user.`);
120
120
  this.stepFunc = stepFunc;
121
121
  }
122
122
  }
123
- addError(ScenarioActorRequired, {
123
+ addError(ScenarioVirtualUserRequired, {
124
124
  status: 500,
125
- message: 'This step needs an actor.',
125
+ message: 'This step needs a virtual user.',
126
126
  });
127
127
  /**
128
128
  * A step declares no binding the run can execute.
@@ -186,7 +186,7 @@ addError(ScenarioNoWitness, {
186
186
  * An assertion ran, but not on the surface the run targets.
187
187
  *
188
188
  * The sibling of {@link ScenarioNoWitness}: that one checked nothing anywhere,
189
- * this one checked the system of record while the prose claims the actor saw it
189
+ * this one checked the system of record while the prose claims the virtual user saw it
190
190
  * on the page. Ordinary runs count it as a coverage gap; a strict run refuses
191
191
  * it, because a flow that cannot be observed end to end on the run surface is
192
192
  * not a flow that surface can be documented from.
@@ -198,7 +198,7 @@ export class ScenarioUnwitnessedAssertion extends PikkuError {
198
198
  witnessedOn;
199
199
  constructor(stepFunc, declared, runSurface, witnessedOn) {
200
200
  super(`[scenario] assertion '${stepFunc}' was checked on ${witnessedOn.join(', ')}, not on '${runSurface}'. ` +
201
- `It held there — but nothing looked at '${runSurface}', which is what the step's prose claims the actor saw. ` +
201
+ `It held there — but nothing looked at '${runSurface}', which is what the step's prose claims the virtual user saw. ` +
202
202
  `Add a '${runSurface}' witness (declares: ${declared.join(', ') || 'nothing'}), or drop --strict.`);
203
203
  this.stepFunc = stepFunc;
204
204
  this.declared = declared;
@@ -214,7 +214,7 @@ addError(ScenarioUnwitnessedAssertion, {
214
214
  * The scenario capability, layered onto a workflow service rather than being
215
215
  * one.
216
216
  *
217
- * Every scenario affordance — steps, actors, lifecycle hooks, the browser
217
+ * Every scenario affordance — steps, virtual users, lifecycle hooks, the browser
218
218
  * provider, the assertion wire members — lives here rather than on
219
219
  * `PikkuWorkflowService`, because a bundler drops an unused *module* but never
220
220
  * an unused class member: anything declared on the workflow service ships in
@@ -236,14 +236,14 @@ addError(ScenarioUnwitnessedAssertion, {
236
236
  */
237
237
  export class PikkuScenarioService {
238
238
  engine;
239
- // Scenario actors per run: live authenticated clients (cookie jars) are
239
+ // Scenario virtual users per run: live authenticated clients (cookie jars) are
240
240
  // process-local by nature, so they ride this map, never the persisted wire.
241
- runActors = new Map();
242
- // What each run has accumulated so far — process-local like the actors above,
241
+ runVirtualUsers = new Map();
242
+ // What each run has accumulated so far — process-local like the virtual users above,
243
243
  // so the body and its hooks share one object rather than reading it back off
244
244
  // the persisted wire.
245
245
  runContexts = new Map();
246
- // Where each browser step landed in its actor's recording, per run. Held
246
+ // Where each browser step landed in its virtual user's recording, per run. Held
247
247
  // apart from the run context because the runner reads it once the run has
248
248
  // ended, which is exactly when `detachRunContext` has cleared that.
249
249
  runVideoOffsets = new Map();
@@ -255,7 +255,7 @@ export class PikkuScenarioService {
255
255
  this.engine = engine;
256
256
  }
257
257
  /**
258
- * The surface every actor drives the system through for this run, set once by
258
+ * The surface every virtual user drives the system through for this run, set once by
259
259
  * the runner from `--run`. `default` is the server-side path — the fast suite.
260
260
  *
261
261
  * `strict` removes both routes off that surface: an action may not fall back
@@ -297,7 +297,7 @@ export class PikkuScenarioService {
297
297
  return this.scenarioEnvironment;
298
298
  }
299
299
  /**
300
- * Where each of a run's browser steps fell in its actor's video, keyed by the
300
+ * Where each of a run's browser steps fell in its virtual user's video, keyed by the
301
301
  * durable step name, handed over and forgotten in one call.
302
302
  *
303
303
  * Taken rather than read because the runner joins these onto the step rows
@@ -309,51 +309,51 @@ export class PikkuScenarioService {
309
309
  this.runVideoOffsets.delete(runId);
310
310
  return offsets ?? new Map();
311
311
  }
312
- /** Where a step starting now falls in this actor's recording, if anywhere. */
313
- videoOffsetFor(actor) {
312
+ /** Where a step starting now falls in this virtual user's recording, if anywhere. */
313
+ videoOffsetFor(virtualUser) {
314
314
  const provider = this.scenarioBrowserProvider;
315
315
  if (provider?.markVideoStep) {
316
- return provider.markVideoStep(actor);
316
+ return provider.markVideoStep(virtualUser);
317
317
  }
318
- const startedAt = provider?.videoStartedAt?.(actor);
318
+ const startedAt = provider?.videoStartedAt?.(virtualUser);
319
319
  return startedAt === undefined
320
320
  ? undefined
321
321
  : Math.max(0, Date.now() - startedAt);
322
322
  }
323
323
  /**
324
- * Stamp where a step began inside one actor's recording.
324
+ * Stamp where a step began inside one virtual user's recording.
325
325
  *
326
- * First write per actor wins: a `then` step runs once per witness, and the
326
+ * First write per virtual user wins: a `then` step runs once per witness, and the
327
327
  * moment the reader wants is when the sentence started, not when its last
328
328
  * witness got around to the browser.
329
329
  */
330
- recordVideoOffset(runId, stepName, actor, offsetMs) {
330
+ recordVideoOffset(runId, stepName, virtualUser, offsetMs) {
331
331
  let byStep = this.runVideoOffsets.get(runId);
332
332
  if (!byStep) {
333
333
  byStep = new Map();
334
334
  this.runVideoOffsets.set(runId, byStep);
335
335
  }
336
336
  const offsets = byStep.get(stepName) ?? [];
337
- if (offsets.some((offset) => offset.actor === actor)) {
337
+ if (offsets.some((offset) => offset.virtualUser === virtualUser)) {
338
338
  return;
339
339
  }
340
- offsets.push({ actor, offsetMs });
340
+ offsets.push({ virtualUser, offsetMs });
341
341
  byStep.set(stepName, offsets);
342
342
  }
343
343
  async attachRunContext(runId, workflowMeta, options) {
344
- const actors = options?.actors ??
344
+ const virtualUsers = options?.virtualUsers ??
345
345
  (workflowMeta.source === 'scenario'
346
- ? await this.resolvePersonas()
346
+ ? await this.resolveVirtualUsers()
347
347
  : undefined);
348
- if (actors) {
349
- this.runActors.set(runId, actors);
348
+ if (virtualUsers) {
349
+ this.runVirtualUsers.set(runId, virtualUsers);
350
350
  }
351
351
  if (workflowMeta.source === 'scenario') {
352
352
  this.runContexts.set(runId, {});
353
353
  }
354
354
  }
355
355
  detachRunContext(runId) {
356
- this.runActors.delete(runId);
356
+ this.runVirtualUsers.delete(runId);
357
357
  this.runContexts.delete(runId);
358
358
  }
359
359
  /**
@@ -383,7 +383,7 @@ export class PikkuScenarioService {
383
383
  context.workflowMeta?.source === 'scenario'
384
384
  ? context.workflowWire
385
385
  : undefined;
386
- wire.actors = this.runActors.get(context.runId);
386
+ wire.virtualUsers = this.runVirtualUsers.get(context.runId);
387
387
  }
388
388
  async onBeforeRunFunc(context) {
389
389
  const hooks = this.scenarioHooks(context);
@@ -436,7 +436,7 @@ export class PikkuScenarioService {
436
436
  *
437
437
  * A hook is not a pikku function: it has no id, no meta and no schema, so it
438
438
  * cannot go through `runPikkuFunc` and the runner records nothing for it. It
439
- * gets exactly what the scenario body gets — the same wire (so `actors` is
439
+ * gets exactly what the scenario body gets — the same wire (so `virtualUsers` is
440
440
  * how it reaches the app), and singleton services composed with this
441
441
  * invocation's wire services — and nothing else.
442
442
  */
@@ -467,44 +467,42 @@ export class PikkuScenarioService {
467
467
  }
468
468
  }
469
469
  /**
470
- * Build HTTP scenario actors for a run started without them; undefined when
471
- * SCENARIO_ACTOR_SECRET or the API URL is missing.
470
+ * Build HTTP scenario virtual users for a run started without them; undefined when
471
+ * the app has no auth service or the API URL is missing.
472
472
  *
473
- * The actor client is imported lazily so that even a runner bundle only pays
474
- * for the AI persona conversation loop it pulls in when a scenario actually
475
- * signs an actor in.
473
+ * The virtual user client is imported lazily so that even a runner bundle only pays
474
+ * for the AI virtual user conversation loop it pulls in when a scenario actually
475
+ * signs a virtual user in.
476
476
  */
477
- async resolvePersonas() {
477
+ async resolveVirtualUsers() {
478
478
  const services = getSingletonServices();
479
479
  const variables = services?.variables;
480
480
  const metaService = services?.metaService;
481
481
  if (!variables || !metaService) {
482
482
  return undefined;
483
483
  }
484
- const secret = await variables.get('SCENARIO_ACTOR_SECRET');
484
+ const auth = await services?.auth?.();
485
485
  const apiUrl = await variables.get('API_URL');
486
- if (!secret || !apiUrl) {
487
- services?.logger?.warn('A scenario was started without personas but SCENARIO_ACTOR_SECRET / API_URL is not configured — running without them.');
486
+ if (!auth || !apiUrl) {
487
+ services?.logger?.warn('A scenario was started without virtual users but the auth service / API_URL is not configured — running without them.');
488
488
  return undefined;
489
489
  }
490
- const personas = await metaService.getPersonasMeta();
491
- if (!personas || Object.keys(personas).length === 0) {
490
+ const virtualUsers = await metaService.getVirtualUsersMeta();
491
+ if (!virtualUsers || Object.keys(virtualUsers).length === 0) {
492
492
  return undefined;
493
493
  }
494
- const signInPath = (await variables.get('SCENARIO_SIGN_IN_PATH')) ??
495
- '/api/auth/sign-in/actor';
496
494
  const rpcPath = (await variables.get('SCENARIO_RPC_PATH')) ?? '/rpc';
497
495
  // A run started outside the CLI still targets an environment — its own.
498
496
  this.scenarioEnvironment ??= {
499
497
  apiUrl,
500
498
  appUrl: (await variables.get('APP_URL')) ?? undefined,
501
499
  };
502
- const { createHttpPersonas } = await import('../../services/http-personas.js');
503
- return createHttpPersonas({
500
+ const { createHttpVirtualUsers } = await import('../../services/http-virtual-users.js');
501
+ const { inProcessSignIn } = await import('../../services/virtual-user-sign-in.js');
502
+ return createHttpVirtualUsers({
504
503
  apiUrl,
505
- secret,
506
- personas,
507
- signInPath,
504
+ signIn: inProcessSignIn(auth),
505
+ virtualUsers,
508
506
  rpcPath,
509
507
  });
510
508
  }
@@ -520,7 +518,7 @@ export class PikkuScenarioService {
520
518
  });
521
519
  Object.assign(workflowWire, {
522
520
  context: this.contextForRun(runId),
523
- // Durable polling step: invoke an RPC (as an actor when options.as is
521
+ // Durable polling step: invoke an RPC (as a virtual user when options.as is
524
522
  // set) until the predicate passes or `within` elapses. The whole poll is
525
523
  // ONE recorded step, so replay returns the cached outcome.
526
524
  expectEventually: async (stepName, rpcName, data, predicate, options) => {
@@ -534,14 +532,14 @@ export class PikkuScenarioService {
534
532
  const deadline = Date.now() + within;
535
533
  let last;
536
534
  while (true) {
537
- last = options?.actor
538
- ? await options.actor.invoke(resolvedRpcName, data)
535
+ last = options?.virtualUser
536
+ ? await options.virtualUser.invoke(resolvedRpcName, data)
539
537
  : await rpcService.rpcWithWire(resolvedRpcName, data, {});
540
538
  if (predicate(last))
541
539
  return last;
542
540
  if (Date.now() + interval > deadline) {
543
541
  throw new Error(`[workflow] expectEventually '${stepName}' ('${resolvedRpcName}'` +
544
- `${options?.actor ? ` as '${options.actor.name}'` : ''}) did not pass within ${within}ms; ` +
542
+ `${options?.virtualUser ? ` as '${options.virtualUser.name}'` : ''}) did not pass within ${within}ms; ` +
545
543
  `last result: ${JSON.stringify(last)?.slice(0, 300)}`);
546
544
  }
547
545
  await new Promise((resolve) => setTimeout(resolve, interval));
@@ -556,8 +554,8 @@ export class PikkuScenarioService {
556
554
  return await this.engine.inlineStep(runId, stepName, async () => {
557
555
  let result;
558
556
  try {
559
- result = options?.actor
560
- ? await options.actor.invoke(resolvedRpcName, data)
557
+ result = options?.virtualUser
558
+ ? await options.virtualUser.invoke(resolvedRpcName, data)
561
559
  : await rpcService.rpcWithWire(resolvedRpcName, data, {});
562
560
  }
563
561
  catch (e) {
@@ -583,8 +581,8 @@ export class PikkuScenarioService {
583
581
  }
584
582
  await this.engine.inlineStep(runId, stepName, async () => {
585
583
  const rpcName = 'pikkuScenarioGetStubCalls';
586
- const calls = options?.actor
587
- ? await options.actor.invoke(rpcName, { service })
584
+ const calls = options?.virtualUser
585
+ ? await options.virtualUser.invoke(rpcName, { service })
588
586
  : await rpcService.rpcWithWire(rpcName, { service }, {});
589
587
  const matching = (calls ?? []).filter((c) => c.service === service &&
590
588
  c.method === method &&
@@ -615,8 +613,8 @@ export class PikkuScenarioService {
615
613
  ? { reference: options.reference }
616
614
  : {}),
617
615
  };
618
- const grade = options?.actor
619
- ? await options.actor.invoke(rpcName, data)
616
+ const grade = options?.virtualUser
617
+ ? await options.virtualUser.invoke(rpcName, data)
620
618
  : await rpcService.rpcWithWire(rpcName, data, {});
621
619
  // A scorer that graded is a scorer that answered, so an unstated
622
620
  // bound still fails a zero rather than passing anything at all.
@@ -655,12 +653,13 @@ export class PikkuScenarioService {
655
653
  const resolvedStepFunc = addonNamespace && !stepFunc.includes(':')
656
654
  ? `${addonNamespace}:${stepFunc}`
657
655
  : stepFunc;
658
- const actor = options?.actor;
656
+ const virtualUser = options?.virtualUser;
659
657
  const description = options?.description ??
660
658
  this.scenarioStepDescription(packageName, resolvedStepFunc) ??
661
659
  stepName;
662
- if (!actor && this.requiresActor(packageName, resolvedStepFunc)) {
663
- throw new ScenarioActorRequired(resolvedStepFunc);
660
+ if (!virtualUser &&
661
+ this.requiresVirtualUser(packageName, resolvedStepFunc)) {
662
+ throw new ScenarioVirtualUserRequired(resolvedStepFunc);
664
663
  }
665
664
  const declared = this.declaredSurfaces(packageName, resolvedStepFunc);
666
665
  const resolution = resolveScenarioSurfaces(phase, declared, this.runSurface);
@@ -671,8 +670,8 @@ export class PikkuScenarioService {
671
670
  workflow: workflowWire,
672
671
  scenario: workflowWire,
673
672
  pikkuUserId: workflowWire.pikkuUserId,
674
- actors: this.runActors.get(runId),
675
- ...(actor ? { actor } : {}),
673
+ virtualUsers: this.runVirtualUsers.get(runId),
674
+ ...(virtualUser ? { virtualUser } : {}),
676
675
  scenarioStep: {
677
676
  name: resolvedStepFunc,
678
677
  stepName,
@@ -686,12 +685,12 @@ export class PikkuScenarioService {
686
685
  if (!this.scenarioBrowserProvider) {
687
686
  throw new ScenarioBrowserUnavailable(resolvedStepFunc);
688
687
  }
689
- // The dispatch guard above already refused an actor-less call, and a
688
+ // The dispatch guard above already refused an anonymous call, and a
690
689
  // browser binding always requires one.
691
- wire.browser = await this.scenarioBrowserProvider.sessionFor(actor.name);
692
- const offsetMs = this.videoOffsetFor(actor.name);
690
+ wire.browser = await this.scenarioBrowserProvider.sessionFor(virtualUser.name);
691
+ const offsetMs = this.videoOffsetFor(virtualUser.name);
693
692
  if (offsetMs !== undefined) {
694
- this.recordVideoOffset(runId, stepName, actor.name, offsetMs);
693
+ this.recordVideoOffset(runId, stepName, virtualUser.name, offsetMs);
695
694
  }
696
695
  }
697
696
  const result = await runPikkuFunc('workflow', workflowName, resolvedStepFunc, {
@@ -765,10 +764,11 @@ export class PikkuScenarioService {
765
764
  return surfaces?.length ? surfaces : ['default'];
766
765
  }
767
766
  /**
768
- * Whether a step is driven by a persona, and so must be given one. Stamped by
769
- * the definer from a `browser` binding or an explicit `actor: true`.
767
+ * Whether a step is driven by a virtual user, and so must be given one. Stamped by
768
+ * the definer from a `browser` binding or an explicit `virtualUser: true`.
770
769
  */
771
- requiresActor(packageName, stepFunc) {
772
- return (this.scenarioStepConfig(packageName, stepFunc)?.requiresActor === true);
770
+ requiresVirtualUser(packageName, stepFunc) {
771
+ return (this.scenarioStepConfig(packageName, stepFunc)?.requiresVirtualUser ===
772
+ true);
773
773
  }
774
774
  }
@@ -3,7 +3,7 @@ import type { SerializedError } from '../../errors/serialized-error.js';
3
3
  import type { GroupConcurrencyConfig, JobGroup, JobOptions } from '../queue/queue.types.js';
4
4
  import type { PikkuWorkflowWire, StepState, StepStatus, WorkflowPlannedStep, WorkflowRun, WorkflowRunMirror, WorkflowRunStatus, WorkflowRunWire, WorkflowStatus, WorkflowVersionStatus, WorkflowQueueOptions, WorkflowStepOptions } from './workflow.types.js';
5
5
  import type { WorkflowService } from '../../services/workflow-service.js';
6
- import type { ScenarioPersonas } from '../../services/personas-service.js';
6
+ import type { ScenarioVirtualUsers } from '../../services/virtual-users-service.js';
7
7
  import type { PikkuRPC } from '../rpc/rpc-types.js';
8
8
  import { type RunTimeline, type ReconstructedRunState } from './run-timeline.js';
9
9
  import type { WorkflowRunEngine, WorkflowRunExtension } from './workflow-run-engine.types.js';
@@ -194,7 +194,7 @@ export declare abstract class PikkuWorkflowService implements WorkflowService {
194
194
  startWorkflow<I>(name: string, input: I, wire: WorkflowRunWire, rpcService: PikkuRPC, options?: {
195
195
  inline?: boolean;
196
196
  startNode?: string;
197
- actors?: ScenarioPersonas;
197
+ virtualUsers?: ScenarioVirtualUsers;
198
198
  onRunCreated?: (runId: string) => void;
199
199
  }): Promise<{
200
200
  runId: string;
@@ -818,7 +818,7 @@ export class PikkuWorkflowService {
818
818
  const resolvedStepOptions = {
819
819
  retries: stepOptions?.retries ?? DEFAULT_STEP_RETRIES,
820
820
  retryDelay: stepOptions?.retryDelay,
821
- actor: stepOptions?.actor,
821
+ virtualUser: stepOptions?.virtualUser,
822
822
  };
823
823
  const stepState = await this.loadOrCreateStep(runId, stepName, async () => {
824
824
  if (stepOptions?.compensate === false) {
@@ -844,7 +844,7 @@ export class PikkuWorkflowService {
844
844
  if (lease === 'held') {
845
845
  throw new WorkflowAsyncException(runId, stepName);
846
846
  }
847
- const dispatched = resolvedStepOptions.actor
847
+ const dispatched = resolvedStepOptions.virtualUser
848
848
  ? false
849
849
  : await this.dispatchStep(runId, stepName, rpcName, data, resolvedStepOptions, fromStepName);
850
850
  if (dispatched) {
@@ -856,8 +856,8 @@ export class PikkuWorkflowService {
856
856
  const retries = resolvedStepOptions.retries ?? this.getConfig().retries;
857
857
  const retryDelay = resolvedStepOptions.retryDelay;
858
858
  return runInlineRetryLoop(this, stepState, retries, retryDelay, async (currentStepState) => {
859
- if (resolvedStepOptions.actor) {
860
- return resolvedStepOptions.actor.invoke(rpcName, data);
859
+ if (resolvedStepOptions.virtualUser) {
860
+ return resolvedStepOptions.virtualUser.invoke(rpcName, data);
861
861
  }
862
862
  if (pikkuState(null, 'workflows', 'meta')[rpcName]) {
863
863
  return runInlineChildStep({
@@ -1,25 +1,25 @@
1
1
  import type { ScenarioStepPhase } from './scenario-step.types.js';
2
2
  export declare const renderStepTemplate: (template: string, input: unknown) => string;
3
- export declare const composeStepProse: ({ phase, description, template, input, actor, actorRole, continuesPhase, continuesActor, keywordWidth, }: {
3
+ export declare const composeStepProse: ({ phase, description, template, input, virtualUser, virtualUserRole, continuesPhase, continuesVirtualUser, keywordWidth, }: {
4
4
  phase: ScenarioStepPhase;
5
5
  description: string;
6
6
  template?: string;
7
7
  input?: unknown;
8
- actor?: string;
8
+ virtualUser?: string;
9
9
  /**
10
- * What this actor is, rendered as an apposition after their key — "yasser
11
- * (the founder)". Only pass it where the actor has not been named yet: an
12
- * ordinary run repeats one actor for a dozen steps, and repeating the role
10
+ * What this virtual user is, rendered as an apposition after their key — "yasser
11
+ * (the founder)". Only pass it where the virtual user has not been named yet: an
12
+ * ordinary run repeats one virtual user for a dozen steps, and repeating the role
13
13
  * with them turns the one piece of context into the noise around it.
14
14
  */
15
- actorRole?: string;
15
+ virtualUserRole?: string;
16
16
  /**
17
17
  * This step repeats the phase of the one before it, so it reads as `And`
18
18
  * rather than saying `Given` three times — the same thing Gherkin does.
19
19
  */
20
20
  continuesPhase?: boolean;
21
21
  /**
22
- * The step before this one had the same actor. Combined with `continuesPhase`
22
+ * The step before this one had the same virtual user. Combined with `continuesPhase`
23
23
  * the subject is dropped, because English drops a repeated subject in a
24
24
  * compound predicate: "yasser opens the dashboard / and sees the audit log".
25
25
  *
@@ -27,6 +27,6 @@ export declare const composeStepProse: ({ phase, description, template, input, a
27
27
  * the dashboard", and a pronoun instead of a name would give "they sees",
28
28
  * since step templates are authored in the third person singular.
29
29
  */
30
- continuesActor?: boolean;
30
+ continuesVirtualUser?: boolean;
31
31
  keywordWidth?: number;
32
32
  }) => string;
@@ -14,13 +14,15 @@ const formatValue = (value) => {
14
14
  }
15
15
  return String(value);
16
16
  };
17
- export const composeStepProse = ({ phase, description, template, input, actor, actorRole, continuesPhase, continuesActor, keywordWidth, }) => {
17
+ export const composeStepProse = ({ phase, description, template, input, virtualUser, virtualUserRole, continuesPhase, continuesVirtualUser, keywordWidth, }) => {
18
18
  const keyword = capitalise(continuesPhase ? 'and' : phase);
19
- // The actor key is the subject verbatim, with no article in front of it.
20
- // "the ${actor}" only reads as English when the key happens to be a role
21
- // noun — it turns a persona named after a person into "the nadia", which
19
+ // The virtual user key is the subject verbatim, with no article in front of it.
20
+ // "the ${virtual user}" only reads as English when the key happens to be a role
21
+ // noun — it turns a virtual user named after a person into "the nadia", which
22
22
  // is the reporter quietly imposing a naming convention on the author.
23
- const subject = continuesPhase && continuesActor ? '' : composeSubject(actor, actorRole);
23
+ const subject = continuesPhase && continuesVirtualUser
24
+ ? ''
25
+ : composeSubject(virtualUser, virtualUserRole);
24
26
  const rendered = template ? renderStepTemplate(template, input) : description;
25
27
  const sentence = [subject, rendered].filter(Boolean).join(' ');
26
28
  if (keywordWidth === undefined) {
@@ -28,9 +30,11 @@ export const composeStepProse = ({ phase, description, template, input, actor, a
28
30
  }
29
31
  return `${keyword.padEnd(keywordWidth)} ${sentence}`;
30
32
  };
31
- const composeSubject = (actor, actorRole) => {
32
- if (!actor)
33
+ const composeSubject = (virtualUser, virtualUserRole) => {
34
+ if (!virtualUser)
33
35
  return '';
34
- return actorRole ? `${actor} (the ${actorRole})` : actor;
36
+ return virtualUserRole
37
+ ? `${virtualUser} (the ${virtualUserRole})`
38
+ : virtualUser;
35
39
  };
36
40
  const capitalise = (value) => value.charAt(0).toUpperCase() + value.slice(1);
@@ -27,8 +27,8 @@ export interface ScenarioArtifact {
27
27
  scenario: string;
28
28
  kind: ScenarioArtifactKind;
29
29
  path: string;
30
- /** Whose window it was — a two-actor scenario produces two of everything. */
31
- actor?: string;
30
+ /** Whose window it was — a two-virtual-user scenario produces two of everything. */
31
+ virtualUser?: string;
32
32
  /** The caption the scenario author took a screenshot under. */
33
33
  name?: string;
34
34
  /**
@@ -42,9 +42,9 @@ export interface ScenarioArtifact {
42
42
  showcase?: boolean;
43
43
  }
44
44
  /**
45
- * Where a step falls inside one actor's recording.
45
+ * Where a step falls inside one virtual user's recording.
46
46
  *
47
- * Measured from the moment that actor's browser context opened — which is when
47
+ * Measured from the moment that virtual user's browser context opened — which is when
48
48
  * Playwright starts the file — rather than from the start of the scenario, so
49
49
  * it addresses the video's own clock. The two differ by however long the
50
50
  * scenario spent before that window existed, plus every non-browser step since,
@@ -52,17 +52,17 @@ export interface ScenarioArtifact {
52
52
  * being summed back out of the ladder afterwards.
53
53
  */
54
54
  export interface ScenarioStepVideoOffset {
55
- /** Whose recording this offset is into: one actor, one video file. */
56
- actor: string;
55
+ /** Whose recording this offset is into: one virtual user, one video file. */
56
+ virtualUser: string;
57
57
  offsetMs: number;
58
58
  }
59
59
  /** One step of a run, already joined to the prose that declared it. */
60
60
  export interface ScenarioStepRow {
61
61
  sentence: string;
62
62
  /**
63
- * The same sentence with the actor's role in it — "yasser (the founder)
64
- * signs in". Set only on the step that first names each actor, and only
65
- * when a persona declares a job title or a role, so a reader who wants the
63
+ * The same sentence with the virtual user's role in it — "yasser (the founder)
64
+ * signs in". Set only on the step that first names each virtual user, and only
65
+ * when a virtual user declares a job title or a role, so a reader who wants the
66
66
  * context picks this and one who wants the bare run picks `sentence`.
67
67
  */
68
68
  sentenceWithRole?: string;
@@ -70,11 +70,11 @@ export interface ScenarioStepRow {
70
70
  durationMs?: number;
71
71
  error?: string;
72
72
  /**
73
- * Where this step lands in each actor's video, for the actors whose window
74
- * was being recorded when it ran. Absent for a step with no actor, a run
73
+ * Where this step lands in each virtual user's video, for the virtual users whose window
74
+ * was being recorded when it ran. Absent for a step with no virtual user, a run
75
75
  * without video, and a step that never ran at all.
76
76
  *
77
- * A list rather than one number because a video belongs to an actor, not to
77
+ * A list rather than one number because a video belongs to a virtual user, not to
78
78
  * the scenario: a step touching two windows falls at a different moment in
79
79
  * each, and an offset that does not name its file cannot be seeked to.
80
80
  */
@@ -126,7 +126,7 @@ export interface ScenarioResult {
126
126
  title?: string;
127
127
  description?: string;
128
128
  /** Who the scenario cast, in declaration order. */
129
- actors?: string[];
129
+ virtualUsers?: string[];
130
130
  tags?: string[];
131
131
  /** Images and footage this scenario produced, filed under the run. */
132
132
  artifacts?: ScenarioArtifact[];