@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
package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Scenario lifecycle hooks are a scenario-only affordance and never mask the failure they follow
|
|
4
|
+
description: A durable workflow replays, so a callback that reruns each replay has no honest meaning there
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Scenario lifecycle hooks are a scenario-only affordance and never mask the failure they follow
|
|
9
|
+
|
|
10
|
+
`PikkuScenarioService.scenarioHooks` (`pikku-scenario-service.ts`) returns hooks
|
|
11
|
+
only when `workflowMeta.source === 'scenario'`. A plain workflow is durable and
|
|
12
|
+
resumable, so a `before`/`after` callback that reran on every replay would have
|
|
13
|
+
no honest meaning — hooks exist for scenarios because a scenario run is a single
|
|
14
|
+
pass by a single external process.
|
|
15
|
+
|
|
16
|
+
A hook is not a pikku function: it has no id, no meta and no schema, so it
|
|
17
|
+
cannot go through `runPikkuFunc` and the runner records nothing for it. It gets
|
|
18
|
+
exactly what the scenario body gets — the same wire (which is how it reaches the
|
|
19
|
+
app through `actors`) and singleton services composed with this invocation's
|
|
20
|
+
wire services — and nothing else. `ScenarioHookError` keeps the original error
|
|
21
|
+
as `cause`, so the failure that actually happened is never lost behind the label
|
|
22
|
+
saying which phase it happened in.
|
|
23
|
+
|
|
24
|
+
`onAfterRunFunc` returns early on the `interrupted` outcome, because the run is
|
|
25
|
+
suspended or waiting and teardown would fire mid-flight. When the scenario has
|
|
26
|
+
already failed for its own reason, an `after`-hook failure is attached as
|
|
27
|
+
`cause` and logged rather than replacing the headline; only a teardown failure
|
|
28
|
+
after a *passing* scenario fails the run.
|
|
29
|
+
|
|
30
|
+
At the feature level (`workflow.types.ts`, `CoreFeature`), hooks run once around
|
|
31
|
+
the whole group — `before → a → b → c → after` — not per scenario. That is the
|
|
32
|
+
one thing a feature deliberately cannot express: gherkin's `Background:` runs
|
|
33
|
+
per scenario, and per-scenario setup is the scenario's own `before`.
|
|
34
|
+
|
|
35
|
+
`setScenarioEnvironment` on the same service is per-service, not per-run, for a
|
|
36
|
+
related reason: a runner process targets exactly one environment for every
|
|
37
|
+
scenario it executes, so threading it through each run would only create ways
|
|
38
|
+
for two runs in one process to disagree.
|
|
39
|
+
|
|
40
|
+
**What this rules out:** offering hooks on plain workflows, routing a hook
|
|
41
|
+
through `runPikkuFunc` so it gets recorded as a step, running `after` on an
|
|
42
|
+
interrupted run, letting a teardown failure overwrite the scenario's own
|
|
43
|
+
failure, or reinterpreting feature hooks as per-scenario `Background:`.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Scenario prose is rendered out of typed calls, not parsed into them
|
|
4
|
+
description: The inversion of cucumber — a readable report with no regex step registry to maintain
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Scenario prose is rendered out of typed calls, not parsed into them
|
|
9
|
+
|
|
10
|
+
`scenario-prose.ts` renders the English sentence a reporter shows for a scenario
|
|
11
|
+
step. It is the inversion of cucumber: instead of parsing English into a call
|
|
12
|
+
through a registry of regexes, the call is typed and the English is rendered out
|
|
13
|
+
of it. The readable report survives without anyone maintaining a step-definition
|
|
14
|
+
registry, and a step that no longer exists cannot leave a dangling phrase behind.
|
|
15
|
+
|
|
16
|
+
`renderScenarioProse` fills a step's `template` from the input the step was
|
|
17
|
+
actually called with, so the sentence names the values under test — "sees
|
|
18
|
+
@pikku/addon-todos" rather than "sees an addon in the gallery" three times over.
|
|
19
|
+
A placeholder with no recorded value renders as nothing and the surrounding
|
|
20
|
+
whitespace collapses, so an omitted optional input reads as a shorter sentence
|
|
21
|
+
rather than leaking a literal `{state}` into the report. `template` is
|
|
22
|
+
deliberately distinct from `description`: `description` documents what the step
|
|
23
|
+
does, `template` is what a reader of the report sees, and it falls back to
|
|
24
|
+
`description` when absent.
|
|
25
|
+
|
|
26
|
+
It lives in `@pikku/core` rather than in the CLI so the CLI reporter and the
|
|
27
|
+
console render the same sentence for the same step.
|
|
28
|
+
|
|
29
|
+
**What this rules out:** adding a gherkin parser or regex step registry,
|
|
30
|
+
rendering prose in the CLI reporter or console instead of core (the two would
|
|
31
|
+
drift), collapsing `template` into `description`, or making a missing
|
|
32
|
+
placeholder value render as the raw placeholder.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: A quarantined scenario states its reason in code, not in a CI invocation
|
|
4
|
+
description: `skip` carries the why next to the scenario it applies to, and naming the scenario explicitly still runs it
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# A quarantined scenario states its reason in code, not in a CI invocation
|
|
9
|
+
|
|
10
|
+
`WorkflowsMeta`'s `skip` field (`workflow.types.ts`) is a string, not a boolean.
|
|
11
|
+
A scenario held out of a default run has to say why, and stating the reason in
|
|
12
|
+
code keeps the quarantine next to the scenario it applies to rather than buried
|
|
13
|
+
in a CI invocation nobody reads. A skipped scenario is still runnable — naming
|
|
14
|
+
it explicitly with `--flows` runs it regardless — so quarantine is a default,
|
|
15
|
+
not a disablement.
|
|
16
|
+
|
|
17
|
+
**What this rules out:** turning `skip` into a boolean flag, moving the skip
|
|
18
|
+
list into CI configuration, or making a skipped scenario unrunnable.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Scenario step targets are string literals so the inspector can read them statically
|
|
4
|
+
description: `step/given/when/then` mirror `do`'s RPC shape because the extractor reads a literal, not an imported symbol
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Scenario step targets are string literals so the inspector can read them statically
|
|
9
|
+
|
|
10
|
+
`ScenarioStepInvocation` in `dsl/workflow-dsl.types.ts`, and the `step`,
|
|
11
|
+
`given`, `when` and `then` members of `PikkuScenarioWire`, all take
|
|
12
|
+
`(stepName, stepFunc: string, data?, options?)` — deliberately the same shape as
|
|
13
|
+
`WorkflowWireDoRPC`. The target is a string, not an imported symbol, because
|
|
14
|
+
the Pikku inspector is static analysis: it reads the argument as a literal and
|
|
15
|
+
does not resolve identifiers. Type safety comes back at the edges — the
|
|
16
|
+
generated `TypedScenario` narrows these over `FlattenedScenarioStepMap`.
|
|
17
|
+
|
|
18
|
+
`given`/`when`/`then` are pure sugar over `step`; the phase only changes the
|
|
19
|
+
prose a reporter renders (`scenario-prose.ts`), never what executes.
|
|
20
|
+
|
|
21
|
+
The prose direction is itself the decision: rather than parsing English into a
|
|
22
|
+
call the way cucumber does, `composeStepProse` renders English out of a typed
|
|
23
|
+
call, so a readable report survives without a regex registry paying for it. It
|
|
24
|
+
lives in core so the CLI reporter and the console render the same sentence for
|
|
25
|
+
the same step, and `renderStepTemplate` fills `{placeholders}` from the input
|
|
26
|
+
the step was actually called with — "sees @pikku/addon-todos" rather than the
|
|
27
|
+
same generic sentence three times. A placeholder with no recorded value renders
|
|
28
|
+
as nothing and the surrounding whitespace collapses, so an omitted optional
|
|
29
|
+
input reads as a shorter sentence rather than leaking a literal `{state}`.
|
|
30
|
+
|
|
31
|
+
**What this rules out:** changing `stepFunc` to accept the imported step config,
|
|
32
|
+
reordering the arguments away from `do`'s shape, giving `given`/`when`/`then`
|
|
33
|
+
behaviour of their own, or moving prose rendering into the CLI where the console
|
|
34
|
+
would drift from it.
|
package/knowledge/decisions/internals/workflow-step-compensation-runs-as-its-own-durable-step.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: A step's compensation handler runs as a durable step of its own, and never compensates itself
|
|
4
|
+
description: A refund or rollback must not fire twice on replay, so `onError` is recorded as `<step>:onError` with retries disabled
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# A step's compensation handler runs as a durable step of its own, and never compensates itself
|
|
9
|
+
|
|
10
|
+
`runStepCompensation` in `pikku-workflow-service.ts` invokes a failed step's
|
|
11
|
+
`onError` RPC through `rpcStep` under the name `<stepName>:onError` rather than
|
|
12
|
+
calling it directly. Durability is the point: a compensation handler is
|
|
13
|
+
typically a refund or a rollback, and a bare invoke would fire again on every
|
|
14
|
+
replay that walks past the failed step. Recorded as a step, the second replay
|
|
15
|
+
finds it `succeeded` and returns the cached result.
|
|
16
|
+
|
|
17
|
+
It runs with `{ retries: 0 }` and its own `onError` is deliberately not
|
|
18
|
+
forwarded — a compensation handler cannot itself compensate. `onError` mirrors a
|
|
19
|
+
graph node's: the handler receives `{ error: { message } }`, and the original
|
|
20
|
+
error is still thrown afterwards, so the workflow fails either way. This is
|
|
21
|
+
compensation, not recovery.
|
|
22
|
+
|
|
23
|
+
**What this rules out:** invoking the `onError` RPC inline "since it's just
|
|
24
|
+
cleanup", giving it the workflow's default retry count, chaining a second
|
|
25
|
+
`onError` onto it, or swallowing the original error because the handler
|
|
26
|
+
succeeded.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: A failed workflow step dispatch is transient infrastructure, not a run failure
|
|
4
|
+
description: Queue-unreachable errors leave the run running and the step pending so the orchestrator replays; marking the run failed loses it
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# A failed workflow step dispatch is transient infrastructure, not a run failure
|
|
9
|
+
|
|
10
|
+
`WorkflowDispatchException` (`pikku-workflow-service.ts`) means the queue itself
|
|
11
|
+
could not accept the job — pg-boss momentarily down, the transport unreachable —
|
|
12
|
+
not that the step's own logic failed. Everywhere it surfaces (`dispatchStep`,
|
|
13
|
+
`sleepStep`, `startWorkflow`, `orchestrateWorkflow`) the run is left untouched:
|
|
14
|
+
the step stays `pending`, the run stays `running`, and the orchestrator job is
|
|
15
|
+
rethrown so the queue redelivers it and the workflow replays from its snapshot.
|
|
16
|
+
|
|
17
|
+
The ordering inside `rpcStep` and `sleepStep` is load-bearing: dispatch happens
|
|
18
|
+
BEFORE the step is marked `scheduled`. If the step were marked `scheduled`
|
|
19
|
+
first and the dispatch then failed, the next replay would see `scheduled`,
|
|
20
|
+
pause, and wait forever for a job that was never enqueued.
|
|
21
|
+
|
|
22
|
+
Redelivery is always safe because an orchestrator job is idempotent: it replays
|
|
23
|
+
the workflow from the snapshot and every already-completed step returns its
|
|
24
|
+
cached result rather than running again. The per-job `attempts` that
|
|
25
|
+
`resolveStepJobOptions` always emits is what makes redelivery happen at all — it
|
|
26
|
+
overrides a queue configured with `retry_limit 0`, so the workflow's retry
|
|
27
|
+
policy survives a conservative queue configuration.
|
|
28
|
+
|
|
29
|
+
**What this rules out:** folding `WorkflowDispatchException` into the generic
|
|
30
|
+
catch that calls `updateRunStatus(runId, 'failed', ...)`, swallowing it so the
|
|
31
|
+
run silently stalls, or reordering `setStepScheduled` above `dispatchStep` /
|
|
32
|
+
`scheduleSleep` to "keep the status writes together". Each strands or kills a
|
|
33
|
+
run that a redelivered orchestrator tick would have recovered on its own.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: A workflow step lock is held only to claim the step, never across its execution
|
|
4
|
+
description: Holding the advisory lock — and its pooled connection — across step work exhausted the connection pool and self-deadlocked
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# A workflow step lock is held only to claim the step, never across its execution
|
|
9
|
+
|
|
10
|
+
`executeWorkflowStep` in `pikku-workflow-service.ts` takes `withStepLock` for an
|
|
11
|
+
atomic check-and-mark-running only: it reads the step, returns `null` if the
|
|
12
|
+
step already `succeeded` or is already `running` (another worker owns it),
|
|
13
|
+
starts a fresh attempt if it `failed`, and otherwise marks it `running`. The
|
|
14
|
+
lock is then released, and the actual work plus result persistence run outside
|
|
15
|
+
it.
|
|
16
|
+
|
|
17
|
+
The guard is what makes that safe — once a step is `running`, any concurrent
|
|
18
|
+
worker returns early. The alternative was tried and failed: holding the advisory
|
|
19
|
+
lock, and therefore its pooled connection, across `executeGraphStep` (network
|
|
20
|
+
I/O plus further pool queries) let concurrent steps exhaust the connection pool
|
|
21
|
+
and self-deadlock.
|
|
22
|
+
|
|
23
|
+
**What this rules out:** widening the `withStepLock` callback to cover RPC
|
|
24
|
+
invocation, child-workflow start, `setStepResult` or `resumeWorkflow` — the
|
|
25
|
+
"obviously safer" refactor that reintroduces the deadlock. If a stronger
|
|
26
|
+
guarantee is ever needed it has to come from the claim itself, not from a longer
|
|
27
|
+
lock hold.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: A workflow step's recorded `rpcName` is provenance only — nothing dispatches off it
|
|
4
|
+
description: It exists so a reader can join a runtime step row back to the declaration that produced it, especially when the durable name was built in a loop
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# A workflow step's recorded `rpcName` is provenance only — nothing dispatches off it
|
|
9
|
+
|
|
10
|
+
`insertStepState` and `inlineStep` in `pikku-workflow-service.ts` record the
|
|
11
|
+
name a step was dispatched by: an RPC for a `workflow.do` step, a step function
|
|
12
|
+
for a scenario step, `null` for a closure. Nothing in the engine dispatches off
|
|
13
|
+
that value — it is stored so a reader can join a step back to the function that
|
|
14
|
+
ran it.
|
|
15
|
+
|
|
16
|
+
It earns its keep when the durable step name was built at runtime. A scenario
|
|
17
|
+
step called in a loop reaches the run as, say, `sees @pikku/addon-todos` while
|
|
18
|
+
it was declared as ``sees ${packageName}``; the recorded step-function name is
|
|
19
|
+
then the only way to join that row back to its declaration. `inlineStep` also
|
|
20
|
+
records the `data` the step was called with for the same reason: a reporter
|
|
21
|
+
renders each step's prose from it, so two calls to one step stay
|
|
22
|
+
distinguishable by what they were asked to check.
|
|
23
|
+
|
|
24
|
+
Step lineage is recorded alongside it. `fromStepName` is the predecessor that
|
|
25
|
+
scheduled a step — the walked transition — captured by `rpcStep`/`inlineStep`
|
|
26
|
+
*before* `nextStepKey` advances the lineage, and surfaced to a step as
|
|
27
|
+
`fromInvocationId`. In a cyclic graph `a → b → a → c`, the second `a` therefore
|
|
28
|
+
carries `b`'s id, which is what lets the walked path be reconstructed from the
|
|
29
|
+
chain alone.
|
|
30
|
+
|
|
31
|
+
**What this rules out:** treating the recorded name as the dispatch target,
|
|
32
|
+
dropping it for closure steps "since it is always null", capturing
|
|
33
|
+
`lastStepName` after `nextStepKey` has run, or omitting `data` on inline steps —
|
|
34
|
+
each breaks either the join back to source or the reconstructed path.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: A suspend or approval `reason` is the step's durable identity, not just a message
|
|
4
|
+
description: The reason is namespaced and used raw as the step key, so it must be derived deterministically across replays
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# A suspend or approval `reason` is the step's durable identity, not just a message
|
|
9
|
+
|
|
10
|
+
`getSuspendStepName` and `getApprovalStepName` in `pikku-workflow-service.ts`
|
|
11
|
+
derive a step key from the `reason` string — `__workflow_suspend:<reason>` and
|
|
12
|
+
`__workflow_approval:<reason>`. Each distinct reason is therefore its own step
|
|
13
|
+
row, which is what lets one workflow hold several independent suspends
|
|
14
|
+
(wait-for-build, then wait-for-approval) and lets a dynamic reason inside a loop
|
|
15
|
+
work exactly like a dynamic `do()` step name. The two prefixes are separate
|
|
16
|
+
namespaces so a suspend, an approval, and a `do`/`sleep` step of the same name
|
|
17
|
+
cannot collide.
|
|
18
|
+
|
|
19
|
+
Because the reason IS the identity, it must be derived deterministically: the
|
|
20
|
+
same replay must produce the same reason at the same point, or the run mints a
|
|
21
|
+
new suspend instead of finding the one it is waiting on. This is the same
|
|
22
|
+
contract as `do()` and `sleep()` step names.
|
|
23
|
+
|
|
24
|
+
An approval additionally stores its record under a run-state key built by
|
|
25
|
+
`approvalStateKey`, which hex-encodes the step name. The Mongo backend restricts
|
|
26
|
+
state keys to `/^[a-zA-Z0-9_]+$/` while a reason is arbitrary human text, and
|
|
27
|
+
one key per gate means two gates resolving concurrently cannot clobber each
|
|
28
|
+
other through a read-modify-write.
|
|
29
|
+
|
|
30
|
+
One consequence to know about: `approveStep`'s optional `reason` argument
|
|
31
|
+
addresses the *first* reach of a gate only. If a gate is reached again on a
|
|
32
|
+
later loop iteration, `nextStepKey` gives that row a `#N` suffix, and there is
|
|
33
|
+
currently no way for a caller to name it.
|
|
34
|
+
|
|
35
|
+
**What this rules out:** deriving a reason from a timestamp, a random id or
|
|
36
|
+
anything else that varies between replays; sharing one namespace (or one
|
|
37
|
+
run-state key) between suspends and approvals; and storing the reason raw as a
|
|
38
|
+
run-state key, which breaks on any backend that constrains key characters.
|
package/knowledge/decisions/internals/workflow-suspended-runs-keep-their-in-process-context.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: A suspended workflow run keeps its in-process context; only terminal runs release it
|
|
4
|
+
description: `suspended` is absent from the terminal set on purpose, and a context is dropped only when nothing is holding it open
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# A suspended workflow run keeps its in-process context; only terminal runs release it
|
|
9
|
+
|
|
10
|
+
`WORKFLOW_TERMINAL_STATES` in `pikku-workflow-service.ts` is
|
|
11
|
+
`completed | failed | cancelled`. `suspended` is deliberately absent: a
|
|
12
|
+
suspended run stops a poll loop but can still be resumed, so anything the
|
|
13
|
+
process holds for it — the run context, an extension's per-run state such as a
|
|
14
|
+
scenario's live actor clients — has to survive. `WORKFLOW_END_STATES`, which
|
|
15
|
+
`awaitRunEnd` uses to stop reading, does include `suspended`, because a poller
|
|
16
|
+
should not wait on a run that needs an external nudge. The two sets are not
|
|
17
|
+
interchangeable.
|
|
18
|
+
|
|
19
|
+
`releaseContext` drops a `RunContext` only when neither `inline` nor `replay`
|
|
20
|
+
still holds it open, so an inline run mid-replay is never torn out from under
|
|
21
|
+
itself. `updateRunStatus` releases on a terminal status because queued runs
|
|
22
|
+
never pass through the inline path that would otherwise do it — without that,
|
|
23
|
+
their context would be held for the life of the process. A long-lived server
|
|
24
|
+
orchestrates many runs, so anything kept per run has to be released when that
|
|
25
|
+
run stops executing here (`workflow-run-context.test.ts`).
|
|
26
|
+
|
|
27
|
+
**What this rules out:** adding `suspended` to `WORKFLOW_TERMINAL_STATES`,
|
|
28
|
+
collapsing the two state sets into one, or making `releaseContext`
|
|
29
|
+
unconditional — the first two discard state a resume still needs, the third
|
|
30
|
+
frees a context that an in-flight replay is still walking.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: A dropped audit write is always logged
|
|
4
|
+
description: The no-op audit service falls back to the singleton logger when the wire carries none, so an unconfigured audit call is never silent
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# A dropped audit write is always logged
|
|
9
|
+
|
|
10
|
+
The no-op `AuditService` in `packages/core/src/services/audit-service.ts` is what
|
|
11
|
+
a function gets when it calls `audit.write()` without `audit: true` set on it.
|
|
12
|
+
Its `write` discards the event — but before it does, it warns once, and it looks
|
|
13
|
+
for a logger in two places: the wire's own, then the singleton passed to the
|
|
14
|
+
constructor.
|
|
15
|
+
|
|
16
|
+
The fallback is the point. Wires frequently do not carry a logger, and with only
|
|
17
|
+
`this.wire.logger` the warning would itself be dropped whenever the wire is bare.
|
|
18
|
+
An audit call that silently does nothing is the worst available outcome: the
|
|
19
|
+
function believes it is producing an audit trail, the trail does not exist, and
|
|
20
|
+
nothing anywhere says so. The warning names the function and the fix, and fires
|
|
21
|
+
once per instance so it cannot flood a hot path.
|
|
22
|
+
|
|
23
|
+
**What this rules out:** narrowing the logger lookup to a single source,
|
|
24
|
+
downgrading the warning to `debug`, or removing it as noise from a service whose
|
|
25
|
+
whole job is to do nothing. If this class stops warning, an unconfigured audit
|
|
26
|
+
call becomes undetectable.
|
package/knowledge/decisions/security/actor-flow-missing-approval-decisions-default-to-denied.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: An actor's missing approval decision defaults to denied
|
|
4
|
+
description: Every pending tool call gets an explicit decision; an id the persona LLM omitted is denied, so a dropped field can never read as consent
|
|
5
|
+
tags: actor-flow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# An actor's missing approval decision defaults to denied
|
|
9
|
+
|
|
10
|
+
`decideApprovals` in
|
|
11
|
+
`packages/core/src/wirings/actor-flow/run-conversation.ts` maps over the
|
|
12
|
+
target agent's `pendingApprovals`, not over the decisions the persona LLM
|
|
13
|
+
returned. Any `toolCallId` the model omitted, hallucinated, or renamed resolves
|
|
14
|
+
to `approved: false`.
|
|
15
|
+
|
|
16
|
+
The persona's decision comes from a structured LLM call, and structured output
|
|
17
|
+
is not guaranteed to be complete. Iterating the model's array instead would make
|
|
18
|
+
an omission indistinguishable from silence — and silence would let a scenario
|
|
19
|
+
approve a destructive tool call nobody decided on, then pass.
|
|
20
|
+
|
|
21
|
+
**What this rules out:** building the decision list from the LLM's `decisions`
|
|
22
|
+
array, and defaulting an unmatched call to `true` to keep a conversation moving.
|
package/knowledge/decisions/security/actor-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Actor sign-in is proven by Set-Cookie, not a non-empty jar
|
|
4
|
+
description: HttpScenarioActor tracks its own signedIn flag and requires the sign-in response itself to set a cookie, because a populated jar proves nothing
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Actor sign-in is proven by Set-Cookie, not a non-empty jar
|
|
9
|
+
|
|
10
|
+
`HttpScenarioActor` (`packages/core/src/services/http-scenario-actors.ts`) keeps
|
|
11
|
+
a private `signedIn` boolean rather than inferring the session from its cookie
|
|
12
|
+
jar, and `login()` throws when the sign-in response carries no `Set-Cookie`
|
|
13
|
+
header even though the response was a 2xx.
|
|
14
|
+
|
|
15
|
+
A cookie jar cannot answer "did sign-in happen". A target app may set a cookie on
|
|
16
|
+
any request — a CSRF token, an anonymous session, a locale — so a non-empty jar
|
|
17
|
+
after a failed or skipped sign-in looks exactly like a successful one. What
|
|
18
|
+
actually proves a session was established is *this* response setting a cookie. A
|
|
19
|
+
2xx alone is not enough either: an endpoint that returns 200 while quietly
|
|
20
|
+
declining to issue a session would leave the actor running every subsequent
|
|
21
|
+
request unauthenticated, and the scenario would report the resulting refusals as
|
|
22
|
+
genuine permission failures.
|
|
23
|
+
|
|
24
|
+
**What this rules out:** replacing `signedIn` with a `jar.isEmpty()` check,
|
|
25
|
+
dropping the `getSetCookie().length === 0` guard as redundant with `res.ok`, and
|
|
26
|
+
treating `signOut()` as jar-clearing only — it must reset the flag too, or the
|
|
27
|
+
next call proceeds believing it has a session.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Actor sign-in only works for actor-flagged users
|
|
4
|
+
description: The scenario actor secret mints sessions for user rows flagged actor and nothing else, so holding it never impersonates a real user
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Actor sign-in only works for actor-flagged users
|
|
9
|
+
|
|
10
|
+
`HttpScenarioActorsConfig.secret`
|
|
11
|
+
(`packages/core/src/services/http-scenario-actors.ts`) is a shared impersonation
|
|
12
|
+
secret: `HttpScenarioActor.login` POSTs `{ email, name, secret }` to
|
|
13
|
+
`/auth/sign-in/actor` and gets back a session. That looks like a master key, and
|
|
14
|
+
it deliberately is not one.
|
|
15
|
+
|
|
16
|
+
The Better Auth actor plugin on the other end upserts and signs in only user rows
|
|
17
|
+
flagged `actor: true`. Presenting the secret with a real customer's email does not
|
|
18
|
+
mint that customer's session — it is refused. The `actor` flag also flows into the
|
|
19
|
+
minted session, so audits and analytics can tell scenario traffic from human
|
|
20
|
+
traffic after the fact. The blast radius of a leaked actor secret is therefore the
|
|
21
|
+
synthetic actor population, not the user table.
|
|
22
|
+
|
|
23
|
+
**What this rules out:** widening the sign-in endpoint to accept any email "so
|
|
24
|
+
scenarios can test as a real user", and treating the actor secret as equivalent to
|
|
25
|
+
a session-signing key. It also rules out dropping the `actor` flag from the minted
|
|
26
|
+
session — the audit trail's ability to separate synthetic from real activity
|
|
27
|
+
depends on it.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Addon auth and tags only tighten, and resolve where the function runs
|
|
4
|
+
description: wireAddon auth and tags are applied in runPikkuFunc like scopes, but auth:false is ignored and tags resolve against the consuming app's tag groups rather than the addon package's
|
|
5
|
+
tags: addon, auth, tags, authorization
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Addon auth and tags only tighten, and resolve where the function runs
|
|
9
|
+
|
|
10
|
+
`wireAddon({ auth, tags })` was read only by `resolveAddonFunction` in
|
|
11
|
+
`rpc-runner.ts`, which covers the `namespace:function` RPC form alone. Every
|
|
12
|
+
direct wiring — the inspector writes the addon's package name onto http,
|
|
13
|
+
channel, schedule, queue, cli, trigger, gateway and mcp wirings — reached
|
|
14
|
+
`runPikkuFunc` with a `packageName` and neither value. That is the same hole
|
|
15
|
+
[addon scopes](./addon-scopes-are-resolved-where-the-function-runs.md) had, and
|
|
16
|
+
it is closed the same way: `runPikkuFunc` resolves both from the addon config.
|
|
17
|
+
|
|
18
|
+
`auth` merges as an OR and `auth: false` is ignored. The RPC path treats it as a
|
|
19
|
+
default (`addonConfig?.auth ?? options.requiresAuth`) because there the addon
|
|
20
|
+
config is the only statement of intent. On a direct wiring the route already
|
|
21
|
+
carries its own `auth`, so honouring `false` would let an addon *weaken* a gate
|
|
22
|
+
the app wrote — the inverse of what a wiring-level declaration should be able to
|
|
23
|
+
do. An addon may require a session the wiring did not; it may never waive one
|
|
24
|
+
the wiring did.
|
|
25
|
+
|
|
26
|
+
Tags resolve against the **root** tag groups, not the addon package's. A tag on
|
|
27
|
+
`wireAddon` is written by the consuming app, and `addTagMiddleware('admin', …)`
|
|
28
|
+
in that app registers under the root package. `combineMiddleware` looks tag
|
|
29
|
+
metadata up under the `packageName` it is given, which for an addon function is
|
|
30
|
+
the addon's own namespace — where the app's middleware does not exist. Resolving
|
|
31
|
+
addon tags to concrete middleware before the call and passing them as
|
|
32
|
+
`wireMiddleware` is what keeps `wireAddon({ tags: ['admin'] })` from being
|
|
33
|
+
silently inert, which is the failure mode the whole gate exists to avoid.
|
|
34
|
+
|
|
35
|
+
A function's own tags are unaffected: the inspector already emits them as
|
|
36
|
+
`{ type: 'tag' }` entries on the function and wiring meta, resolved under the
|
|
37
|
+
package that declared them. The `tags` argument `runPikkuFunc` accepts is
|
|
38
|
+
separate and still unused on every path.
|
|
39
|
+
|
|
40
|
+
**What this rules out:** honouring `auth: false` from an addon on a direct
|
|
41
|
+
wiring; resolving addon tags under the addon's `packageName`; and folding addon
|
|
42
|
+
tags into `funcInheritedMiddleware`, which would resolve them in the wrong
|
|
43
|
+
namespace and double-apply the function's own tags.
|
package/knowledge/decisions/security/addon-config-gates-apply-only-at-the-namespaced-rpc-boundary.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Addon auth and tag gates apply wherever the function runs, including inside the addon
|
|
4
|
+
description: wireAddon's auth and tags moved from the namespaced RPC boundary into runPikkuFunc, so they also apply to direct wirings and to bare intra-addon calls
|
|
5
|
+
tags: rpc, addon, auth
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Addon auth and tag gates apply wherever the function runs, including inside the addon
|
|
9
|
+
|
|
10
|
+
`ContextAwareRPCService.invokeAddonFunction` used to be the only place that
|
|
11
|
+
applied an addon's `addonConfig.auth` and `addonConfig.tags`, making them a
|
|
12
|
+
perimeter control on `rpc('namespace:fn')`. That perimeter had a hole in it: the
|
|
13
|
+
inspector writes the addon's package name onto http, channel, schedule, queue,
|
|
14
|
+
cli, trigger, gateway and mcp wirings, and every one of those runners calls
|
|
15
|
+
`runPikkuFunc` directly without resolving a namespace. A consumer who wrote
|
|
16
|
+
`wireAddon({ auth: true })` and then wired an addon function to a route got no
|
|
17
|
+
gate at all.
|
|
18
|
+
|
|
19
|
+
Both values now resolve in `runPikkuFunc`, the one point every path shares —
|
|
20
|
+
the same move, for the same reason, as
|
|
21
|
+
[addon scopes](./addon-scopes-are-resolved-where-the-function-runs.md). See
|
|
22
|
+
[addon auth and tags only tighten](./addon-auth-and-tags-only-tighten.md) for
|
|
23
|
+
the merge rules.
|
|
24
|
+
|
|
25
|
+
This replaces a consequence an earlier decision accepted: a bare `rpc('fn')`
|
|
26
|
+
made from inside an addon now re-applies the gate, because it reaches
|
|
27
|
+
`runPikkuFunc` with the addon's `packageName` like any other call. The earlier
|
|
28
|
+
reasoning — that the perimeter had already been passed, so re-checking would
|
|
29
|
+
gate internal calls on a consumer-facing setting — held only while the perimeter
|
|
30
|
+
was real. Once a direct wiring could enter the addon without passing any gate,
|
|
31
|
+
"already inside" stopped being something the runtime could infer, and the choice
|
|
32
|
+
became re-checking or trusting an entry that may never have happened.
|
|
33
|
+
|
|
34
|
+
In practice an intra-addon call inherits the entry point's session, so the auth
|
|
35
|
+
check passes wherever the entry was itself authenticated. What it does break is
|
|
36
|
+
an addon that wires `auth: true` and also runs its own sessionless internal
|
|
37
|
+
work — a scheduled task or queue worker inside the addon calling a sibling. Such
|
|
38
|
+
an addon should carry authorization on the function via
|
|
39
|
+
`pikkuFunc({ permissions })`, which has always been enforced on every path,
|
|
40
|
+
rather than on the consumer-facing `wireAddon` setting.
|
|
41
|
+
|
|
42
|
+
Re-checking was chosen over provenance because the marker that would make
|
|
43
|
+
"already inside" knowable — set by the runtime, unsettable by any caller outside
|
|
44
|
+
the process, threaded through all eight runners — is a design problem of its
|
|
45
|
+
own, and shipping it inside a security fix would have meant landing an untested
|
|
46
|
+
trust signal alongside the gate that depends on it. Adding that marker is
|
|
47
|
+
tracked separately; until it exists, re-checking is the only option that does
|
|
48
|
+
not trust an entry which may never have happened.
|
|
49
|
+
|
|
50
|
+
**What this rules out:** treating `addonConfig.auth` as a perimeter-only
|
|
51
|
+
control; and inferring "already inside the addon" from the wire, which a direct
|
|
52
|
+
wiring does not set.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Addon scopes are resolved where the function runs
|
|
4
|
+
description: wireAddon scopes are merged inside runPikkuFunc rather than at namespace resolution, because most wirings reach an addon function without ever resolving a namespace
|
|
5
|
+
tags: addon, scopes, authorization
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Addon scopes are resolved where the function runs
|
|
9
|
+
|
|
10
|
+
`wireAddon({ scopes })` names scopes every function in the addon's package
|
|
11
|
+
requires. `runPikkuFunc` calls `resolveAddonScopes(packageName,
|
|
12
|
+
addonInstance?.namespace)` and unions the result with the function's own
|
|
13
|
+
`scopes` before `verifyScopes`.
|
|
14
|
+
|
|
15
|
+
The obvious home for this is `resolveAddonFunction` in `rpc-runner.ts`, next to
|
|
16
|
+
where `auth` and `tags` are already merged from the addon config — but that
|
|
17
|
+
covers only the `namespace:function` RPC form. An addon function is reachable
|
|
18
|
+
without any namespace resolution: the inspector's `resolveAddonName` writes the
|
|
19
|
+
addon's package name onto the wiring meta whenever a wiring's `func` is an
|
|
20
|
+
identifier imported from a wired addon, and every runner (`http-runner`,
|
|
21
|
+
`mcp-runner`, channel, scheduler, queue, cli, trigger, gateway) then passes that
|
|
22
|
+
`packageName` straight to `runPikkuFunc`. `refHTTP` / `refChannel` / `refCLI`
|
|
23
|
+
contracts do the same through `registerHTTPRouteMeta`. A gate at namespace
|
|
24
|
+
resolution would leave every one of those doors open while reading as complete,
|
|
25
|
+
which is worse than no gate. `runPikkuFunc` is the one point all of them share.
|
|
26
|
+
|
|
27
|
+
Merging is a union, not an override, because `firstUnsatisfied` in `scopes.ts`
|
|
28
|
+
requires every listed scope. An addon scope is therefore an additional
|
|
29
|
+
requirement and can only narrow access — an addon can never weaken a function
|
|
30
|
+
that declares stricter scopes of its own. `ref('namespace:fn')` routes are
|
|
31
|
+
gated for the same reason from the other direction: the generated wrapper is a
|
|
32
|
+
local function that calls `rpc.invoke`, so the addon's scopes attach on the
|
|
33
|
+
inner call rather than the route.
|
|
34
|
+
|
|
35
|
+
When the caller carries an `addonInstance`, its namespace selects that
|
|
36
|
+
instance's scopes exactly. The direct-wiring paths know only a package name, so
|
|
37
|
+
`resolveAddonScopes` unions the scopes of every namespace the package is wired
|
|
38
|
+
under. One package wired twice with different scopes is rare; taking the
|
|
39
|
+
stricter reading keeps the unnamed path from becoming the weak one.
|
|
40
|
+
|
|
41
|
+
**What this rules out:** gating addon functions in `resolveAddonFunction`,
|
|
42
|
+
`resolveNamespace`, or any per-wiring runner; treating addon scopes as a
|
|
43
|
+
default that a function's own `scopes` replaces; resolving a package's scopes
|
|
44
|
+
by first matching namespace, the way `findAddonNamespaceForPackage` resolves
|
|
45
|
+
services; and reusing this for `wireRemoteAddon`, whose functions execute on the
|
|
46
|
+
host and are gated there.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Only a Symbol-branded framework result can request tool approval
|
|
4
|
+
description: Approval markers are trusted from the APPROVAL_REQUIRED Symbol on a forwardsApproval tool, never from a JSON key an LLM could emit
|
|
5
|
+
tags: ai-agent
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Only a Symbol-branded framework result can request tool approval
|
|
9
|
+
|
|
10
|
+
`checkForApprovals` in
|
|
11
|
+
`packages/core/src/wirings/ai-agent/ai-agent-stream.ts` honours a forwarded
|
|
12
|
+
approval only when both hold: the tool declares `forwardsApproval` (set solely by
|
|
13
|
+
framework code on the sub-agent delegating tools built in
|
|
14
|
+
`ai-agent-prepare.ts`), and its result carries the `APPROVAL_REQUIRED` unique
|
|
15
|
+
Symbol. The companion `__approvalRequired` string key exists for transport, but
|
|
16
|
+
is never what the decision reads.
|
|
17
|
+
|
|
18
|
+
A tool result is attacker-influenceable — a retrieved document, a third-party API
|
|
19
|
+
response, or a sub-agent's LLM-shaped `result.object`. All of those are plain
|
|
20
|
+
JSON, and plain JSON cannot carry a Symbol. Trusting the string key would let any
|
|
21
|
+
ordinary tool conjure a suspension and an approval prompt showing a tool name and
|
|
22
|
+
arguments of its choosing.
|
|
23
|
+
|
|
24
|
+
**What this rules out:** checking `'__approvalRequired' in result` as the
|
|
25
|
+
condition; replacing the Symbol with a string or numeric sentinel so results
|
|
26
|
+
survive JSON serialization; and setting `forwardsApproval` from user-supplied
|
|
27
|
+
tool configuration rather than from framework code.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Credential requests are trusted only when Symbol-branded
|
|
4
|
+
description: The string key is a wire field; the Symbol is the capability, and only core can mint it
|
|
5
|
+
tags: ai-agent
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Credential requests are trusted only when Symbol-branded
|
|
9
|
+
|
|
10
|
+
A tool result asking the run to suspend and prompt for a credential is honoured
|
|
11
|
+
only when it carries the `CREDENTIAL_REQUIRED` Symbol minted in
|
|
12
|
+
`ai-agent-prepare.ts`. `checkForCredentialRequests` in `ai-agent-stream.ts`
|
|
13
|
+
tests for that Symbol, never for the `__credentialRequired` string key that
|
|
14
|
+
travels beside it on the wire.
|
|
15
|
+
|
|
16
|
+
The distinction is the whole security property. Tool results are frequently
|
|
17
|
+
attacker-influenceable — a retrieved document, an echo from a third-party API,
|
|
18
|
+
LLM-authored content round-tripping through a tool — and any of those can carry
|
|
19
|
+
a string key. None can carry a Symbol, because a Symbol has no literal form and
|
|
20
|
+
does not survive JSON. Without the brand, an influenced tool result could
|
|
21
|
+
suspend the run and push a `credential-request` event with an attacker-chosen
|
|
22
|
+
`connectUrl`, which the client renders as a "Connect" button: a phishing
|
|
23
|
+
primitive inside the product's own UI. This mirrors the `APPROVAL_REQUIRED`
|
|
24
|
+
brand, which exists for the identical reason one function over.
|
|
25
|
+
|
|
26
|
+
The brand survives because the object is passed by reference the whole way —
|
|
27
|
+
core's `buildToolDefs` wrapper returns it, the Vercel adapter's `aiTool` hands
|
|
28
|
+
it back verbatim, and the AI SDK puts the raw value on the stream part rather
|
|
29
|
+
than the JSON form it builds separately for the model.
|
|
30
|
+
|
|
31
|
+
**What this rules out:** widening the check to `'__credentialRequired' in
|
|
32
|
+
result` for convenience, or introducing any path where a credential request is
|
|
33
|
+
reconstructed from parsed JSON rather than passed by reference — either one
|
|
34
|
+
silently converts the gate into a formality. Note the inverse holds for the
|
|
35
|
+
`credentialFilteredChannel` suppression later in the same file: that one
|
|
36
|
+
deliberately matches the *string* key, because it hides tool results from the
|
|
37
|
+
client and a broader match leaks less, not more.
|