@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.
- package/CHANGELOG.md +1171 -0
- package/dist/column-form.d.ts +32 -0
- package/dist/column-form.js +42 -0
- package/dist/crypto-utils.d.ts +43 -7
- package/dist/crypto-utils.js +163 -42
- package/dist/data-classification.d.ts +44 -0
- package/dist/dev/hot-reload.js +11 -30
- package/dist/dev/module-runner.d.ts +3 -7
- package/dist/dev/module-runner.js +4 -10
- package/dist/dev/reload-meta.d.ts +8 -20
- package/dist/dev/reload-meta.js +9 -29
- package/dist/errors/error-handler.d.ts +5 -30
- package/dist/errors/error-handler.js +16 -32
- package/dist/errors/errors.d.ts +32 -151
- package/dist/errors/errors.js +55 -157
- package/dist/function/abort-scope.d.ts +47 -0
- package/dist/function/abort-scope.js +63 -0
- package/dist/function/function-runner.js +37 -32
- package/dist/function/functions.types.d.ts +57 -136
- package/dist/function/functions.types.js +0 -58
- package/dist/function/index.d.ts +1 -1
- package/dist/function/list.types.d.ts +12 -62
- package/dist/function/list.types.js +4 -25
- package/dist/handle-error.d.ts +0 -13
- package/dist/handle-error.js +0 -18
- package/dist/index.d.ts +11 -5
- package/dist/index.js +7 -2
- package/dist/middleware/auth-apikey.d.ts +3 -18
- package/dist/middleware/auth-apikey.js +0 -17
- package/dist/middleware/auth-bearer.d.ts +6 -41
- package/dist/middleware/auth-bearer.js +5 -41
- package/dist/middleware/auth-cookie.d.ts +5 -27
- package/dist/middleware/auth-cookie.js +2 -26
- package/dist/middleware/cors.d.ts +7 -34
- package/dist/middleware/cors.js +7 -34
- package/dist/middleware/remote-auth.d.ts +3 -1
- package/dist/middleware/remote-auth.js +4 -3
- package/dist/middleware/telemetry.d.ts +8 -33
- package/dist/middleware/telemetry.js +2 -31
- package/dist/middleware-runner.d.ts +4 -55
- package/dist/middleware-runner.js +5 -74
- package/dist/permissions.d.ts +3 -44
- package/dist/permissions.js +19 -71
- package/dist/pikku-request.d.ts +0 -6
- package/dist/pikku-request.js +0 -6
- package/dist/pikku-state.d.ts +0 -26
- package/dist/pikku-state.js +2 -30
- package/dist/remote.d.ts +3 -5
- package/dist/remote.js +9 -8
- package/dist/schema.d.ts +5 -39
- package/dist/schema.js +5 -39
- package/dist/scopes.d.ts +4 -23
- package/dist/scopes.js +7 -48
- package/dist/secret-value.d.ts +56 -0
- package/dist/secret-value.js +46 -0
- package/dist/services/ai-agent-runner-service.d.ts +20 -0
- package/dist/services/ai-embedding-service.d.ts +2 -25
- package/dist/services/audit-service.d.ts +74 -4
- package/dist/services/audit-service.js +8 -7
- package/dist/services/content-service.d.ts +1 -46
- package/dist/services/credential-service.d.ts +3 -40
- package/dist/services/credential-wire-service.d.ts +5 -0
- package/dist/services/credential-wire-service.js +9 -1
- package/dist/services/deployment-service.d.ts +3 -9
- package/dist/services/email-service.d.ts +2 -1
- package/dist/services/gateway-service.d.ts +0 -15
- package/dist/services/http-personas.d.ts +80 -0
- package/dist/services/http-personas.js +233 -0
- package/dist/services/in-memory-queue-service.d.ts +0 -14
- package/dist/services/in-memory-queue-service.js +1 -15
- package/dist/services/in-memory-trigger-service.d.ts +0 -18
- package/dist/services/in-memory-trigger-service.js +1 -18
- package/dist/services/in-memory-workflow-service.d.ts +0 -16
- package/dist/services/in-memory-workflow-service.js +4 -33
- package/dist/services/index.d.ts +8 -9
- package/dist/services/index.js +3 -6
- package/dist/services/istanbul-coverage-service.d.ts +1 -5
- package/dist/services/istanbul-coverage-service.js +2 -8
- package/dist/services/jwt-service.d.ts +1 -16
- package/dist/services/local-content-request-handler.d.ts +29 -0
- package/dist/services/local-content-request-handler.js +176 -0
- package/dist/services/local-content.d.ts +13 -2
- package/dist/services/local-content.js +40 -13
- package/dist/services/local-gateway-service.d.ts +0 -16
- package/dist/services/local-gateway-service.js +2 -17
- package/dist/services/local-secrets.d.ts +4 -7
- package/dist/services/local-secrets.js +7 -7
- package/dist/services/logger-console.d.ts +3 -7
- package/dist/services/logger-console.js +3 -7
- package/dist/services/logger.d.ts +22 -40
- package/dist/services/meta-service.d.ts +23 -26
- package/dist/services/meta-service.js +22 -36
- package/dist/services/personas-service.d.ts +134 -0
- package/dist/services/personas-service.js +40 -0
- package/dist/services/pikku-user-id.js +0 -4
- package/dist/services/queue-webhook-service.d.ts +2 -36
- package/dist/services/queue-webhook-service.js +10 -42
- package/dist/services/scheduler-service.d.ts +1 -50
- package/dist/services/scheduler-service.js +0 -10
- package/dist/services/schema-service.d.ts +1 -24
- package/dist/services/scope-service.d.ts +49 -34
- package/dist/services/scoped-secret-service.d.ts +4 -7
- package/dist/services/scoped-secret-service.js +0 -4
- package/dist/services/secret-host-binding.d.ts +8 -0
- package/dist/services/secret-host-binding.js +36 -0
- package/dist/services/secret-service.d.ts +12 -35
- package/dist/services/secretless.d.ts +6 -0
- package/dist/services/secretless.js +21 -0
- package/dist/services/stub-tracker.d.ts +7 -18
- package/dist/services/stub-tracker.js +8 -18
- package/dist/services/system-role-guard.d.ts +33 -0
- package/dist/services/system-role-guard.js +38 -0
- package/dist/services/trigger-service.d.ts +0 -12
- package/dist/services/typed-secret-service.d.ts +5 -11
- package/dist/services/typed-secret-service.js +1 -7
- package/dist/services/v8-coverage-service.d.ts +2 -3
- package/dist/services/v8-coverage-service.js +1 -2
- package/dist/services/variables-service.d.ts +1 -8
- package/dist/services/webhook-service.d.ts +21 -64
- package/dist/services/webhook-service.js +6 -20
- package/dist/services/workflow-service.d.ts +3 -15
- package/dist/testing/service-tests.js +6 -23
- package/dist/time-utils.d.ts +0 -16
- package/dist/time-utils.js +1 -19
- package/dist/types/core.types.d.ts +120 -219
- package/dist/types/core.types.js +0 -42
- package/dist/types/state.types.d.ts +4 -9
- package/dist/utils/hmac.d.ts +4 -10
- package/dist/utils/hmac.js +4 -10
- package/dist/utils/safe-fetch.d.ts +7 -35
- package/dist/utils/safe-fetch.js +13 -53
- package/dist/utils.d.ts +1 -6
- package/dist/utils.js +6 -15
- package/dist/wirings/actor-flow/actor-flow.types.d.ts +1 -34
- package/dist/wirings/actor-flow/index.d.ts +0 -9
- package/dist/wirings/actor-flow/run-conversation.d.ts +5 -5
- package/dist/wirings/actor-flow/run-conversation.js +14 -7
- package/dist/wirings/ai-agent/ai-agent-agui.d.ts +0 -5
- package/dist/wirings/ai-agent/ai-agent-agui.js +46 -12
- package/dist/wirings/ai-agent/ai-agent-helpers.d.ts +7 -0
- package/dist/wirings/ai-agent/ai-agent-helpers.js +7 -0
- package/dist/wirings/ai-agent/ai-agent-interrupt.d.ts +153 -0
- package/dist/wirings/ai-agent/ai-agent-interrupt.js +256 -0
- package/dist/wirings/ai-agent/ai-agent-memory.js +0 -2
- package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +0 -9
- package/dist/wirings/ai-agent/ai-agent-model-config.js +1 -9
- package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +10 -99
- package/dist/wirings/ai-agent/ai-agent-prepare.js +65 -132
- package/dist/wirings/ai-agent/ai-agent-registry.d.ts +2 -1
- package/dist/wirings/ai-agent/ai-agent-registry.js +5 -1
- package/dist/wirings/ai-agent/ai-agent-runner.js +63 -22
- package/dist/wirings/ai-agent/ai-agent-stream.d.ts +25 -2
- package/dist/wirings/ai-agent/ai-agent-stream.js +180 -64
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +124 -4
- package/dist/wirings/ai-agent/index.d.ts +6 -4
- package/dist/wirings/ai-agent/index.js +5 -4
- package/dist/wirings/ai-agent/voice-input.d.ts +59 -1
- package/dist/wirings/ai-agent/voice-input.js +90 -12
- package/dist/wirings/ai-agent/voice-output.d.ts +69 -1
- package/dist/wirings/ai-agent/voice-output.js +162 -50
- package/dist/wirings/channel/channel-common.d.ts +7 -20
- package/dist/wirings/channel/channel-common.js +7 -21
- package/dist/wirings/channel/channel-handler.js +25 -6
- package/dist/wirings/channel/channel-host-rpc.d.ts +25 -0
- package/dist/wirings/channel/channel-host-rpc.js +38 -0
- package/dist/wirings/channel/channel-middleware-runner.d.ts +0 -12
- package/dist/wirings/channel/channel-middleware-runner.js +0 -12
- package/dist/wirings/channel/channel-rpc-registry.d.ts +31 -0
- package/dist/wirings/channel/channel-rpc-registry.js +89 -0
- package/dist/wirings/channel/channel-rpc-responder.d.ts +15 -0
- package/dist/wirings/channel/channel-rpc-responder.js +71 -0
- package/dist/wirings/channel/channel-rpc-service.d.ts +40 -0
- package/dist/wirings/channel/channel-rpc-service.js +106 -0
- package/dist/wirings/channel/channel-rpc-validators.d.ts +14 -0
- package/dist/wirings/channel/channel-rpc-validators.js +30 -0
- package/dist/wirings/channel/channel-rpc.d.ts +5 -0
- package/dist/wirings/channel/channel-rpc.js +5 -0
- package/dist/wirings/channel/channel-rpc.types.d.ts +90 -0
- package/dist/wirings/channel/channel-rpc.types.js +50 -0
- package/dist/wirings/channel/channel-runner.d.ts +0 -4
- package/dist/wirings/channel/channel-runner.js +0 -14
- package/dist/wirings/channel/channel-store.d.ts +0 -10
- package/dist/wirings/channel/channel.types.d.ts +12 -1
- package/dist/wirings/channel/define-channel-routes.d.ts +0 -20
- package/dist/wirings/channel/define-channel-routes.js +0 -20
- package/dist/wirings/channel/eventhub-service.d.ts +0 -18
- package/dist/wirings/channel/index.d.ts +4 -1
- package/dist/wirings/channel/index.js +2 -0
- package/dist/wirings/channel/local/local-channel-runner.js +3 -1
- package/dist/wirings/channel/local/local-eventhub-service.d.ts +0 -33
- package/dist/wirings/channel/local/local-eventhub-service.js +2 -36
- package/dist/wirings/channel/log-channels.d.ts +0 -4
- package/dist/wirings/channel/log-channels.js +0 -4
- package/dist/wirings/channel/pikku-abstract-channel-handler.js +6 -0
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +2 -5
- package/dist/wirings/cli/channel/cli-approval.d.ts +41 -0
- package/dist/wirings/cli/channel/cli-approval.js +81 -0
- package/dist/wirings/cli/channel/cli-channel-runner.d.ts +0 -4
- package/dist/wirings/cli/channel/cli-channel-runner.js +3 -25
- package/dist/wirings/cli/channel/cli-raw-channel-runner.d.ts +47 -9
- package/dist/wirings/cli/channel/cli-raw-channel-runner.js +24 -16
- package/dist/wirings/cli/channel/cli-raw-client-runner.d.ts +38 -0
- package/dist/wirings/cli/channel/cli-raw-client-runner.js +129 -0
- package/dist/wirings/cli/channel/index.d.ts +5 -0
- package/dist/wirings/cli/channel/index.js +2 -0
- package/dist/wirings/cli/cli-runner.d.ts +20 -20
- package/dist/wirings/cli/cli-runner.js +28 -89
- package/dist/wirings/cli/cli.types.d.ts +14 -3
- package/dist/wirings/cli/command-parser.d.ts +1 -10
- package/dist/wirings/cli/command-parser.js +10 -87
- package/dist/wirings/cli/define-cli-commands.d.ts +1 -17
- package/dist/wirings/cli/define-cli-commands.js +1 -17
- package/dist/wirings/credential/credential.types.d.ts +0 -12
- package/dist/wirings/credential/define-credential.d.ts +48 -0
- package/dist/wirings/credential/define-credential.js +47 -0
- package/dist/wirings/credential/index.d.ts +1 -1
- package/dist/wirings/credential/index.js +1 -1
- package/dist/wirings/credential/validate-credential-definitions.d.ts +2 -4
- package/dist/wirings/gateway/gateway-runner.d.ts +1 -20
- package/dist/wirings/gateway/gateway-runner.js +8 -105
- package/dist/wirings/gateway/gateway.types.d.ts +7 -80
- package/dist/wirings/http/http-routes.d.ts +0 -63
- package/dist/wirings/http/http-routes.js +0 -63
- package/dist/wirings/http/http-runner.d.ts +0 -99
- package/dist/wirings/http/http-runner.js +9 -165
- package/dist/wirings/http/http.types.d.ts +14 -55
- package/dist/wirings/http/log-http-routes.d.ts +0 -4
- package/dist/wirings/http/log-http-routes.js +0 -4
- package/dist/wirings/http/pikku-fetch-http-request.d.ts +0 -40
- package/dist/wirings/http/pikku-fetch-http-request.js +0 -58
- package/dist/wirings/http/pikku-fetch-http-response.js +0 -3
- package/dist/wirings/http/routers/path-to-regex.js +2 -13
- package/dist/wirings/http/web-request.d.ts +0 -8
- package/dist/wirings/http/web-request.js +25 -17
- package/dist/wirings/mcp/mcp-runner.d.ts +1 -4
- package/dist/wirings/mcp/mcp-runner.js +1 -14
- package/dist/wirings/mcp/mcp.types.d.ts +2 -35
- package/dist/wirings/oauth2/oauth2.types.d.ts +0 -28
- package/dist/wirings/oauth2/oauth2.types.js +0 -3
- package/dist/wirings/persona/define-personas.d.ts +32 -0
- package/dist/wirings/persona/define-personas.js +31 -0
- package/dist/wirings/persona/index.d.ts +21 -0
- package/dist/wirings/persona/index.js +17 -0
- package/dist/wirings/persona/persona-email.d.ts +37 -0
- package/dist/wirings/persona/persona-email.js +69 -0
- package/dist/wirings/persona/persona-environments.d.ts +45 -0
- package/dist/wirings/persona/persona-environments.js +81 -0
- package/dist/wirings/persona/persona-mailbox.d.ts +101 -0
- package/dist/wirings/persona/persona-mailbox.js +53 -0
- package/dist/wirings/persona/persona.types.d.ts +136 -0
- package/dist/wirings/persona/persona.types.js +1 -0
- package/dist/wirings/persona/validate-personas.d.ts +53 -0
- package/dist/wirings/persona/validate-personas.js +94 -0
- package/dist/wirings/queue/index.d.ts +3 -0
- package/dist/wirings/queue/index.js +2 -3
- package/dist/wirings/queue/queue-identity.d.ts +28 -0
- package/dist/wirings/queue/queue-identity.js +103 -0
- package/dist/wirings/queue/queue-runner.d.ts +0 -19
- package/dist/wirings/queue/queue-runner.js +9 -30
- package/dist/wirings/queue/queue.types.d.ts +20 -90
- package/dist/wirings/queue/register-queue-helper.d.ts +0 -12
- package/dist/wirings/queue/register-queue-helper.js +0 -11
- package/dist/wirings/queue/signed-queue-service.d.ts +17 -0
- package/dist/wirings/queue/signed-queue-service.js +42 -0
- package/dist/wirings/queue/validate-worker-config.d.ts +2 -23
- package/dist/wirings/queue/validate-worker-config.js +0 -14
- package/dist/wirings/role/define-system-role.d.ts +32 -0
- package/dist/wirings/role/define-system-role.js +31 -0
- package/dist/wirings/role/index.d.ts +3 -0
- package/dist/wirings/role/index.js +2 -0
- package/dist/wirings/role/role.types.d.ts +43 -0
- package/dist/wirings/role/role.types.js +1 -0
- package/dist/wirings/role/validate-role-definitions.d.ts +21 -0
- package/dist/wirings/role/validate-role-definitions.js +71 -0
- package/dist/wirings/rpc/addon-runner.d.ts +0 -19
- package/dist/wirings/rpc/addon-runner.js +0 -51
- package/dist/wirings/rpc/remote-addon-auth.d.ts +3 -13
- package/dist/wirings/rpc/remote-addon-auth.js +7 -11
- package/dist/wirings/rpc/rpc-runner.d.ts +11 -18
- package/dist/wirings/rpc/rpc-runner.js +88 -105
- package/dist/wirings/rpc/rpc-types.d.ts +7 -6
- package/dist/wirings/rpc/wire-addon.d.ts +25 -0
- package/dist/wirings/rpc/wire-addon.js +62 -0
- package/dist/wirings/rpc/wire-remote-addon.d.ts +3 -28
- package/dist/wirings/rpc/wire-remote-addon.js +0 -8
- package/dist/wirings/scheduler/log-schedulers.d.ts +0 -4
- package/dist/wirings/scheduler/log-schedulers.js +0 -4
- package/dist/wirings/scheduler/scheduler-runner.d.ts +0 -1
- package/dist/wirings/scheduler/scheduler-runner.js +0 -1
- package/dist/wirings/scheduler/scheduler.types.d.ts +1 -14
- package/dist/wirings/scope/define-scope.d.ts +32 -0
- package/dist/wirings/scope/define-scope.js +31 -0
- package/dist/wirings/scope/index.d.ts +1 -1
- package/dist/wirings/scope/index.js +1 -1
- package/dist/wirings/scope/scope.types.d.ts +7 -9
- package/dist/wirings/scope/validate-scope-definitions.d.ts +2 -21
- package/dist/wirings/scope/validate-scope-definitions.js +3 -21
- package/dist/wirings/secret/index.d.ts +1 -1
- package/dist/wirings/secret/index.js +1 -1
- package/dist/wirings/secret/secret.types.d.ts +19 -15
- package/dist/wirings/secret/secret.types.js +1 -1
- package/dist/wirings/secret/validate-secret-definitions.d.ts +2 -4
- package/dist/wirings/trigger/trigger-runner.d.ts +0 -27
- package/dist/wirings/trigger/trigger-runner.js +1 -24
- package/dist/wirings/trigger/trigger.types.d.ts +1 -82
- package/dist/wirings/trigger/trigger.types.js +0 -34
- package/dist/wirings/variable/index.d.ts +1 -1
- package/dist/wirings/variable/index.js +1 -1
- package/dist/wirings/variable/validate-variable-definitions.d.ts +2 -4
- package/dist/wirings/variable/variable.types.d.ts +1 -13
- package/dist/wirings/variable/variable.types.js +1 -1
- package/dist/wirings/virtual-user/index.d.ts +30 -0
- package/dist/wirings/virtual-user/index.js +10 -0
- package/dist/wirings/virtual-user/prepare-virtual-user-run.d.ts +54 -0
- package/dist/wirings/virtual-user/prepare-virtual-user-run.js +49 -0
- package/dist/wirings/virtual-user/run-virtual-user.d.ts +92 -0
- package/dist/wirings/virtual-user/run-virtual-user.js +478 -0
- package/dist/wirings/virtual-user/virtual-user-agents.d.ts +38 -0
- package/dist/wirings/virtual-user/virtual-user-agents.js +24 -0
- package/dist/wirings/virtual-user/virtual-user-catalogue.d.ts +92 -0
- package/dist/wirings/virtual-user/virtual-user-catalogue.js +134 -0
- package/dist/wirings/virtual-user/virtual-user-derive.d.ts +26 -0
- package/dist/wirings/virtual-user/virtual-user-derive.js +137 -0
- package/dist/wirings/virtual-user/virtual-user-dispositions.d.ts +79 -0
- package/dist/wirings/virtual-user/virtual-user-dispositions.js +128 -0
- package/dist/wirings/virtual-user/virtual-user-intents.d.ts +78 -0
- package/dist/wirings/virtual-user/virtual-user-intents.js +142 -0
- package/dist/wirings/virtual-user/virtual-user-rng.d.ts +24 -0
- package/dist/wirings/virtual-user/virtual-user-rng.js +44 -0
- package/dist/wirings/virtual-user/virtual-user-run-store.d.ts +90 -0
- package/dist/wirings/virtual-user/virtual-user-run-store.js +1 -0
- package/dist/wirings/virtual-user/virtual-user-target.d.ts +21 -0
- package/dist/wirings/virtual-user/virtual-user-target.js +34 -0
- package/dist/wirings/virtual-user/virtual-user.types.d.ts +199 -0
- package/dist/wirings/virtual-user/virtual-user.types.js +8 -0
- package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +19 -15
- package/dist/wirings/workflow/dsl/workflow-runner.d.ts +0 -4
- package/dist/wirings/workflow/dsl/workflow-runner.js +0 -4
- package/dist/wirings/workflow/feature.d.ts +0 -19
- package/dist/wirings/workflow/feature.js +0 -19
- package/dist/wirings/workflow/graph/graph-node.d.ts +0 -98
- package/dist/wirings/workflow/graph/graph-node.js +0 -34
- package/dist/wirings/workflow/graph/graph-runner.js +6 -41
- package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +0 -4
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +0 -58
- package/dist/wirings/workflow/graph/workflow-graph.types.js +0 -6
- package/dist/wirings/workflow/index.d.ts +5 -7
- package/dist/wirings/workflow/index.js +3 -17
- package/dist/wirings/workflow/pikku-scenario-service.d.ts +87 -5
- package/dist/wirings/workflow/pikku-scenario-service.js +204 -43
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +7 -459
- package/dist/wirings/workflow/pikku-workflow-service.js +58 -551
- package/dist/wirings/workflow/run-timeline.d.ts +0 -47
- package/dist/wirings/workflow/run-timeline.js +0 -22
- package/dist/wirings/workflow/scenario-cookie-jar.d.ts +0 -23
- package/dist/wirings/workflow/scenario-cookie-jar.js +0 -16
- package/dist/wirings/workflow/scenario-poll.d.ts +0 -15
- package/dist/wirings/workflow/scenario-poll.js +0 -12
- package/dist/wirings/workflow/scenario-prose.d.ts +0 -28
- package/dist/wirings/workflow/scenario-prose.js +1 -19
- package/dist/wirings/workflow/scenario-step-guards.d.ts +0 -13
- package/dist/wirings/workflow/scenario-step-guards.js +1 -14
- package/dist/wirings/workflow/scenario-step.types.d.ts +84 -12
- package/dist/wirings/workflow/scenario-step.types.js +5 -1
- package/dist/wirings/workflow/scenario-surface.d.ts +16 -0
- package/dist/wirings/workflow/scenario-surface.js +56 -0
- package/dist/wirings/workflow/workflow-invocation-id.d.ts +0 -18
- package/dist/wirings/workflow/workflow-invocation-id.js +2 -22
- package/dist/wirings/workflow/workflow-queue-workers.d.ts +0 -20
- package/dist/wirings/workflow/workflow-queue-workers.js +0 -19
- package/dist/wirings/workflow/workflow.types.d.ts +5 -195
- package/knowledge/decisions/index.md +19 -0
- package/knowledge/decisions/internals/a-secret-that-fails-to-decrypt-fails-the-whole-read.md +49 -0
- package/knowledge/decisions/internals/a-virtual-user-run-is-not-a-workflow-and-not-a-queued-job.md +48 -0
- package/knowledge/decisions/internals/actor-flow-conversations-seed-a-hidden-kickoff-message.md +23 -0
- package/knowledge/decisions/internals/actor-flow-drives-the-target-through-a-transport-seam.md +24 -0
- package/knowledge/decisions/internals/actor-flow-verdicts-are-llm-self-evaluations.md +25 -0
- package/knowledge/decisions/internals/addon-package-roots-resolve-by-walking-node-module-search-paths.md +26 -0
- package/knowledge/decisions/internals/addon-singleton-services-are-cached-per-namespace-not-per-package.md +33 -0
- package/knowledge/decisions/internals/addon-workflow-names-are-prefixed-with-the-consumer-namespace.md +28 -0
- package/knowledge/decisions/internals/ai-agent-agui-bridge-obeys-the-client-ordering-contract.md +29 -0
- package/knowledge/decisions/internals/ai-agent-audio-chunks-carry-the-format-the-provider-returned.md +20 -0
- package/knowledge/decisions/internals/ai-agent-credential-suspensions-hide-the-tool-result.md +26 -0
- package/knowledge/decisions/internals/ai-agent-delegate-and-supervise-hide-different-text.md +26 -0
- package/knowledge/decisions/internals/ai-agent-llm-tool-arguments-have-nulls-stripped.md +23 -0
- package/knowledge/decisions/internals/ai-agent-model-config-stays-a-single-resolution-seam.md +25 -0
- package/knowledge/decisions/internals/ai-agent-onerror-hooks-cannot-change-the-failure.md +22 -0
- package/knowledge/decisions/internals/ai-agent-runner-methods-must-keep-their-receiver.md +22 -0
- package/knowledge/decisions/internals/ai-agent-stream-persistence-is-best-effort.md +27 -0
- package/knowledge/decisions/internals/ai-agent-sub-agents-inherit-the-parent-context-block.md +26 -0
- package/knowledge/decisions/internals/ai-agent-tool-execute-failures-are-logged-unconditionally.md +25 -0
- package/knowledge/decisions/internals/ai-agent-voice-input-transcribes-audio-parts-in-place.md +22 -0
- package/knowledge/decisions/internals/ai-agent-working-memory-is-persisted-only-when-valid.md +25 -0
- package/knowledge/decisions/internals/channel-message-handlers-accept-three-config-shapes.md +30 -0
- package/knowledge/decisions/internals/channel-middleware-caches-only-statically-resolved-middleware.md +31 -0
- package/knowledge/decisions/internals/channel-state-is-per-socket-session-state-is-per-user.md +29 -0
- package/knowledge/decisions/internals/channel-user-id-is-persisted-after-onconnect-middleware-runs.md +28 -0
- package/knowledge/decisions/internals/cli-option-names-are-camelcase-in-state-and-kebab-on-the-command-line.md +27 -0
- package/knowledge/decisions/internals/cli-parse-errors-are-routed-by-message-prefix.md +28 -0
- package/knowledge/decisions/internals/cli-stdout-is-reserved-for-machine-readable-output.md +34 -0
- package/knowledge/decisions/internals/cli-unknown-long-options-warn-instead-of-failing.md +29 -0
- package/knowledge/decisions/internals/core-column-form-is-an-axis-of-its-own.md +84 -0
- package/knowledge/decisions/internals/core-data-classification-brand-is-an-optional-property.md +41 -0
- package/knowledge/decisions/internals/core-function-runner-restores-the-wire-fields-it-overwrites.md +44 -0
- package/knowledge/decisions/internals/core-hot-reload-merges-generated-meta-never-replaces-it.md +39 -0
- package/knowledge/decisions/internals/core-hot-reload-owns-its-module-registry.md +42 -0
- package/knowledge/decisions/internals/core-middleware-order-is-scope-then-priority.md +39 -0
- package/knowledge/decisions/internals/core-schema-defaults-apply-on-every-transport.md +43 -0
- package/knowledge/decisions/internals/core-scopes-are-an-and-gate-separate-from-permissions.md +38 -0
- package/knowledge/decisions/internals/core-state-is-a-global-map-written-only-at-registration-time.md +44 -0
- package/knowledge/decisions/internals/email-meta-is-read-uncached-because-codegen-rewrites-it-mid-session.md +27 -0
- package/knowledge/decisions/internals/gateway-adapters-resolve-lazily-and-are-promise-cached.md +32 -0
- package/knowledge/decisions/internals/gateway-webhook-challenges-echo-bytes-not-json.md +28 -0
- package/knowledge/decisions/internals/gateway-wiring-is-a-meta-wiring-over-http-and-channels.md +31 -0
- package/knowledge/decisions/internals/generated-src-paths-in-pikku-meta-are-absolute.md +26 -0
- package/knowledge/decisions/internals/http-request-bodies-are-read-once-and-shared.md +32 -0
- package/knowledge/decisions/internals/http-route-groups-cascade-config-in-a-fixed-order.md +28 -0
- package/knowledge/decisions/internals/http-router-matches-normalized-paths-but-returns-registered-ones.md +30 -0
- package/knowledge/decisions/internals/http-runner-logs-through-a-trace-scoped-logger-functions-do-not.md +26 -0
- package/knowledge/decisions/internals/http-set-cookie-headers-are-appended-never-joined.md +28 -0
- package/knowledge/decisions/internals/http-sse-streams-flush-headers-only-after-middleware.md +32 -0
- package/knowledge/decisions/internals/http-wiring-without-metadata-is-skipped-not-fatal.md +26 -0
- package/knowledge/decisions/internals/in-a-scenario-a-4xx-is-data-not-an-exception.md +25 -0
- package/knowledge/decisions/internals/in-memory-workflow-history-aliases-the-live-step-object.md +26 -0
- package/knowledge/decisions/internals/index.md +117 -0
- package/knowledge/decisions/internals/istanbul-statement-counts-attach-to-the-start-line-only.md +25 -0
- package/knowledge/decisions/internals/local-trigger-and-gateway-services-assume-a-single-process.md +26 -0
- package/knowledge/decisions/internals/node-only-builtins-are-imported-dynamically.md +24 -0
- package/knowledge/decisions/internals/one-project-shape-check-two-validators.md +53 -0
- package/knowledge/decisions/internals/queue-group-concurrency-keeps-one-shared-queue-fair.md +28 -0
- package/knowledge/decisions/internals/queue-jobs-always-carry-an-explicit-attempts-count.md +27 -0
- package/knowledge/decisions/internals/remote-addons-dispatch-over-http-instead-of-local-meta.md +31 -0
- package/knowledge/decisions/internals/rpc-names-resolve-through-package-scope-before-root.md +32 -0
- package/knowledge/decisions/internals/scenario-agent-calls-sign-in-on-401-only.md +27 -0
- package/knowledge/decisions/internals/scenario-meta-lives-apart-from-app-meta-but-merges-when-read-off-disk.md +26 -0
- package/knowledge/decisions/internals/scenario-steps-return-drained-response-records.md +27 -0
- package/knowledge/decisions/internals/scenarios-live-in-files-named-for-them.md +48 -0
- package/knowledge/decisions/internals/scope-roots-may-be-co-declared-by-an-addon-and-its-host-app.md +30 -0
- package/knowledge/decisions/internals/serverless-channel-disconnect-must-tolerate-a-missing-channel.md +28 -0
- package/knowledge/decisions/internals/the-dev-queue-copies-prod-timing-and-serialization-semantics.md +30 -0
- package/knowledge/decisions/internals/the-embedding-model-is-pinned-per-service-and-doc-query-embedding-is-split.md +29 -0
- package/knowledge/decisions/internals/the-in-memory-workflow-service-is-inline-only-and-single-process.md +27 -0
- package/knowledge/decisions/internals/the-kek-salt-is-scoped-to-the-key-version.md +40 -0
- package/knowledge/decisions/internals/the-schema-service-is-never-stubbed.md +26 -0
- package/knowledge/decisions/internals/trigger-declaration-is-split-from-trigger-source.md +33 -0
- package/knowledge/decisions/internals/typed-secret-service-caches-for-the-process-lifetime.md +26 -0
- package/knowledge/decisions/internals/validate-checks-personas-through-a-shared-module.md +43 -0
- package/knowledge/decisions/internals/webhook-delivery-history-records-every-attempt-best-effort.md +26 -0
- package/knowledge/decisions/internals/webhook-service-collaborators-are-constructor-args-not-locator-lookups.md +25 -0
- package/knowledge/decisions/internals/whether-a-run-is-inline-is-read-from-the-run-record.md +58 -0
- package/knowledge/decisions/internals/workflow-approval-expiry-is-decided-from-a-recorded-deadline.md +34 -0
- package/knowledge/decisions/internals/workflow-core-never-imports-a-browser-driver.md +42 -0
- package/knowledge/decisions/internals/workflow-dsl-meta-separates-runtime-expressions-from-literals.md +38 -0
- package/knowledge/decisions/internals/workflow-features-resolve-scenarios-by-object-identity.md +29 -0
- package/knowledge/decisions/internals/workflow-graph-inline-and-queued-runs-share-one-planner.md +42 -0
- package/knowledge/decisions/internals/workflow-graph-node-notes-are-excluded-from-the-graph-hash.md +25 -0
- package/knowledge/decisions/internals/workflow-inline-runs-report-their-run-id-before-they-can-fail.md +29 -0
- package/knowledge/decisions/internals/workflow-invocation-id-is-the-dedupe-key-not-step-id.md +43 -0
- package/knowledge/decisions/internals/workflow-queued-step-dispatch-requires-an-explicit-opt-in.md +29 -0
- package/knowledge/decisions/internals/workflow-queues-are-per-workflow-by-default.md +42 -0
- package/knowledge/decisions/internals/workflow-repeated-step-names-get-an-ordinal-suffix.md +33 -0
- package/knowledge/decisions/internals/workflow-replay-reads-its-steps-once-and-caches-only-the-immutable-half.md +32 -0
- package/knowledge/decisions/internals/workflow-retries-are-owned-by-the-workflow-not-the-queue.md +31 -0
- package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md +39 -0
- package/knowledge/decisions/internals/workflow-run-mirror-is-never-a-source-of-truth.md +29 -0
- package/knowledge/decisions/internals/workflow-run-polling-backs-off-to-the-callers-ceiling.md +33 -0
- package/knowledge/decisions/internals/workflow-run-timeline-is-a-pure-fold-over-durable-history.md +37 -0
- package/knowledge/decisions/internals/workflow-scenario-assertions-never-retry-and-record-one-step.md +50 -0
- package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md +43 -0
- package/knowledge/decisions/internals/workflow-scenario-prose-is-rendered-from-typed-calls-not-parsed-from-english.md +32 -0
- package/knowledge/decisions/internals/workflow-scenario-quarantine-reason-lives-in-code.md +18 -0
- package/knowledge/decisions/internals/workflow-scenario-step-targets-are-string-literals-for-the-inspector.md +34 -0
- package/knowledge/decisions/internals/workflow-step-compensation-runs-as-its-own-durable-step.md +26 -0
- package/knowledge/decisions/internals/workflow-step-dispatch-failure-is-transient-not-a-run-failure.md +33 -0
- package/knowledge/decisions/internals/workflow-step-lock-is-held-only-to-claim-the-step.md +27 -0
- package/knowledge/decisions/internals/workflow-step-rpc-name-is-provenance-only.md +34 -0
- package/knowledge/decisions/internals/workflow-suspend-and-approval-reasons-are-durable-step-identities.md +38 -0
- package/knowledge/decisions/internals/workflow-suspended-runs-keep-their-in-process-context.md +30 -0
- package/knowledge/decisions/security/a-dropped-audit-write-is-always-logged.md +26 -0
- package/knowledge/decisions/security/actor-flow-missing-approval-decisions-default-to-denied.md +22 -0
- package/knowledge/decisions/security/actor-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md +27 -0
- package/knowledge/decisions/security/actor-sign-in-only-works-for-actor-flagged-users.md +27 -0
- package/knowledge/decisions/security/addon-auth-and-tags-only-tighten.md +43 -0
- package/knowledge/decisions/security/addon-config-gates-apply-only-at-the-namespaced-rpc-boundary.md +52 -0
- package/knowledge/decisions/security/addon-scopes-are-resolved-where-the-function-runs.md +46 -0
- package/knowledge/decisions/security/ai-agent-approval-forwarding-requires-a-symbol-brand.md +27 -0
- package/knowledge/decisions/security/ai-agent-credential-requests-are-symbol-branded.md +37 -0
- package/knowledge/decisions/security/ai-agent-gate-requires-a-session-only-when-auth-is-true.md +31 -0
- package/knowledge/decisions/security/ai-agent-ownership-failures-never-echo-the-resource.md +23 -0
- package/knowledge/decisions/security/ai-agent-resume-re-runs-the-authorization-gate.md +22 -0
- package/knowledge/decisions/security/ai-agent-sessionless-deployments-have-no-thread-ownership.md +39 -0
- package/knowledge/decisions/security/ai-agent-thread-ownership-composes-the-session-principal.md +30 -0
- package/knowledge/decisions/security/ai-agent-tool-filtering-reads-the-live-function-config.md +24 -0
- package/knowledge/decisions/security/an-empty-owners-constraint-matches-nothing.md +30 -0
- package/knowledge/decisions/security/an-exposed-ungated-function-is-a-codegen-warning.md +49 -0
- package/knowledge/decisions/security/console-addon-privileged-functions-gate-themselves.md +76 -0
- package/knowledge/decisions/security/core-safe-fetch-blocks-ssrf-by-host-literal-not-dns.md +39 -0
- package/knowledge/decisions/security/core-secrets-use-a-per-secret-dek-wrapped-by-a-kek.md +37 -0
- package/knowledge/decisions/security/gateway-handlers-run-through-the-function-runner-gate.md +31 -0
- package/knowledge/decisions/security/gateway-middleware-sessions-must-be-bridged-onto-the-wire.md +30 -0
- package/knowledge/decisions/security/global-permissions-and-function-permissions-are-independent-gates.md +40 -0
- package/knowledge/decisions/security/http-error-detail-is-withheld-from-clients-in-production.md +33 -0
- package/knowledge/decisions/security/http-request-bodies-are-bounded-before-they-are-buffered.md +46 -0
- package/knowledge/decisions/security/index.md +55 -0
- package/knowledge/decisions/security/mcp-internal-error-details-are-double-gated-on-production.md +27 -0
- package/knowledge/decisions/security/passphrases-are-stretched-key-material-is-expanded.md +40 -0
- package/knowledge/decisions/security/permission-auth-filtering-requires-live-permission-functions.md +31 -0
- package/knowledge/decisions/security/pikku-carries-actor-scopes-as-data-and-the-app-grants-them.md +26 -0
- package/knowledge/decisions/security/queue-job-identities-are-signed-at-enqueue.md +69 -0
- package/knowledge/decisions/security/queue-jobs-carry-the-producers-pikku-user-id.md +39 -0
- package/knowledge/decisions/security/remote-addon-tokens-are-client-credentials-not-mesh-trust.md +34 -0
- package/knowledge/decisions/security/scaffold-features-are-authenticated-unless-opted-out.md +49 -0
- package/knowledge/decisions/security/scenario-step-functions-are-never-externally-invocable.md +30 -0
- package/knowledge/decisions/security/scope-resolution-happens-at-the-session-boundary-and-sync-never-deletes.md +28 -0
- package/knowledge/decisions/security/self-authentication-is-declared-not-detected.md +34 -0
- package/knowledge/decisions/security/signed-content-urls-bind-the-request-path.md +37 -0
- package/knowledge/decisions/security/webhook-bodies-are-signed-before-they-are-enqueued.md +25 -0
- package/knowledge/decisions/security/workflow-actor-steps-always-use-the-real-transport.md +34 -0
- package/knowledge/decisions/security/workflow-approval-payloads-are-validated-on-replay-inside-the-workflow.md +40 -0
- package/knowledge/decisions/security/workflow-queued-steps-rehydrate-their-session-from-the-run-wire.md +32 -0
- package/knowledge/decisions/security/workflow-scenario-sessions-are-isolated-per-actor-and-per-scenario.md +32 -0
- package/knowledge/decisions/security/workflow-scenario-steps-are-never-network-invocable.md +31 -0
- package/knowledge/index.md +24 -0
- package/knowledge/questions/index.md +15 -0
- package/package.json +6 -2
- package/run-tests.sh +0 -0
- package/src/column-form.test.ts +97 -0
- package/src/column-form.ts +58 -0
- package/src/crypto-utils.test.ts +460 -19
- package/src/crypto-utils.ts +306 -59
- package/src/data-classification.ts +45 -7
- package/src/dev/hot-reload.test.ts +0 -4
- package/src/dev/hot-reload.ts +11 -30
- package/src/dev/module-runner.ts +7 -32
- package/src/dev/reload-meta.ts +9 -29
- package/src/errors/error-handler.ts +20 -35
- package/src/errors/error.test.ts +30 -1
- package/src/errors/errors.ts +73 -157
- package/src/function/abort-scope.test.ts +97 -0
- package/src/function/abort-scope.ts +80 -0
- package/src/function/function-runner.test.ts +0 -7
- package/src/function/function-runner.ts +62 -32
- package/src/function/functions.types.ts +95 -138
- package/src/function/index.ts +1 -0
- package/src/function/list.types.test.ts +3 -25
- package/src/function/list.types.ts +12 -62
- package/src/handle-error.ts +0 -18
- package/src/index.ts +84 -3
- package/src/middleware/auth-apikey.test.ts +0 -1
- package/src/middleware/auth-apikey.ts +0 -17
- package/src/middleware/auth-bearer.test.ts +3 -5
- package/src/middleware/auth-bearer.ts +5 -41
- package/src/middleware/auth-cookie.test.ts +0 -6
- package/src/middleware/auth-cookie.ts +2 -26
- package/src/middleware/cors.test.ts +34 -0
- package/src/middleware/cors.ts +12 -33
- package/src/middleware/remote-auth.test.ts +26 -10
- package/src/middleware/remote-auth.ts +11 -3
- package/src/middleware/telemetry.ts +2 -31
- package/src/middleware-runner.test.ts +0 -2
- package/src/middleware-runner.ts +5 -74
- package/src/permissions.test.ts +30 -0
- package/src/permissions.ts +24 -74
- package/src/pikku-request.ts +0 -6
- package/src/pikku-state.ts +2 -30
- package/src/production-barrels-stay-lean.test.ts +110 -0
- package/src/remote.test.ts +173 -0
- package/src/remote.ts +18 -8
- package/src/schema.ts +5 -39
- package/src/scopes.ts +7 -48
- package/src/secret-value.test.ts +204 -0
- package/src/secret-value.ts +111 -0
- package/src/services/ai-agent-runner-service.ts +20 -0
- package/src/services/ai-embedding-service.ts +3 -25
- package/src/services/audit-service.ts +88 -11
- package/src/services/content-service.ts +1 -46
- package/src/services/credential-service.ts +3 -40
- package/src/services/credential-wire-service.test.ts +0 -2
- package/src/services/credential-wire-service.ts +9 -1
- package/src/services/deployment-service.ts +3 -9
- package/src/services/email-service.ts +3 -1
- package/src/services/gateway-service.ts +0 -15
- package/src/services/{http-scenario-actors-converse.test.ts → http-personas-converse.test.ts} +38 -9
- package/src/services/{http-scenario-actors.test.ts → http-personas.test.ts} +39 -22
- package/src/services/{http-scenario-actors.ts → http-personas.ts} +85 -45
- package/src/services/in-memory-queue-service.ts +1 -15
- package/src/services/in-memory-trigger-service.ts +1 -18
- package/src/services/in-memory-workflow-service.test.ts +0 -13
- package/src/services/in-memory-workflow-service.ts +4 -38
- package/src/services/index.ts +23 -18
- package/src/services/istanbul-coverage-service.ts +2 -8
- package/src/services/jwt-service.ts +1 -16
- package/src/services/local-content-request-handler.test.ts +202 -0
- package/src/services/local-content-request-handler.ts +267 -0
- package/src/services/local-content.test.ts +159 -27
- package/src/services/local-content.ts +55 -23
- package/src/services/local-gateway-service.ts +2 -17
- package/src/services/local-secrets.test.ts +20 -5
- package/src/services/local-secrets.ts +15 -11
- package/src/services/logger-console.test.ts +0 -1
- package/src/services/logger-console.ts +3 -7
- package/src/services/logger.ts +31 -46
- package/src/services/meta-service.test.ts +1 -5
- package/src/services/meta-service.ts +41 -61
- package/src/services/{scenario-actors-service.ts → personas-service.ts} +48 -43
- package/src/services/pikku-user-id.ts +0 -4
- package/src/services/queue-webhook-service.test.ts +2 -1
- package/src/services/queue-webhook-service.ts +10 -42
- package/src/services/scheduler-service.ts +1 -50
- package/src/services/schema-service.ts +1 -24
- package/src/services/scope-service.ts +50 -34
- package/src/services/scoped-secret-service.ts +4 -7
- package/src/services/secret-host-binding.test.ts +138 -0
- package/src/services/secret-host-binding.ts +51 -0
- package/src/services/secret-service.ts +12 -35
- package/src/services/secretless.test.ts +54 -0
- package/src/services/secretless.ts +29 -0
- package/src/services/stub-tracker.ts +8 -18
- package/src/services/system-role-guard.test.ts +93 -0
- package/src/services/system-role-guard.ts +71 -0
- package/src/services/trigger-service.ts +0 -12
- package/src/services/typed-secret-service.ts +12 -14
- package/src/services/v8-coverage-service.ts +3 -6
- package/src/services/variables-service.ts +1 -8
- package/src/services/webhook-service.ts +23 -64
- package/src/services/workflow-service.ts +3 -20
- package/src/testing/service-tests.ts +6 -32
- package/src/time-utils.ts +1 -19
- package/src/types/core.types.ts +137 -229
- package/src/types/state.types.ts +7 -9
- package/src/utils/hmac.ts +4 -10
- package/src/utils/safe-fetch.ts +13 -54
- package/src/utils.test.ts +11 -2
- package/src/utils.ts +6 -15
- package/src/wirings/actor-flow/actor-flow.types.ts +1 -34
- package/src/wirings/actor-flow/index.ts +0 -9
- package/src/wirings/actor-flow/run-conversation.test.ts +11 -6
- package/src/wirings/actor-flow/run-conversation.ts +19 -12
- package/src/wirings/ai-agent/ai-agent-agui.test.ts +91 -10
- package/src/wirings/ai-agent/ai-agent-agui.ts +49 -17
- package/src/wirings/ai-agent/ai-agent-helpers.ts +20 -0
- package/src/wirings/ai-agent/ai-agent-interrupt.test.ts +842 -0
- package/src/wirings/ai-agent/ai-agent-interrupt.ts +399 -0
- package/src/wirings/ai-agent/ai-agent-memory.ts +0 -2
- package/src/wirings/ai-agent/ai-agent-model-config.ts +1 -9
- package/src/wirings/ai-agent/ai-agent-prepare.test.ts +202 -31
- package/src/wirings/ai-agent/ai-agent-prepare.ts +89 -139
- package/src/wirings/ai-agent/ai-agent-registry.test.ts +191 -6
- package/src/wirings/ai-agent/ai-agent-registry.ts +18 -1
- package/src/wirings/ai-agent/ai-agent-resume-authorization.test.ts +0 -2
- package/src/wirings/ai-agent/ai-agent-runner.test.ts +11 -9
- package/src/wirings/ai-agent/ai-agent-runner.ts +85 -35
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +205 -103
- package/src/wirings/ai-agent/ai-agent-stream.ts +224 -76
- package/src/wirings/ai-agent/ai-agent-thread-ownership.test.ts +301 -0
- package/src/wirings/ai-agent/ai-agent.types.ts +130 -5
- package/src/wirings/ai-agent/index.ts +37 -3
- package/src/wirings/ai-agent/voice-input.test.ts +137 -7
- package/src/wirings/ai-agent/voice-input.ts +96 -12
- package/src/wirings/ai-agent/voice-output.test.ts +512 -0
- package/src/wirings/ai-agent/voice-output.ts +243 -56
- package/src/wirings/channel/channel-common.ts +15 -20
- package/src/wirings/channel/channel-handler.test.ts +50 -0
- package/src/wirings/channel/channel-handler.ts +32 -11
- package/src/wirings/channel/channel-host-rpc.test.ts +150 -0
- package/src/wirings/channel/channel-host-rpc.ts +69 -0
- package/src/wirings/channel/channel-middleware-runner.test.ts +0 -1
- package/src/wirings/channel/channel-middleware-runner.ts +0 -12
- package/src/wirings/channel/channel-rpc-registry.ts +116 -0
- package/src/wirings/channel/channel-rpc-responder.ts +117 -0
- package/src/wirings/channel/channel-rpc-service.ts +146 -0
- package/src/wirings/channel/channel-rpc-validators.ts +65 -0
- package/src/wirings/channel/channel-rpc.test.ts +820 -0
- package/src/wirings/channel/channel-rpc.ts +5 -0
- package/src/wirings/channel/channel-rpc.types.ts +150 -0
- package/src/wirings/channel/channel-runner.ts +0 -14
- package/src/wirings/channel/channel-store.ts +0 -10
- package/src/wirings/channel/channel.types.ts +19 -8
- package/src/wirings/channel/define-channel-routes.ts +0 -20
- package/src/wirings/channel/eventhub-service.ts +0 -18
- package/src/wirings/channel/index.ts +35 -0
- package/src/wirings/channel/local/local-channel-handler.ts +3 -1
- package/src/wirings/channel/local/local-channel-runner.test.ts +0 -10
- package/src/wirings/channel/local/local-channel-runner.ts +3 -1
- package/src/wirings/channel/local/local-eventhub-service.test.ts +0 -13
- package/src/wirings/channel/local/local-eventhub-service.ts +2 -37
- package/src/wirings/channel/log-channels.ts +0 -4
- package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +83 -2
- package/src/wirings/channel/pikku-abstract-channel-handler.ts +7 -0
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +2 -5
- package/src/wirings/cli/channel/cli-approval.test.ts +177 -0
- package/src/wirings/cli/channel/cli-approval.ts +135 -0
- package/src/wirings/cli/channel/cli-channel-runner.ts +4 -26
- package/src/wirings/cli/channel/cli-raw-channel-runner.test.ts +169 -0
- package/src/wirings/cli/channel/cli-raw-channel-runner.ts +59 -16
- package/src/wirings/cli/channel/cli-raw-client-runner.test.ts +480 -0
- package/src/wirings/cli/channel/cli-raw-client-runner.ts +185 -0
- package/src/wirings/cli/channel/index.ts +13 -0
- package/src/wirings/cli/cli-runner.test.ts +0 -1
- package/src/wirings/cli/cli-runner.ts +46 -88
- package/src/wirings/cli/cli.types.ts +14 -3
- package/src/wirings/cli/command-parser.test.ts +0 -4
- package/src/wirings/cli/command-parser.ts +11 -91
- package/src/wirings/cli/define-cli-commands.ts +1 -17
- package/src/wirings/credential/credential.types.ts +0 -12
- package/src/wirings/credential/{wire-credential.ts → define-credential.ts} +7 -7
- package/src/wirings/credential/index.ts +1 -1
- package/src/wirings/credential/validate-credential-definitions.ts +2 -4
- package/src/wirings/gateway/gateway-runner.test.ts +1 -21
- package/src/wirings/gateway/gateway-runner.ts +8 -110
- package/src/wirings/gateway/gateway.types.ts +7 -80
- package/src/wirings/http/http-routes.test.ts +0 -3
- package/src/wirings/http/http-routes.ts +0 -86
- package/src/wirings/http/http-runner.test.ts +0 -1
- package/src/wirings/http/http-runner.ts +8 -167
- package/src/wirings/http/http.types.ts +15 -62
- package/src/wirings/http/log-http-routes.ts +0 -4
- package/src/wirings/http/pikku-fetch-http-request.test.ts +2 -10
- package/src/wirings/http/pikku-fetch-http-request.ts +0 -58
- package/src/wirings/http/pikku-fetch-http-response.test.ts +1 -1
- package/src/wirings/http/pikku-fetch-http-response.ts +0 -3
- package/src/wirings/http/routers/path-to-regex.test.ts +4 -17
- package/src/wirings/http/routers/path-to-regex.ts +2 -13
- package/src/wirings/http/web-request.test.ts +33 -2
- package/src/wirings/http/web-request.ts +30 -17
- package/src/wirings/mcp/mcp-endpoint-registry.test.ts +0 -1
- package/src/wirings/mcp/mcp-runner.ts +2 -17
- package/src/wirings/mcp/mcp.types.ts +7 -42
- package/src/wirings/oauth2/oauth2.types.ts +0 -30
- package/src/wirings/persona/define-personas.ts +33 -0
- package/src/wirings/persona/index.ts +62 -0
- package/src/wirings/persona/persona-email.ts +87 -0
- package/src/wirings/persona/persona-environments.test.ts +183 -0
- package/src/wirings/persona/persona-environments.ts +138 -0
- package/src/wirings/persona/persona-mailbox.ts +156 -0
- package/src/wirings/persona/persona.test.ts +220 -0
- package/src/wirings/persona/persona.types.ts +142 -0
- package/src/wirings/persona/validate-personas.ts +133 -0
- package/src/wirings/queue/index.ts +13 -3
- package/src/wirings/queue/queue-identity.test.ts +454 -0
- package/src/wirings/queue/queue-identity.ts +176 -0
- package/src/wirings/queue/queue-runner.ts +12 -31
- package/src/wirings/queue/queue.types.ts +25 -90
- package/src/wirings/queue/register-queue-helper.ts +0 -14
- package/src/wirings/queue/signed-queue-service.ts +60 -0
- package/src/wirings/queue/validate-worker-config.ts +2 -28
- package/src/wirings/role/define-system-role.ts +33 -0
- package/src/wirings/role/index.ts +13 -0
- package/src/wirings/role/role.test.ts +104 -0
- package/src/wirings/role/role.types.ts +47 -0
- package/src/wirings/role/validate-role-definitions.ts +93 -0
- package/src/wirings/rpc/addon-auth-tags.test.ts +223 -0
- package/src/wirings/rpc/addon-runner.ts +0 -56
- package/src/wirings/rpc/addon-scopes.test.ts +225 -0
- package/src/wirings/rpc/remote-addon-auth.ts +9 -16
- package/src/wirings/rpc/rpc-runner.test.ts +192 -6
- package/src/wirings/rpc/rpc-runner.ts +145 -127
- package/src/wirings/rpc/rpc-types.ts +11 -6
- package/src/wirings/rpc/wire-addon.test.ts +43 -1
- package/src/wirings/rpc/wire-addon.ts +99 -0
- package/src/wirings/rpc/wire-remote-addon.ts +9 -29
- package/src/wirings/scheduler/log-schedulers.ts +0 -4
- package/src/wirings/scheduler/scheduler-runner.test.ts +1 -8
- package/src/wirings/scheduler/scheduler-runner.ts +0 -2
- package/src/wirings/scheduler/scheduler.types.ts +1 -14
- package/src/wirings/scope/{wire-scope.ts → define-scope.ts} +5 -6
- package/src/wirings/scope/index.ts +1 -1
- package/src/wirings/scope/scope.test.ts +1 -2
- package/src/wirings/scope/scope.types.ts +7 -9
- package/src/wirings/scope/validate-scope-definitions.ts +3 -21
- package/src/wirings/secret/index.ts +1 -1
- package/src/wirings/secret/secret.types.ts +19 -15
- package/src/wirings/secret/validate-secret-definitions.ts +2 -4
- package/src/wirings/trigger/trigger-runner.ts +1 -27
- package/src/wirings/trigger/trigger.types.ts +1 -82
- package/src/wirings/variable/index.ts +1 -1
- package/src/wirings/variable/validate-variable-definitions.ts +2 -4
- package/src/wirings/variable/variable.types.ts +1 -13
- package/src/wirings/virtual-user/index.ts +88 -0
- package/src/wirings/virtual-user/prepare-virtual-user-run.test.ts +115 -0
- package/src/wirings/virtual-user/prepare-virtual-user-run.ts +95 -0
- package/src/wirings/virtual-user/run-virtual-user.test.ts +765 -0
- package/src/wirings/virtual-user/run-virtual-user.ts +671 -0
- package/src/wirings/virtual-user/virtual-user-agents.test.ts +65 -0
- package/src/wirings/virtual-user/virtual-user-agents.ts +57 -0
- package/src/wirings/virtual-user/virtual-user-catalogue.test.ts +215 -0
- package/src/wirings/virtual-user/virtual-user-catalogue.ts +184 -0
- package/src/wirings/virtual-user/virtual-user-derive.test.ts +398 -0
- package/src/wirings/virtual-user/virtual-user-derive.ts +173 -0
- package/src/wirings/virtual-user/virtual-user-dispositions.test.ts +63 -0
- package/src/wirings/virtual-user/virtual-user-dispositions.ts +213 -0
- package/src/wirings/virtual-user/virtual-user-intents.test.ts +208 -0
- package/src/wirings/virtual-user/virtual-user-intents.ts +185 -0
- package/src/wirings/virtual-user/virtual-user-rng.test.ts +72 -0
- package/src/wirings/virtual-user/virtual-user-rng.ts +50 -0
- package/src/wirings/virtual-user/virtual-user-run-store.ts +98 -0
- package/src/wirings/virtual-user/virtual-user-target.ts +47 -0
- package/src/wirings/virtual-user/virtual-user.types.ts +219 -0
- package/src/wirings/workflow/dsl/workflow-dsl.types.ts +19 -20
- package/src/wirings/workflow/dsl/workflow-runner.ts +0 -4
- package/src/wirings/workflow/feature.ts +0 -19
- package/src/wirings/workflow/graph/graph-node.ts +0 -136
- package/src/wirings/workflow/graph/graph-runner.test.ts +20 -19
- package/src/wirings/workflow/graph/graph-runner.ts +6 -41
- package/src/wirings/workflow/graph/wire-workflow-graph.ts +0 -4
- package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -58
- package/src/wirings/workflow/index.ts +10 -44
- package/src/wirings/workflow/pikku-scenario-service.ts +235 -61
- package/src/wirings/workflow/pikku-workflow-service.test.ts +0 -39
- package/src/wirings/workflow/pikku-workflow-service.ts +77 -674
- package/src/wirings/workflow/run-timeline.test.ts +7 -19
- package/src/wirings/workflow/run-timeline.ts +0 -56
- package/src/wirings/workflow/scenario-cookie-jar.test.ts +0 -1
- package/src/wirings/workflow/scenario-cookie-jar.ts +0 -25
- package/src/wirings/workflow/scenario-expectations.test.ts +2 -7
- package/src/wirings/workflow/scenario-hooks.test.ts +2 -7
- package/src/wirings/workflow/scenario-poll.test.ts +0 -2
- package/src/wirings/workflow/scenario-poll.ts +0 -15
- package/src/wirings/workflow/scenario-prose.test.ts +5 -7
- package/src/wirings/workflow/scenario-prose.ts +1 -29
- package/src/wirings/workflow/scenario-service.test.ts +2 -10
- package/src/wirings/workflow/scenario-step-guards.ts +1 -14
- package/src/wirings/workflow/scenario-step.test.ts +163 -19
- package/src/wirings/workflow/scenario-step.types.ts +94 -12
- package/src/wirings/workflow/scenario-surface.test.ts +146 -0
- package/src/wirings/workflow/scenario-surface.ts +71 -0
- package/src/wirings/workflow/workflow-dispatch-durability.test.ts +14 -15
- package/src/wirings/workflow/workflow-dispatch-payload.test.ts +0 -4
- package/src/wirings/workflow/workflow-inline-authority.test.ts +169 -0
- package/src/wirings/workflow/workflow-invocation-id.test.ts +0 -2
- package/src/wirings/workflow/workflow-invocation-id.ts +2 -22
- package/src/wirings/workflow/workflow-mirror.test.ts +0 -7
- package/src/wirings/workflow/workflow-on-error.test.ts +0 -9
- package/src/wirings/workflow/workflow-queue-workers.ts +0 -21
- package/src/wirings/workflow/workflow-replay-snapshot.test.ts +8 -7
- package/src/wirings/workflow/workflow-retry-policy.test.ts +0 -5
- package/src/wirings/workflow/workflow-run-context.test.ts +5 -10
- package/src/wirings/workflow/workflow-run-polling.test.ts +0 -5
- package/src/wirings/workflow/workflow-step-ordinal.test.ts +19 -4
- package/src/wirings/workflow/workflow-step-session.test.ts +0 -7
- package/src/wirings/workflow/workflow.types.ts +5 -201
- package/tsconfig.tsbuildinfo +1 -1
- package/tsconfig.type-tests.json +12 -0
- package/src/middleware/timeout.ts +0 -22
- package/src/pikku-response.ts +0 -5
- package/src/wirings/mcp/mcp-endpoint-registry.test.d.ts +0 -1
- package/src/wirings/workflow/dsl/index.ts +0 -36
- package/src/wirings/workflow/graph/index.ts +0 -15
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Core declares the scenario browser surface structurally and never imports a driver
|
|
4
|
+
description: `@pikku/core` must stay dependency-free for edge runtimes, so playwright augments the interface instead of being imported by it
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Core declares the scenario browser surface structurally and never imports a driver
|
|
9
|
+
|
|
10
|
+
`PikkuBrowserWire`, `TestIdSelector`, `ScenarioBrowserProvider` and
|
|
11
|
+
`ScenarioBrowserFailure` all live in `scenario-step.types.ts` as plain
|
|
12
|
+
structural types. `@pikku/core` deliberately never imports playwright — it has
|
|
13
|
+
to stay dependency-free for edge runtimes — so `@pikku/playwright` augments
|
|
14
|
+
`PikkuBrowserWire` via `declare module`, and `wire.browser.page` becomes a fully
|
|
15
|
+
typed Playwright `Page` only in a project that installs it. Declaring the
|
|
16
|
+
provider contract here is also what lets the CLI depend on core alone.
|
|
17
|
+
|
|
18
|
+
`reset` and `captureFailure` are optional on `ScenarioBrowserProvider` so a
|
|
19
|
+
driver written against an earlier version keeps compiling; the runner treats a
|
|
20
|
+
driver without them as one offering no isolation and no diagnostics.
|
|
21
|
+
`captureFailure` must never throw — a failure to capture must not replace the
|
|
22
|
+
failure being captured — and exists because a browser step fails with a selector
|
|
23
|
+
timeout that says nothing about *why* the page never rendered; the answer is
|
|
24
|
+
almost always in the page's own console and request errors, which the driver has
|
|
25
|
+
been collecting all along.
|
|
26
|
+
|
|
27
|
+
`TestIdSelector` is richer than a bare `data-testid` because one rarely names
|
|
28
|
+
exactly one element: `where` matches the element's own data attributes (so a
|
|
29
|
+
step asserts a status without reading translated copy back to the app), `prefix`
|
|
30
|
+
matches a family of ids, `containing` picks the match holding a piece of text,
|
|
31
|
+
and `within` scopes the lookup to one row or section. Core defines the shape;
|
|
32
|
+
the driver resolves it against a real page.
|
|
33
|
+
|
|
34
|
+
The same dependency discipline applies at runtime: `resolveScenarioActors` in
|
|
35
|
+
`pikku-scenario-service.ts` imports the HTTP actor client lazily, so even a
|
|
36
|
+
runner bundle only pays for the AI persona conversation loop when a scenario
|
|
37
|
+
actually signs an actor in.
|
|
38
|
+
|
|
39
|
+
**What this rules out:** importing playwright (or any driver) from core,
|
|
40
|
+
tightening `reset`/`captureFailure` to required, letting `captureFailure` throw,
|
|
41
|
+
reducing `TestIdSelector` to a plain string, or making the actor-client import
|
|
42
|
+
static.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Workflow DSL meta keeps runtime expressions in their own field, apart from literal values
|
|
4
|
+
description: A string `value` regenerates as a string literal; an `expression` regenerates as code, so the two can never share a field
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Workflow DSL meta keeps runtime expressions in their own field, apart from literal values
|
|
9
|
+
|
|
10
|
+
Several step metas in `dsl/workflow-dsl.types.ts` carry a literal field and a
|
|
11
|
+
parallel `expression` field: `SetStepMeta` has `value` and `expression`
|
|
12
|
+
(`count + 1`), `SleepStepMeta` has `duration` and `expression` (a duration known
|
|
13
|
+
only at runtime, e.g. a loop variable). They are mutually exclusive by
|
|
14
|
+
construction because regenerated code has to emit them differently — a string
|
|
15
|
+
`value` becomes a string literal, an `expression` becomes raw code. Collapsing
|
|
16
|
+
them would make every computed assignment regenerate as a quoted string.
|
|
17
|
+
|
|
18
|
+
Two related shapes exist for the same "the extractor cannot see this
|
|
19
|
+
statically" reason. `ReturnStepMeta.spread` records variables spread into a
|
|
20
|
+
returned object (`return { ...r }`) or a sole returned variable (`return r`) by
|
|
21
|
+
name, because their fields are not enumerable statically and cannot be expanded
|
|
22
|
+
into `outputs`. `FeatureMeta.unresolvedEntries` counts feature entries that
|
|
23
|
+
could not be read statically (a spread, a `.map()`), so a non-zero count marks
|
|
24
|
+
the listing as partial rather than pretending it is complete.
|
|
25
|
+
|
|
26
|
+
`FanoutStepMeta.stepName` is optional for a different structural reason: a
|
|
27
|
+
fanout is not itself a cached step, and node ids are step names — borrowing a
|
|
28
|
+
body step's name would give the loop and that step the same id, collapsing one
|
|
29
|
+
onto the other.
|
|
30
|
+
|
|
31
|
+
Free-text documentation (`GraphNodeConfig.notes`,
|
|
32
|
+
`PikkuWorkflowGraphConfig.notes`) is excluded from the graph topology hash, so
|
|
33
|
+
editing a note never marks the workflow as changed and never triggers a version
|
|
34
|
+
mismatch on in-flight runs.
|
|
35
|
+
|
|
36
|
+
**What this rules out:** merging `expression` into `value`/`duration`, expanding
|
|
37
|
+
`spread` into concrete `outputs`, giving a fanout a required `stepName` taken
|
|
38
|
+
from its body, and folding `notes` into `graphHash`.
|
package/knowledge/decisions/internals/workflow-features-resolve-scenarios-by-object-identity.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: A feature resolves its scenarios by object identity, never by name or shape
|
|
4
|
+
description: An unregistered scenario comes back explicitly unresolved rather than silently running as something else
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# A feature resolves its scenarios by object identity, never by name or shape
|
|
9
|
+
|
|
10
|
+
`resolveFeatureScenarios` in `feature.ts` builds a `Map` keyed by the registered
|
|
11
|
+
config object itself and looks each feature entry up in it. `pikkuScenario`
|
|
12
|
+
returns its config verbatim and `addWorkflow` registers that same object, so a
|
|
13
|
+
feature holding the imported identifier holds the very object that was
|
|
14
|
+
registered. Nothing is matched by shape, by name, or by any other guess.
|
|
15
|
+
|
|
16
|
+
That is also why a scenario built inline inside a feature — and therefore never
|
|
17
|
+
registered — comes back in `unresolved` rather than silently running as
|
|
18
|
+
something else. Because scenarios are referenced by imported identifier, a
|
|
19
|
+
renamed or deleted scenario is a compile error rather than a silent skip.
|
|
20
|
+
|
|
21
|
+
Entries are returned in declaration order and features in registration order,
|
|
22
|
+
since a feature's reading order is its declaration order. A scenario's effective
|
|
23
|
+
tags are its own unioned with the containing feature's, so a tag filter selects
|
|
24
|
+
through the feature.
|
|
25
|
+
|
|
26
|
+
**What this rules out:** falling back to name matching when identity lookup
|
|
27
|
+
misses, structurally comparing configs, or dropping unresolved entries silently
|
|
28
|
+
instead of reporting them — each turns "this scenario is not registered" into
|
|
29
|
+
"some other scenario ran instead".
|
package/knowledge/decisions/internals/workflow-graph-inline-and-queued-runs-share-one-planner.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Inline and queued workflow graph runs share one transition planner
|
|
4
|
+
description: A second, weaker inline traversal would lose joins, cycle revisits and step provenance that the queued path has
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Inline and queued workflow graph runs share one transition planner
|
|
9
|
+
|
|
10
|
+
`planGraphTransitions` in `graph/graph-runner.ts` is the single place that
|
|
11
|
+
decides which nodes fire next. `continueGraph` (queued) and
|
|
12
|
+
`continueGraphInline` (in-process loop) both call it; they differ only in
|
|
13
|
+
whether the planned wave is dispatched via `queueGraphNode` or executed by
|
|
14
|
+
`executeGraphNodeInline`. Sharing the planner is what gives the inline path
|
|
15
|
+
joins, cycle revisits and `fromStepName` provenance identical to the queue,
|
|
16
|
+
instead of a second and weaker traversal. `executeGraphNodeInline` persists
|
|
17
|
+
under the same physical instance key and records the same predecessor as
|
|
18
|
+
`queueGraphNode` for the same reason.
|
|
19
|
+
|
|
20
|
+
The planner distinguishes two kinds of edge. A forward edge is node-once: the
|
|
21
|
+
target fires only if it has no instance yet, so converging edges (joins)
|
|
22
|
+
collapse to a single run. A back-edge — one whose target can reach the source,
|
|
23
|
+
detected by `closesCycle` — is a revisit: it fires a fresh ordinal instance
|
|
24
|
+
(`target#1`, …) and is edge-once on `from → target` so it does not re-fire every
|
|
25
|
+
tick. Cycles terminate when branch routing stops looping back, and every
|
|
26
|
+
instance records the predecessor it was reached from.
|
|
27
|
+
|
|
28
|
+
`remapStepNamesToNodeIds` and `remapBranchKeys` are called on the completed and
|
|
29
|
+
branch sets even where their results are discarded: planning keys steps
|
|
30
|
+
physically, so those calls exist only to surface an ambiguous template-node
|
|
31
|
+
config as an error.
|
|
32
|
+
|
|
33
|
+
On the queued path a node that sets no `retries` falls back to
|
|
34
|
+
`DEFAULT_STEP_RETRIES` rather than to zero, so the persisted step's retry count
|
|
35
|
+
matches the queue job's `attempts` (see `resolveStepJobOptions`). A step row
|
|
36
|
+
claiming one attempt while the queue silently delivers five is the kind of
|
|
37
|
+
disagreement that makes a retry bug unreadable from the outside.
|
|
38
|
+
|
|
39
|
+
**What this rules out:** writing a separate traversal for the inline path,
|
|
40
|
+
making forward edges fire per-edge (which breaks joins) or back-edges fire
|
|
41
|
+
node-once (which breaks loops), dropping `fromStepName` from either path, and
|
|
42
|
+
deleting the "unused" remap calls as dead code.
|
package/knowledge/decisions/internals/workflow-graph-node-notes-are-excluded-from-the-graph-hash.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Workflow graph node notes are non-semantic and excluded from the graph hash
|
|
4
|
+
description: Documentation on a node must not count as a topology change, or editing a comment redeploys the workflow
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Workflow graph node notes are non-semantic and excluded from the graph hash
|
|
9
|
+
|
|
10
|
+
`GraphNodeConfig.notes` (`graph/workflow-graph.types.ts`, mirrored on the typed
|
|
11
|
+
builder in `graph/graph-node.ts`) is free-text documentation attached to a node.
|
|
12
|
+
It is deliberately excluded from the graph topology hash (`graphHash`), so
|
|
13
|
+
editing a note never marks the workflow as changed. The graph-level `notes`
|
|
14
|
+
field on `wireWorkflowGraph` (`graph/wire-workflow-graph.ts`) — which carries
|
|
15
|
+
things like imported sticky notes — is excluded for the same reason.
|
|
16
|
+
|
|
17
|
+
The hash exists to answer "is this the same workflow the running instances were
|
|
18
|
+
started against?". Prose about a node has no bearing on that. If notes were
|
|
19
|
+
hashed, adding a sentence of documentation would register as a topology change
|
|
20
|
+
and the only safe habit would be to never document a node.
|
|
21
|
+
|
|
22
|
+
**What this rules out:** folding `notes` into `graphHash` "for completeness",
|
|
23
|
+
or using `notes` to carry anything semantic — a routing hint, a version marker,
|
|
24
|
+
a flag some other code reads — since nothing that changes behaviour may live in
|
|
25
|
+
a field the change-detection hash ignores.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: An inline workflow run reports its run id the moment it exists, because a failure throws instead of returning
|
|
4
|
+
description: `onRunCreated` is the only moment guaranteed to happen whether the run passes, fails or suspends
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# An inline workflow run reports its run id the moment it exists, because a failure throws instead of returning
|
|
9
|
+
|
|
10
|
+
`startWorkflow` in `pikku-workflow-service.ts` calls `options.onRunCreated(runId)`
|
|
11
|
+
immediately after `createRun`, before any execution. An inline run that fails
|
|
12
|
+
throws rather than returning `{ runId }`, so a caller wanting to read the run
|
|
13
|
+
back — its steps, which one failed, what it was called with — would otherwise
|
|
14
|
+
have nothing to read it by. Run creation is the only moment guaranteed to happen
|
|
15
|
+
whether the run goes on to pass, fail or suspend.
|
|
16
|
+
|
|
17
|
+
The failure path is equally deliberate. `WorkflowAsyncException`,
|
|
18
|
+
`WorkflowCancelledException`, `WorkflowSuspendedException` and
|
|
19
|
+
`WorkflowDispatchException` are all excluded from the "mark the run failed"
|
|
20
|
+
branch: the first three already recorded their own status, and the fourth is
|
|
21
|
+
transient. When a run does fail, an *expected* error (a `PikkuError`, e.g. a
|
|
22
|
+
build gate tripping) logs only its message — the message is the whole story, and
|
|
23
|
+
the `expected` flag survives the step-boundary rehydration that strips the
|
|
24
|
+
class. Anything else is logged in full so the trace is there to debug.
|
|
25
|
+
|
|
26
|
+
**What this rules out:** moving `onRunCreated` to after execution or into the
|
|
27
|
+
success path, returning a sentinel run id instead of throwing, folding the four
|
|
28
|
+
control-flow exceptions into the generic failure branch, or dumping a stack for
|
|
29
|
+
every expected error.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: `invocationId` is a workflow step's dedupe key; `stepId` is store-specific and must never be used as one
|
|
4
|
+
description: The invocation id is a frozen UUIDv5 of runId + stepName, identical across retries on every backend
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# `invocationId` is a workflow step's dedupe key; `stepId` is store-specific and must never be used as one
|
|
9
|
+
|
|
10
|
+
`deriveInvocationId` (`workflow-invocation-id.ts`) is `uuidv5(runId:stepName)`.
|
|
11
|
+
Because both inputs are stable across replays, the same call yields the same
|
|
12
|
+
UUID on every attempt and on every storage backend — so a step can
|
|
13
|
+
`INSERT … ON CONFLICT (invocation_id)` or pass it as an external idempotency
|
|
14
|
+
key (a Stripe key, say) and have a retry of a half-applied side effect collapse
|
|
15
|
+
onto the first attempt.
|
|
16
|
+
|
|
17
|
+
`stepId` cannot do that job. Whether it stays the same or is minted fresh per
|
|
18
|
+
attempt is store-specific: the in-memory store mints a new one each attempt
|
|
19
|
+
while the SQL store reuses the row. `WorkflowStepWire` documents `invocationId`
|
|
20
|
+
as the dedupe key for exactly this reason.
|
|
21
|
+
|
|
22
|
+
`PIKKU_WORKFLOW_NAMESPACE` in `workflow-invocation-id.ts` is frozen. Changing it
|
|
23
|
+
would alter every derived invocation id and break dedupe across a deploy — steps
|
|
24
|
+
that already ran would look new. The v5 implementation is hand-rolled (SHA-1
|
|
25
|
+
plus the version and variant bit twiddling) rather than pulled from the `uuid`
|
|
26
|
+
package, and `workflow-invocation-id.test.ts` pins it against the known
|
|
27
|
+
`www.example.com`-in-DNS-namespace vector.
|
|
28
|
+
|
|
29
|
+
Calling the same step name more than once in a run *is* disambiguated. Ordinals
|
|
30
|
+
are already in: `nextStepKey` (`pikku-workflow-service.ts`) mints a physical key
|
|
31
|
+
per reach — `name`, then `name#1`, `name#2` — and every step entry point routes
|
|
32
|
+
through it, so `deriveInvocationId` hashes the physical key, not the logical
|
|
33
|
+
name. Each reach therefore gets its own row and its own invocation id. The first
|
|
34
|
+
reach keeps the bare name, so ids minted before ordinals landed are unchanged,
|
|
35
|
+
and the ordinal counters reset at the start of each replay, so a given call site
|
|
36
|
+
resolves to the same key on every attempt. `workflow-step-ordinal.test.ts` pins
|
|
37
|
+
all three properties.
|
|
38
|
+
|
|
39
|
+
**What this rules out:** using `stepId` as an idempotency key, regenerating the
|
|
40
|
+
namespace UUID, swapping in a different hash or a random id, passing the logical
|
|
41
|
+
step name to `deriveInvocationId` instead of the physical key from
|
|
42
|
+
`nextStepKey`, or "simplifying" the derivation to include anything that varies
|
|
43
|
+
between replays.
|
package/knowledge/decisions/internals/workflow-queued-step-dispatch-requires-an-explicit-opt-in.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: A workflow step goes through the queue only if its function opts in, and there is no inline fallback
|
|
4
|
+
description: `workflowQueued: true` is the whole decision; a missing queue service is a hard error, not a silent downgrade
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# A workflow step goes through the queue only if its function opts in, and there is no inline fallback
|
|
9
|
+
|
|
10
|
+
`dispatchStep` in `pikku-workflow-service.ts` decides queued-vs-inline purely
|
|
11
|
+
from the step function's `workflowQueued` flag in function meta, which defaults
|
|
12
|
+
to false. If the flag is not set the method returns false and the caller runs
|
|
13
|
+
the step inline. If it IS set and no queue service is configured, that is a hard
|
|
14
|
+
error naming the step and the function — never a quiet downgrade to inline
|
|
15
|
+
execution, because a function marked `workflowQueued` was marked that way for a
|
|
16
|
+
reason (isolation, a long tail latency, a resource limit) that inline execution
|
|
17
|
+
does not honour.
|
|
18
|
+
|
|
19
|
+
Inline execution is not merely a degraded queue path. `runInlineRetryLoop` wraps
|
|
20
|
+
the same `running → result` / `fail → retry-attempt → backoff → retry`
|
|
21
|
+
scaffolding around a step-specific body and stays O(K) — no suspend, no replay —
|
|
22
|
+
which is what makes an inline run cheap. Its optional `onError` hook exists for
|
|
23
|
+
terminal errors that must NOT retry (RPC-not-found suspends the run for
|
|
24
|
+
redeploy); if the hook throws, the loop exits immediately without recording a
|
|
25
|
+
step error or retrying.
|
|
26
|
+
|
|
27
|
+
**What this rules out:** inferring "should queue" from the presence of a queue
|
|
28
|
+
service, falling back to inline when the queue is missing, and reusing
|
|
29
|
+
`runInlineRetryLoop` for anything that needs to suspend between attempts.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Workflows get their own queues by default, and queue names are resolved from queue meta
|
|
4
|
+
description: Per-workflow queues stop one slow step head-of-line-blocking every other workflow; `shared-groups` trades that for one set of pollers
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Workflows get their own queues by default, and queue names are resolved from queue meta
|
|
9
|
+
|
|
10
|
+
`WorkflowQueueOptions.queueStrategy` defaults to `'per-workflow'`: each workflow
|
|
11
|
+
gets its own `wf-orchestrator-*` and `wf-step-*` queue. That gives complete
|
|
12
|
+
isolation and is what lets serverless providers deploy one unit per workflow,
|
|
13
|
+
at the cost of one set of pollers per queue — which adds up on pull-based
|
|
14
|
+
backends. `'shared-groups'` puts every workflow on the shared orchestrator and
|
|
15
|
+
step-worker queues and keeps them isolated with a per-group concurrency cap, so
|
|
16
|
+
there is one set of pollers for the whole system. It is only for single-process
|
|
17
|
+
runtimes; a per-unit serverless deploy needs the per-workflow queues to route to
|
|
18
|
+
its units. The options are passed to the service constructor rather than read
|
|
19
|
+
from `config.workflow` because the queues are wired during construction, before
|
|
20
|
+
singleton services — and so before `config` — exist.
|
|
21
|
+
|
|
22
|
+
Under `'shared-groups'`, `getJobGroup` returns a group keyed by workflow name
|
|
23
|
+
(steps group by step function, mirroring how per-step queues split them). It
|
|
24
|
+
returns `undefined` under `'per-workflow'`, because the queue name already
|
|
25
|
+
isolates the workflow and a group would cap it inside its own dedicated queue.
|
|
26
|
+
The group tier repeats the id so a workflow can be given its own limit purely
|
|
27
|
+
from config; note tiers can only lower a limit, never raise it above `default`,
|
|
28
|
+
because the backend applies its pre-fetch exclusion per group using `default`
|
|
29
|
+
alone.
|
|
30
|
+
|
|
31
|
+
`getOrchestratorQueueName` and `getStepWorkerQueueName` read `queue.meta`, which
|
|
32
|
+
is always populated globally, rather than `queue.registrations`, which only
|
|
33
|
+
covers queues this unit consumes. In a per-unit deploy the orchestrator unit
|
|
34
|
+
produces to the per-step queues without consuming them, so registrations would
|
|
35
|
+
miss them. `wireQueueWorkers` warns loudly when workflows exist but no
|
|
36
|
+
`wf-orchestrator-*` queue is in meta: everything still "works" via the shared
|
|
37
|
+
fallback, but the isolation is gone and one slow step head-of-line-blocks every
|
|
38
|
+
other workflow — invisible until a queue starves.
|
|
39
|
+
|
|
40
|
+
**What this rules out:** defaulting to `'shared-groups'`, returning a job group
|
|
41
|
+
under `'per-workflow'`, resolving queue names from `queue.registrations`, or
|
|
42
|
+
dropping the wiring-time warning as noise.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: A workflow step name repeated in one run gets an ordinal suffix, and the first reach stays bare
|
|
4
|
+
description: `name`, `name#1`, `name#2` keys each reach separately without changing the durable key of any existing run
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# A workflow step name repeated in one run gets an ordinal suffix, and the first reach stays bare
|
|
9
|
+
|
|
10
|
+
`nextStepKey` in `pikku-workflow-service.ts` turns a logical step name into the
|
|
11
|
+
physical, replay-stable key for the Nth time the run reaches it: the bare name
|
|
12
|
+
for ordinal 0, `name#N` for repeats. Keeping the first reach unsuffixed is what
|
|
13
|
+
makes the scheme backward compatible — existing runs and their persisted step
|
|
14
|
+
rows are untouched — while still letting the same literal step name be invoked
|
|
15
|
+
several times (a loop, a helper called twice) without the rows clobbering each
|
|
16
|
+
other.
|
|
17
|
+
|
|
18
|
+
The counters live in the per-replay `RunContext.replay.ordinals` and are reset
|
|
19
|
+
by `beginReplay` on every orchestrator tick. That reset is what makes the keys
|
|
20
|
+
deterministic: given a deterministic workflow body, the second replay assigns
|
|
21
|
+
exactly the same key to the same reach and therefore finds the cached row rather
|
|
22
|
+
than minting `name#1` for a step that already succeeded. `nextStepKey` also
|
|
23
|
+
records the key it just produced as `replay.lastStep`, which is how the next
|
|
24
|
+
step learns its predecessor (`fromStepName`).
|
|
25
|
+
|
|
26
|
+
Graph runs use the same convention for cycle revisits, and
|
|
27
|
+
`stripInstanceOrdinal` / `executeWorkflowStep` map `node#N` back to the logical
|
|
28
|
+
node id, which is not a literal key in the graph's `nodes` map.
|
|
29
|
+
|
|
30
|
+
**What this rules out:** suffixing the first reach too (it re-keys every step of
|
|
31
|
+
every existing run), advancing the ordinal counters anywhere other than a fresh
|
|
32
|
+
replay pass, deriving step keys from a non-deterministic source, or treating a
|
|
33
|
+
physical step key as a graph node id without stripping the ordinal.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: A workflow replay reads its steps once and caches only the run's immutable half
|
|
4
|
+
description: The per-replay snapshot collapses O(N^2) step reads to one, but caching mutable run fields would make the replay read a lie
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# A workflow replay reads its steps once and caches only the run's immutable half
|
|
9
|
+
|
|
10
|
+
A DSL replay walks the workflow body from the top, and each step it passes asks
|
|
11
|
+
for its own row — so a run of N steps costs N reads per replay and O(N^2) over
|
|
12
|
+
its lifetime. `beginReplay` in `pikku-workflow-service.ts` opens a pass by
|
|
13
|
+
calling `listStepStates`, which backends able to answer in a single query
|
|
14
|
+
override; `loadOrCreateStep` then serves every step from that snapshot. This is
|
|
15
|
+
safe because a pass reaches each step key at most once and the steps it replays
|
|
16
|
+
past are `succeeded`, and therefore immutable.
|
|
17
|
+
|
|
18
|
+
`getRunIdentity` caches the run for the same pass, but only for its immutable
|
|
19
|
+
half — which workflow it is, the wire it was started on, its input. Anything
|
|
20
|
+
needing `status`, `output`, `error` or `state` must call `getRun`: those move
|
|
21
|
+
while the run executes and a cached copy would be a lie. The `replay` half of
|
|
22
|
+
`RunContext` is rebuilt from scratch on every orchestrator tick and torn down by
|
|
23
|
+
`endReplay`.
|
|
24
|
+
|
|
25
|
+
`loadOrCreateStep` also handles a concurrent replay creating the row after the
|
|
26
|
+
snapshot was taken: if `create()` throws, it re-reads the step, and only if that
|
|
27
|
+
read also fails does it rethrow the original — because in that case the insert
|
|
28
|
+
failed for its own reasons and that error is the one worth seeing.
|
|
29
|
+
|
|
30
|
+
**What this rules out:** widening the snapshot to cover mutable run fields,
|
|
31
|
+
keeping it across orchestrator ticks, or removing the re-read fallback in
|
|
32
|
+
`loadOrCreateStep` on the grounds that a duplicate insert "cannot happen".
|
package/knowledge/decisions/internals/workflow-retries-are-owned-by-the-workflow-not-the-queue.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Workflow step retries are owned by the workflow, never by the queue
|
|
4
|
+
description: A step's retry count is resolved once and always passed to the queue as `attempts`, so the queue can never apply its own default
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Workflow step retries are owned by the workflow, never by the queue
|
|
9
|
+
|
|
10
|
+
A step's retry policy comes from the step itself, falling back to
|
|
11
|
+
`DEFAULT_STEP_RETRIES` (5) when unset. The default is deliberately greater than
|
|
12
|
+
zero so a transient failure — a DB blip, a downstream restart, a deploy — is
|
|
13
|
+
ridden out without the author asking for it; that is safe only because every
|
|
14
|
+
step gets a stable `invocationId` to dedupe on. An explicit `retries: 0` means
|
|
15
|
+
exactly once and must be honoured.
|
|
16
|
+
|
|
17
|
+
`resolveStepJobOptions` in `pikku-workflow-service.ts` therefore ALWAYS emits
|
|
18
|
+
`attempts`, even when it is 1. Backoff defaults to exponential whenever at least
|
|
19
|
+
one retry remains, so retries ride out an outage instead of firing instantly; a
|
|
20
|
+
concrete `retryDelay` (`15000`, `'15s'`) selects fixed backoff, and only the
|
|
21
|
+
literal `'exponential'` selects exponential explicitly. `rpcStep` resolves the
|
|
22
|
+
policy once, before both persistence and dispatch, so the value stored on the
|
|
23
|
+
step row — which drives `retriesExhausted` — is the same number the queue turns
|
|
24
|
+
into `attempts`. `queueGraphNode` in `graph/graph-runner.ts` defaults node
|
|
25
|
+
retries to `DEFAULT_STEP_RETRIES` for the same reason.
|
|
26
|
+
|
|
27
|
+
**What this rules out:** dropping `attempts` when it equals 1 "because that is
|
|
28
|
+
the default anyway", resolving retries separately at the persistence and
|
|
29
|
+
dispatch sites, or letting the queue adapter's own `retry_limit` decide. Any of
|
|
30
|
+
those lets the queue re-run a step the workflow said to run once, or lets the
|
|
31
|
+
engine believe retries are exhausted while the queue keeps retrying.
|
package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Workflow run capabilities are extensions, not subclasses
|
|
4
|
+
description: Scenario support lives in a separate module behind `setRunExtension` because a bundler drops an unused module but never an unused class member
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Workflow run capabilities are extensions, not subclasses
|
|
9
|
+
|
|
10
|
+
`PikkuWorkflowService` names nothing about what a `WorkflowRunExtension` is for.
|
|
11
|
+
An extension is installed with `setRunExtension(create)` and receives a narrow
|
|
12
|
+
`WorkflowRunEngine` handle — `inlineStep`, `updateRunStatus`,
|
|
13
|
+
`onChildWorkflowFailed`, `verifyStepName` — so recording a durable step stays
|
|
14
|
+
available to it without becoming public API on every workflow service a
|
|
15
|
+
production app instantiates.
|
|
16
|
+
|
|
17
|
+
The reason it is not a subclass is bundle size: a bundler drops an unused
|
|
18
|
+
*module* but never an unused class member. Anything declared on
|
|
19
|
+
`PikkuWorkflowService` ships in every server built on Pikku, along with
|
|
20
|
+
everything it imports. `PikkuScenarioService` (`pikku-scenario-service.ts`) is
|
|
21
|
+
the one implementation today — steps, actors, lifecycle hooks, the browser
|
|
22
|
+
provider and the assertion wire members — and scenarios only ever run from
|
|
23
|
+
`pikku scenario run`, so the whole surface stays behind an import that only the
|
|
24
|
+
runner makes. It is not a workflow service in its own right because a scenario
|
|
25
|
+
is not a different kind of run; it is the same durable run with a step
|
|
26
|
+
vocabulary on top. `scenario-service.test.ts` asserts that none of those members
|
|
27
|
+
leak onto the base class.
|
|
28
|
+
|
|
29
|
+
`createScenarioRunner` in the same file bundles the two lines
|
|
30
|
+
`pikku scenario run` needs so no caller has to remember the capability is
|
|
31
|
+
installed rather than inherited. It pairs the extension with
|
|
32
|
+
`InMemoryWorkflowService`, which is the right engine because a scenario run is a
|
|
33
|
+
single external process driving a deployed app over its real transport: there
|
|
34
|
+
is nothing to persist and no second worker to resume it.
|
|
35
|
+
|
|
36
|
+
**What this rules out:** moving scenario steps, actors, hooks or the browser
|
|
37
|
+
provider onto `PikkuWorkflowService`, making `PikkuScenarioService` extend it,
|
|
38
|
+
or widening `WorkflowRunEngine` into "just pass the service" — each one puts the
|
|
39
|
+
scenario runtime, and its transitive imports, into every deployed Pikku server.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: The workflow run mirror is an observability sink, never a second source of truth
|
|
4
|
+
description: Every mirrored write happens after the authoritative write lands, and a mirror failure can never fail the workflow
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# The workflow run mirror is an observability sink, never a second source of truth
|
|
9
|
+
|
|
10
|
+
`WorkflowRunMirror` lets an executor shadow every state write to an external
|
|
11
|
+
read store — typically a DB the console UI queries while the run itself lives in
|
|
12
|
+
a Durable Object or Redis. Both properties that make it safe follow from the
|
|
13
|
+
single shape of `PikkuWorkflowService.mirrored()` in
|
|
14
|
+
`pikku-workflow-service.ts`: the mirror is only ever told about a write that has
|
|
15
|
+
already landed in the canonical store, and a mirror that is down or throwing is
|
|
16
|
+
caught, logged at warn, and otherwise invisible to the workflow. Even the log
|
|
17
|
+
call is wrapped, because singleton services may not be initialised yet.
|
|
18
|
+
|
|
19
|
+
Every public write method is a thin `mirrored(() => …Impl(...), (mirror) => …)`
|
|
20
|
+
pair over a `protected abstract` implementation. That pairing is the reason a
|
|
21
|
+
mirror method added to the interface but never wired into the service would
|
|
22
|
+
write nothing at runtime — `workflow-mirror.test.ts` spells out the full method
|
|
23
|
+
list to catch exactly that.
|
|
24
|
+
|
|
25
|
+
**What this rules out:** reading run or step state back from the mirror,
|
|
26
|
+
awaiting the mirror before returning the authoritative result, letting a mirror
|
|
27
|
+
rejection propagate, or writing to the mirror first so the two "stay in sync" —
|
|
28
|
+
any of which turns an index into a second, divergent source of truth that can
|
|
29
|
+
take the workflow down with it.
|
package/knowledge/decisions/internals/workflow-run-polling-backs-off-to-the-callers-ceiling.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Workflow run polling starts short and backs off to the caller's ceiling
|
|
4
|
+
description: `pollIntervalMs` is a ceiling, not a cadence, and the wait lives in its own method so the schedule can be asserted without the clock
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Workflow run polling starts short and backs off to the caller's ceiling
|
|
9
|
+
|
|
10
|
+
`awaitRunEnd` in `pikku-workflow-service.ts` reads a run until it reaches an end
|
|
11
|
+
state, starting at `WORKFLOW_POLL_MIN_MS` (10ms) and multiplying by
|
|
12
|
+
`WORKFLOW_POLL_FACTOR` (1.6) up to the caller's `maxIntervalMs`. A fixed
|
|
13
|
+
interval is wrong at both ends: it makes a workflow that finished in
|
|
14
|
+
milliseconds wait out the whole interval anyway, and it keeps reading a
|
|
15
|
+
long-running one at full rate for its entire life. Backing off returns quick
|
|
16
|
+
runs promptly while a slow run's read cost grows logarithmically rather than
|
|
17
|
+
linearly with duration. So `runToCompletion`'s `pollIntervalMs` is a ceiling,
|
|
18
|
+
not a cadence.
|
|
19
|
+
|
|
20
|
+
An inline sub-workflow uses a lower ceiling, `WORKFLOW_CHILD_POLL_MAX_MS`
|
|
21
|
+
(500ms), because the parent step is blocked on it: every wait there is added
|
|
22
|
+
latency in the middle of a workflow rather than at its edge.
|
|
23
|
+
|
|
24
|
+
`waitBeforeNextRead` exists as its own method purely so the schedule can be
|
|
25
|
+
asserted directly (`workflow-run-polling.test.ts`). Timing a poll loop by the
|
|
26
|
+
clock measures the host's scheduler as much as the policy — `setTimeout(40)`
|
|
27
|
+
routinely returns late on a loaded CI runner — which makes the obvious test both
|
|
28
|
+
slow and flaky.
|
|
29
|
+
|
|
30
|
+
**What this rules out:** replacing the backoff with a fixed `pollIntervalMs`
|
|
31
|
+
sleep, reading `pollIntervalMs` as the first wait, giving child runs the
|
|
32
|
+
top-level ceiling, or inlining `waitBeforeNextRead` back into the loop as a bare
|
|
33
|
+
`setTimeout`.
|
package/knowledge/decisions/internals/workflow-run-timeline-is-a-pure-fold-over-durable-history.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: The workflow run timeline is a pure fold over durable history, with the row's status as the authority
|
|
4
|
+
description: No IO in the fold keeps time-travel transport-independent; the terminal event comes from `status`, not from a timestamp every backend populates
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# The workflow run timeline is a pure fold over durable history, with the row's status as the authority
|
|
9
|
+
|
|
10
|
+
`run-timeline.ts` turns `getRunHistory` — one row per step *attempt*, each with
|
|
11
|
+
lifecycle timestamps — into a flat, chronologically ordered event stream, and
|
|
12
|
+
folds that stream up to any point to recover what the run "knew" then: the same
|
|
13
|
+
step cache a replay would hold, plus the walked path. Both functions are pure,
|
|
14
|
+
with no IO, so they are trivially testable and the same fold works for the
|
|
15
|
+
Redis, Kysely and in-memory stores alike.
|
|
16
|
+
|
|
17
|
+
The terminal event is driven by the row's authoritative `status`, falling back
|
|
18
|
+
to `updatedAt` when the specific stamp is absent, because the lifecycle
|
|
19
|
+
timestamps are not populated by every backend — Kysely leaves
|
|
20
|
+
`succeededAt`/`runningAt` null. The intermediate `scheduled` and `running`
|
|
21
|
+
events are optional enrichment, emitted only when the backend recorded them; the
|
|
22
|
+
`pending` event always exists and is the one that carries provenance
|
|
23
|
+
(`fromStepName`).
|
|
24
|
+
|
|
25
|
+
Ordering is defensive: events sort by timestamp, then by `LIFECYCLE_ORDER`, then
|
|
26
|
+
by original index, so rows sharing an instant stay deterministic across
|
|
27
|
+
backends. In the fold, a retry's `pending` event reopens the step and drops the
|
|
28
|
+
prior result and error.
|
|
29
|
+
|
|
30
|
+
The index conventions are fixed and callers depend on them: `TimelineEvent.seq`
|
|
31
|
+
is a monotonic 0-based position, `attempt` is 1-based, and
|
|
32
|
+
`reconstructStateAt(at)` is inclusive whether `at` is a seq or a `Date` — a
|
|
33
|
+
point before the first event yields the empty initial state with `seq` of `-1`.
|
|
34
|
+
|
|
35
|
+
**What this rules out:** reading state inside the fold, deriving the terminal
|
|
36
|
+
event from `succeededAt`/`failedAt` alone, trusting history to arrive sorted, or
|
|
37
|
+
letting a retry's reopening event keep the previous attempt's outcome.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Scenario steps default to no retries, and a whole poll is one durable step
|
|
4
|
+
description: Retrying a failed assertion is wrong for a test primitive; recording the poll as one step means replay returns the outcome, not the loop
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Scenario steps default to no retries, and a whole poll is one durable step
|
|
9
|
+
|
|
10
|
+
`ScenarioStepOptions.retries` defaults to 0, unlike an ordinary workflow step
|
|
11
|
+
which inherits `DEFAULT_STEP_RETRIES`. `PikkuScenarioService.scenarioStep`
|
|
12
|
+
applies that default explicitly (`options?.retries ?? 0`). Retrying a failed
|
|
13
|
+
assertion is the wrong behaviour for a test primitive: it converts a real
|
|
14
|
+
failure into a slow flake and hides the very race the scenario was written to
|
|
15
|
+
catch.
|
|
16
|
+
|
|
17
|
+
`expectEventually` is the sanctioned way to wait. The entire poll — invoke,
|
|
18
|
+
check the predicate, sleep, repeat until `within` elapses — runs inside a single
|
|
19
|
+
`inlineStep`, so it is ONE recorded step and a replay returns the cached
|
|
20
|
+
outcome rather than re-polling. `expectError` and `expectService` are the same
|
|
21
|
+
shape: one durable step whose body contains the whole assertion, with a failure
|
|
22
|
+
message that names the step, the target, and what was actually seen.
|
|
23
|
+
|
|
24
|
+
`pollUntil` in `scenario-poll.ts` is the step-level equivalent, and its
|
|
25
|
+
`undefined` convention is deliberate: `undefined` means "not yet" and nothing
|
|
26
|
+
else, because `false`, `0` and `''` are all real answers — a probe asking
|
|
27
|
+
whether something happened reports `false` when it did not. It returns
|
|
28
|
+
`undefined` at the deadline rather than throwing, leaving the error to the
|
|
29
|
+
caller, who is the only one who knows what was being waited for. Its own
|
|
30
|
+
defaults are shorter than the assertion wrappers': `within` 15s, `interval`
|
|
31
|
+
250ms.
|
|
32
|
+
|
|
33
|
+
`requireActor` and `requireScenarioEnv` (`scenario-step-guards.ts`) exist for
|
|
34
|
+
the mirror-image reason: `actor` and `env` are optional on the step wire because
|
|
35
|
+
a pure assertion step needs neither, so the narrowing happens in one place with
|
|
36
|
+
a message that says what to do, instead of every step file writing its own
|
|
37
|
+
guard. `scenarioStep`'s `verifyStepName` call doubles as the guard for `then`
|
|
38
|
+
being a wire member — an accidental `await scenario` calls it with a resolve
|
|
39
|
+
function, which lands as a loud named error instead of a silent hang.
|
|
40
|
+
|
|
41
|
+
The assertion options are lenient by design so a scenario reads as intent
|
|
42
|
+
rather than as an exact-match harness: `matches` is a substring test when it is
|
|
43
|
+
a string and a full match only when it is a `RegExp`; `calledWith` deep-equals
|
|
44
|
+
the first argument only; `times` means at-least-once unless a count is given;
|
|
45
|
+
`within` defaults to `'30s'` and `interval` to `'1s'`.
|
|
46
|
+
|
|
47
|
+
**What this rules out:** giving scenario steps the workflow retry default,
|
|
48
|
+
recording each poll iteration as its own step, treating a falsy `pollUntil`
|
|
49
|
+
result as "not yet", making `pollUntil` throw on timeout, or narrowing `actor`
|
|
50
|
+
by hand inside individual step files.
|