@pikku/core 0.12.143 → 0.12.144
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/dist/analytics/analytics.d.ts +14 -0
- package/dist/analytics/analytics.js +14 -0
- package/dist/analytics/analytics.types.d.ts +1 -0
- package/dist/analytics/anonymous-analytics-identity.d.ts +1 -0
- package/dist/analytics/cookie-analytics-identity.d.ts +1 -0
- package/dist/analytics/mint-cookie.d.ts +1 -0
- package/dist/{wirings/channel/channel-middleware-runner.d.ts → channel-middleware-runner.d.ts} +17 -3
- package/dist/{wirings/channel/channel-middleware-runner.js → channel-middleware-runner.js} +24 -8
- package/dist/classification/data-classification.d.ts +13 -0
- package/dist/classification/secret-value.d.ts +7 -0
- package/dist/classification/secret-value.js +7 -0
- package/dist/crypto-utils.d.ts +93 -0
- package/dist/crypto-utils.js +92 -0
- package/dist/dev/hot-reload.d.ts +16 -0
- package/dist/dev/hot-reload.js +16 -1
- package/dist/dev/module-runner.js +7 -3
- package/dist/dev/reload-meta.js +1 -1
- package/dist/errors/error-handler.d.ts +9 -0
- package/dist/errors/error-handler.js +8 -0
- package/dist/errors/errors.d.ts +219 -0
- package/dist/errors/errors.js +227 -0
- package/dist/errors/serialized-error.d.ts +4 -0
- package/dist/function/abort-scope.d.ts +5 -0
- package/dist/function/function-meta.types.d.ts +20 -0
- package/dist/function/function-runner.d.ts +41 -0
- package/dist/function/function-runner.js +57 -11
- package/dist/function/functions.types.d.ts +59 -0
- package/dist/function/functions.types.js +23 -0
- package/dist/function/list.types.d.ts +4 -0
- package/dist/lifecycle.d.ts +12 -1
- package/dist/lifecycle.js +12 -1
- package/dist/middleware/addon-scope-cap.d.ts +4 -0
- package/dist/middleware/addon-scope-cap.js +7 -3
- package/dist/middleware/auth-apikey.js +3 -3
- package/dist/middleware/auth-bearer.js +5 -13
- package/dist/middleware/auth-cookie.js +3 -3
- package/dist/middleware/middleware-factories.d.ts +17 -0
- package/dist/middleware/middleware-factories.js +17 -0
- package/dist/middleware/middleware.types.d.ts +23 -0
- package/dist/middleware/remote-auth.d.ts +15 -0
- package/dist/middleware/remote-auth.js +18 -3
- package/dist/middleware/remote-jobs-secret.js +2 -10
- package/dist/middleware-runner.d.ts +7 -0
- package/dist/middleware-runner.js +23 -7
- package/dist/permissions.d.ts +13 -0
- package/dist/permissions.js +13 -0
- package/dist/pikku-state.d.ts +49 -0
- package/dist/pikku-state.js +49 -0
- package/dist/remote.js +20 -5
- package/dist/schema.d.ts +36 -0
- package/dist/schema.js +36 -0
- package/dist/services/agent-run-state-service.d.ts +8 -0
- package/dist/services/agent-runner-service.d.ts +24 -0
- package/dist/services/agent-storage-service.d.ts +8 -0
- package/dist/services/ai-embedding-service.d.ts +4 -0
- package/dist/services/audit-service.d.ts +48 -0
- package/dist/services/audit-service.js +22 -0
- package/dist/services/content-service.d.ts +34 -0
- package/dist/services/credential-wire-service.d.ts +9 -0
- package/dist/services/credential-wire-service.js +9 -0
- package/dist/services/deployment-service.d.ts +14 -0
- package/dist/services/email-service.d.ts +20 -0
- package/dist/services/email-template.d.ts +24 -0
- package/dist/services/email-template.js +12 -0
- package/dist/services/file-scenario-run-store.d.ts +5 -0
- package/dist/services/file-scenario-run-store.js +4 -0
- package/dist/services/gateway-service.d.ts +5 -0
- package/dist/services/in-memory-agent-run-state-service.d.ts +5 -0
- package/dist/services/in-memory-agent-run-state-service.js +5 -0
- package/dist/services/in-memory-lease-service.d.ts +5 -0
- package/dist/services/in-memory-lease-service.js +5 -0
- package/dist/services/in-memory-session-store.d.ts +4 -0
- package/dist/services/in-memory-session-store.js +4 -0
- package/dist/services/incoming-webhook-queue.d.ts +2 -0
- package/dist/services/incoming-webhook-queue.js +2 -0
- package/dist/services/incoming-webhook-service.d.ts +9 -1
- package/dist/services/incoming-webhook-service.js +1 -1
- package/dist/services/index.d.ts +1 -5
- package/dist/services/index.js +1 -5
- package/dist/services/jwt-service.d.ts +8 -0
- package/dist/services/lease-service.d.ts +5 -0
- package/dist/services/lease-service.js +1 -0
- package/dist/services/local-content-request-handler.d.ts +20 -0
- package/dist/services/local-content-request-handler.js +11 -0
- package/dist/services/local-content.d.ts +45 -0
- package/dist/services/local-content.js +35 -0
- package/dist/services/local-credential-service.d.ts +5 -0
- package/dist/services/local-credential-service.js +5 -0
- package/dist/services/local-email-service.d.ts +7 -0
- package/dist/services/local-email-service.js +7 -0
- package/dist/services/local-secrets.d.ts +8 -0
- package/dist/services/local-secrets.js +8 -0
- package/dist/services/local-variables.d.ts +6 -0
- package/dist/services/local-variables.js +6 -0
- package/dist/services/logger.d.ts +4 -0
- package/dist/services/logger.js +4 -0
- package/dist/services/meta-service.d.ts +38 -0
- package/dist/services/meta-service.js +6 -0
- package/dist/services/queue-webhook-service.d.ts +19 -0
- package/dist/services/queue-webhook-service.js +19 -0
- package/dist/services/remote-jobs.d.ts +8 -13
- package/dist/services/remote-jobs.js +3 -54
- package/dist/services/scenario-cookie-jar.d.ts +4 -0
- package/dist/services/scheduler-service.d.ts +13 -0
- package/dist/services/scheduler-service.js +8 -0
- package/dist/services/schema-service.d.ts +9 -0
- package/dist/services/scope-service.d.ts +10 -0
- package/dist/services/scoped-secret-service.d.ts +5 -0
- package/dist/services/scoped-secret-service.js +5 -0
- package/dist/services/secret-host-binding.d.ts +5 -0
- package/dist/services/secret-host-binding.js +5 -0
- package/dist/services/secret-service.d.ts +19 -1
- package/dist/services/secretless.d.ts +6 -0
- package/dist/services/secretless.js +6 -0
- package/dist/services/session-store.d.ts +5 -0
- package/dist/services/stub-tracker.d.ts +1 -0
- package/dist/services/temporary-file-service.d.ts +9 -0
- package/dist/services/temporary-file-service.js +9 -0
- package/dist/services/trigger-service.d.ts +4 -0
- package/dist/services/trigger-source-store.d.ts +13 -0
- package/dist/services/trigger-source-store.js +7 -0
- package/dist/services/typed-credential-service.d.ts +6 -0
- package/dist/services/typed-credential-service.js +5 -0
- package/dist/services/typed-secret-service.d.ts +12 -0
- package/dist/services/typed-secret-service.js +11 -0
- package/dist/services/typed-variables-service.d.ts +1 -0
- package/dist/services/user-session-service.d.ts +31 -1
- package/dist/services/user-session-service.js +29 -3
- package/dist/services/v8-coverage-service.d.ts +27 -0
- package/dist/services/v8-coverage-service.js +5 -0
- package/dist/services/variables-service.d.ts +8 -0
- package/dist/services/virtual-user-sign-in.d.ts +1 -0
- package/dist/services/virtual-user-statement.d.ts +8 -0
- package/dist/services/virtual-user-statement.js +4 -0
- package/dist/services/webhook-service.d.ts +25 -0
- package/dist/services/webhook-service.js +15 -0
- package/dist/services/workflow-service.d.ts +6 -0
- package/dist/test-utils.js +1 -1
- package/dist/testing/service-tests.d.ts +4 -0
- package/dist/time-utils.d.ts +15 -0
- package/dist/time-utils.js +14 -0
- package/dist/types/core.types.d.ts +80 -0
- package/dist/types/state.types.d.ts +4 -0
- package/dist/utils/hmac.d.ts +3 -0
- package/dist/utils/safe-fetch.d.ts +14 -0
- package/dist/utils/safe-fetch.js +13 -0
- package/dist/utils/stable-stringify.d.ts +11 -0
- package/dist/utils/stable-stringify.js +33 -0
- package/dist/utils.d.ts +28 -0
- package/dist/utils.js +22 -0
- package/dist/version.d.ts +7 -0
- package/dist/version.js +7 -0
- package/dist/wirings/addon/define-screens.d.ts +2 -0
- package/dist/wirings/addon/remote-addon-auth.d.ts +9 -0
- package/dist/wirings/addon/remote-addon-auth.js +5 -0
- package/dist/wirings/addon/wire-addon.d.ts +4 -0
- package/dist/wirings/addon/wire-remote-addon.d.ts +1 -0
- package/dist/wirings/agent/agent-agui.d.ts +14 -5
- package/dist/wirings/agent/agent-agui.js +17 -6
- package/dist/wirings/agent/agent-helpers.d.ts +61 -1
- package/dist/wirings/agent/agent-helpers.js +62 -2
- package/dist/wirings/agent/agent-interrupt.d.ts +5 -0
- package/dist/wirings/agent/agent-output.d.ts +20 -0
- package/dist/wirings/agent/agent-output.js +69 -0
- package/dist/wirings/agent/agent-prepare.d.ts +41 -0
- package/dist/wirings/agent/agent-prepare.js +38 -2
- package/dist/wirings/agent/agent-registry.d.ts +8 -0
- package/dist/wirings/agent/agent-registry.js +10 -4
- package/dist/wirings/agent/agent-runner.d.ts +33 -0
- package/dist/wirings/agent/agent-runner.js +40 -7
- package/dist/wirings/agent/agent-stream.d.ts +30 -0
- package/dist/wirings/agent/agent-stream.js +33 -11
- package/dist/wirings/agent/agent.types.d.ts +43 -0
- package/dist/wirings/agent/voice-input.d.ts +12 -0
- package/dist/wirings/agent/voice-input.js +12 -0
- package/dist/wirings/agent/voice-output.d.ts +14 -0
- package/dist/wirings/agent/voice-output.js +10 -0
- package/dist/wirings/agent-scorer/agent-scorer-judge.js +1 -2
- package/dist/wirings/agent-scorer/agent-scorer-registry.d.ts +10 -0
- package/dist/wirings/agent-scorer/agent-scorer-registry.js +10 -0
- package/dist/wirings/agent-scorer/agent-scorer-snapshots.d.ts +1 -0
- package/dist/wirings/agent-scorer/agent-scorer-snapshots.js +1 -0
- package/dist/wirings/agent-scorer/agent-scorer.types.d.ts +7 -0
- package/dist/wirings/channel/channel-common.js +1 -1
- package/dist/wirings/channel/channel-rpc.types.d.ts +5 -0
- package/dist/wirings/channel/channel-runner.d.ts +22 -0
- package/dist/wirings/channel/channel-runner.js +22 -0
- package/dist/wirings/channel/channel-store.d.ts +8 -0
- package/dist/wirings/channel/channel-store.js +7 -0
- package/dist/wirings/channel/channel.types.d.ts +18 -0
- package/dist/wirings/channel/define-channel-routes.d.ts +5 -0
- package/dist/wirings/channel/define-channel-routes.js +5 -0
- package/dist/wirings/channel/eventhub-service.d.ts +9 -0
- package/dist/wirings/channel/eventhub-store.d.ts +1 -0
- package/dist/wirings/channel/eventhub-store.js +1 -0
- package/dist/wirings/channel/index.d.ts +1 -1
- package/dist/wirings/channel/index.js +1 -1
- package/dist/wirings/channel/local/local-channel-handler.d.ts +1 -0
- package/dist/wirings/channel/local/local-channel-handler.js +1 -0
- package/dist/wirings/channel/local/local-channel-runner.d.ts +13 -0
- package/dist/wirings/channel/local/local-channel-runner.js +13 -0
- package/dist/wirings/channel/local/local-eventhub-service.d.ts +1 -0
- package/dist/wirings/channel/local/local-eventhub-service.js +1 -0
- package/dist/wirings/channel/log-channels.d.ts +1 -0
- package/dist/wirings/channel/log-channels.js +1 -0
- package/dist/wirings/channel/pikku-abstract-channel-handler.d.ts +5 -0
- package/dist/wirings/channel/pikku-abstract-channel-handler.js +5 -0
- package/dist/wirings/channel/serverless/serverless-channel-runner.d.ts +32 -0
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +31 -0
- package/dist/wirings/cli/channel/cli-channel-runner.d.ts +8 -0
- package/dist/wirings/cli/channel/cli-channel-runner.js +8 -0
- package/dist/wirings/cli/channel/cli-raw-channel-runner.d.ts +1 -0
- package/dist/wirings/cli/cli-runner.d.ts +43 -0
- package/dist/wirings/cli/cli-runner.js +43 -0
- package/dist/wirings/cli/command-parser.d.ts +13 -0
- package/dist/wirings/cli/command-parser.js +12 -0
- package/dist/wirings/credential/credential-overrides.d.ts +1 -0
- package/dist/wirings/credential/credential.types.d.ts +7 -0
- package/dist/wirings/credential/validate-credential-definitions.d.ts +7 -0
- package/dist/wirings/credential/validate-credential-definitions.js +7 -0
- package/dist/wirings/flag/cached-flag-source.d.ts +1 -0
- package/dist/wirings/flag/flag.types.d.ts +3 -0
- package/dist/wirings/gateway/gateway-runner.d.ts +23 -0
- package/dist/wirings/gateway/gateway-runner.js +23 -0
- package/dist/wirings/gateway/gateway.types.d.ts +3 -0
- package/dist/wirings/gateway/local-gateway-service.d.ts +10 -0
- package/dist/{services → wirings/gateway}/local-gateway-service.js +6 -2
- package/dist/wirings/http/http-routes.d.ts +21 -0
- package/dist/wirings/http/http-routes.js +11 -0
- package/dist/wirings/http/http-runner.d.ts +71 -0
- package/dist/wirings/http/http-runner.js +73 -5
- package/dist/wirings/http/http.types.d.ts +27 -0
- package/dist/wirings/http/index.d.ts +1 -0
- package/dist/wirings/http/index.js +1 -0
- package/dist/wirings/http/log-http-routes.d.ts +1 -0
- package/dist/wirings/http/log-http-routes.js +1 -0
- package/dist/wirings/http/merge-request-data.d.ts +12 -0
- package/dist/wirings/http/merge-request-data.js +42 -0
- package/dist/wirings/http/pikku-fetch-http-request.d.ts +1 -0
- package/dist/wirings/http/pikku-fetch-http-request.js +3 -32
- package/dist/wirings/http/pikku-fetch-http-response.d.ts +1 -0
- package/dist/wirings/http/pikku-fetch-http-response.js +1 -0
- package/dist/wirings/http/routers/http-router.d.ts +6 -0
- package/dist/wirings/http/routers/http-router.js +6 -0
- package/dist/wirings/http/web-request.d.ts +17 -0
- package/dist/wirings/http/web-request.js +17 -0
- package/dist/wirings/mcp/mcp-endpoint-registry.d.ts +7 -0
- package/dist/wirings/mcp/mcp-endpoint-registry.js +7 -0
- package/dist/wirings/mcp/mcp-runner.d.ts +63 -0
- package/dist/wirings/mcp/mcp-runner.js +62 -0
- package/dist/wirings/mcp/mcp.types.d.ts +12 -0
- package/dist/wirings/node/node.types.d.ts +4 -0
- package/dist/wirings/oauth2/oauth2.types.d.ts +2 -0
- package/dist/{services → wirings/queue}/in-memory-queue-service.d.ts +9 -1
- package/dist/{services → wirings/queue}/in-memory-queue-service.js +9 -1
- package/dist/wirings/queue/index.d.ts +1 -0
- package/dist/wirings/queue/index.js +1 -0
- package/dist/wirings/queue/queue-identity.js +2 -14
- package/dist/wirings/queue/queue-runner.d.ts +37 -0
- package/dist/wirings/queue/queue-runner.js +37 -0
- package/dist/wirings/queue/queue.types.d.ts +35 -0
- package/dist/wirings/queue/register-queue-helper.d.ts +12 -0
- package/dist/wirings/queue/register-queue-helper.js +11 -0
- package/dist/wirings/queue/remote-queue-job.d.ts +11 -0
- package/dist/wirings/queue/remote-queue-job.js +41 -0
- package/dist/wirings/queue/validate-worker-config.d.ts +1 -0
- package/dist/wirings/role/role.types.d.ts +3 -0
- package/dist/wirings/rpc/rpc-runner.d.ts +24 -0
- package/dist/wirings/rpc/rpc-runner.js +37 -2
- package/dist/wirings/rpc/rpc-types.d.ts +2 -0
- package/dist/wirings/scheduler/index.d.ts +1 -0
- package/dist/wirings/scheduler/index.js +1 -0
- package/dist/wirings/scheduler/log-schedulers.d.ts +1 -0
- package/dist/wirings/scheduler/log-schedulers.js +1 -0
- package/dist/wirings/scheduler/remote-scheduled-job.d.ts +11 -0
- package/dist/wirings/scheduler/remote-scheduled-job.js +20 -0
- package/dist/wirings/scheduler/scheduler-runner.d.ts +29 -0
- package/dist/wirings/scheduler/scheduler-runner.js +28 -0
- package/dist/wirings/scheduler/scheduler.types.d.ts +3 -0
- package/dist/wirings/scope/scope.types.d.ts +5 -0
- package/dist/wirings/secret/index.d.ts +2 -2
- package/dist/wirings/secret/index.js +1 -1
- package/dist/wirings/secret/secret.types.d.ts +26 -1
- package/dist/wirings/secret/secret.types.js +1 -0
- package/dist/wirings/secret/validate-secret-definitions.d.ts +8 -0
- package/dist/wirings/secret/validate-secret-definitions.js +15 -0
- package/dist/wirings/trigger/in-memory-trigger-service.d.ts +11 -0
- package/dist/{services → wirings/trigger}/in-memory-trigger-service.js +10 -3
- package/dist/wirings/trigger/index.d.ts +1 -1
- package/dist/wirings/trigger/pikku-trigger-service.d.ts +8 -3
- package/dist/wirings/trigger/pikku-trigger-service.js +14 -3
- package/dist/wirings/trigger/trigger-runner.d.ts +27 -2
- package/dist/wirings/trigger/trigger-runner.js +35 -2
- package/dist/wirings/trigger/trigger.types.d.ts +26 -4
- package/dist/wirings/trigger/webhook-source-runner.d.ts +24 -0
- package/dist/wirings/trigger/webhook-source-runner.js +19 -0
- package/dist/wirings/trigger/webhook-source.types.d.ts +12 -2
- package/dist/wirings/trigger/webhook-source.types.js +1 -1
- package/dist/wirings/variable/validate-variable-definitions.d.ts +7 -0
- package/dist/wirings/variable/validate-variable-definitions.js +7 -0
- package/dist/wirings/variable/variable.types.d.ts +7 -0
- package/dist/wirings/virtual-user/conversation/conversation.types.d.ts +5 -0
- package/dist/wirings/virtual-user/conversation/run-conversation.d.ts +6 -0
- package/dist/wirings/virtual-user/conversation/run-conversation.js +1 -1
- package/dist/{services → wirings/virtual-user}/http-virtual-users.d.ts +4 -3
- package/dist/{services → wirings/virtual-user}/http-virtual-users.js +6 -6
- package/dist/wirings/virtual-user/index.d.ts +1 -1
- package/dist/wirings/virtual-user/index.js +1 -1
- package/dist/wirings/virtual-user/run-virtual-user.d.ts +2 -1
- package/dist/wirings/virtual-user/run-virtual-user.js +1 -14
- package/dist/wirings/virtual-user/virtual-user-declaration.types.d.ts +4 -0
- package/dist/wirings/virtual-user/virtual-user-scaffold.d.ts +10 -1
- package/dist/wirings/virtual-user/virtual-user-scaffold.js +5 -0
- package/dist/wirings/virtual-user/virtual-user-schedule.d.ts +5 -0
- package/dist/wirings/virtual-user/virtual-user-schedule.js +1 -0
- package/dist/wirings/virtual-user/virtual-user-target.d.ts +1 -0
- package/dist/wirings/webhook/define-outgoing-webhook.d.ts +20 -0
- package/dist/wirings/webhook/define-outgoing-webhook.js +9 -0
- package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +8 -4
- package/dist/wirings/workflow/dsl/workflow-runner.d.ts +7 -0
- package/dist/wirings/workflow/dsl/workflow-runner.js +7 -0
- package/dist/wirings/workflow/feature.d.ts +12 -0
- package/dist/wirings/workflow/feature.js +12 -0
- package/dist/wirings/workflow/graph/graph-node.d.ts +5 -0
- package/dist/wirings/workflow/graph/graph-node.js +5 -0
- package/dist/wirings/workflow/graph/template.d.ts +6 -0
- package/dist/wirings/workflow/graph/template.js +5 -0
- package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +12 -0
- package/dist/wirings/workflow/graph/wire-workflow-graph.js +10 -0
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +11 -0
- package/dist/wirings/workflow/graph/workflow-graph.types.js +1 -0
- package/dist/{services → wirings/workflow}/in-memory-workflow-service.d.ts +8 -3
- package/dist/{services → wirings/workflow}/in-memory-workflow-service.js +9 -4
- package/dist/wirings/workflow/pikku-scenario-service.d.ts +1 -1
- package/dist/wirings/workflow/pikku-scenario-service.js +2 -2
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +1 -0
- package/dist/wirings/workflow/pikku-workflow-service.js +1 -0
- package/dist/wirings/workflow/run-timeline.d.ts +21 -0
- package/dist/wirings/workflow/run-timeline.js +15 -7
- package/dist/wirings/workflow/scenario-coverage.d.ts +1 -0
- package/dist/wirings/workflow/scenario-poll.d.ts +1 -0
- package/dist/wirings/workflow/scenario-prose.d.ts +6 -0
- package/dist/wirings/workflow/scenario-prose.js +6 -0
- package/dist/wirings/workflow/scenario-run.types.d.ts +3 -0
- package/dist/wirings/workflow/scenario-step.types.d.ts +1 -0
- package/dist/wirings/workflow/scenario-step.types.js +1 -0
- package/dist/wirings/workflow/scenario-surface.js +1 -13
- package/dist/wirings/workflow/scenario.types.d.ts +6 -0
- package/dist/wirings/workflow/workflow-approval-policy.d.ts +6 -0
- package/dist/wirings/workflow/workflow-approval-policy.js +6 -0
- package/dist/wirings/workflow/workflow-constants.d.ts +7 -1
- package/dist/wirings/workflow/workflow-constants.js +10 -1
- package/dist/wirings/workflow/workflow-errors.d.ts +13 -0
- package/dist/wirings/workflow/workflow-errors.js +13 -0
- package/dist/wirings/workflow/workflow-invocation-id.d.ts +4 -0
- package/dist/wirings/workflow/workflow-invocation-id.js +4 -0
- package/dist/wirings/workflow/workflow-queue-workers.d.ts +3 -0
- package/dist/wirings/workflow/workflow-run-ownership.d.ts +1 -0
- package/dist/wirings/workflow/workflow-run-ownership.js +1 -0
- package/dist/wirings/workflow/workflow-status-stream.d.ts +1 -0
- package/dist/wirings/workflow/workflow-unwind-plan.js +2 -7
- package/dist/wirings/workflow/workflow.types.d.ts +40 -0
- package/package.json +26 -9
- package/CHANGELOG.md +0 -6978
- package/dist/services/in-memory-trigger-service.d.ts +0 -4
- package/dist/services/local-gateway-service.d.ts +0 -6
- package/dist/utils/hash.d.ts +0 -2
- package/dist/utils/hash.js +0 -23
- package/knowledge/decisions/index.md +0 -19
- package/knowledge/decisions/internals/a-credential-name-declared-twice-must-agree-on-schema-and-type.md +0 -29
- package/knowledge/decisions/internals/a-grant-can-name-a-scope-declared-without-its-addon.md +0 -29
- package/knowledge/decisions/internals/a-held-run-is-woken-later-not-retried.md +0 -28
- package/knowledge/decisions/internals/a-latency-budget-is-asserted-by-its-cause.md +0 -32
- package/knowledge/decisions/internals/a-non-streaming-agent-run-registers-with-agentrunstate-too.md +0 -22
- package/knowledge/decisions/internals/a-reset-suite-makes-the-dev-seed-the-fixture.md +0 -50
- package/knowledge/decisions/internals/a-resumed-agent-turn-is-as-interruptible-as-the-first.md +0 -20
- package/knowledge/decisions/internals/a-scenario-step-template-is-offered-unfilled.md +0 -21
- package/knowledge/decisions/internals/a-scheduled-task-writes-its-caller-session-before-it-runs.md +0 -22
- package/knowledge/decisions/internals/a-secret-set-in-memory-shadows-the-variable-of-the-same-name.md +0 -28
- package/knowledge/decisions/internals/a-secret-that-fails-to-decrypt-fails-the-whole-read.md +0 -49
- package/knowledge/decisions/internals/a-virtual-user-acts-through-invokeraw-so-a-refusal-is-data.md +0 -32
- package/knowledge/decisions/internals/a-virtual-user-cadence-is-a-row-not-a-timer.md +0 -66
- package/knowledge/decisions/internals/a-virtual-user-converse-signs-in-before-its-first-turn.md +0 -24
- package/knowledge/decisions/internals/a-virtual-user-decides-whether-to-trust-memory-once-per-turn.md +0 -21
- package/knowledge/decisions/internals/a-virtual-user-email-is-computed-with-the-run-id-as-a-sub-address.md +0 -34
- package/knowledge/decisions/internals/a-virtual-user-run-is-not-a-workflow-but-it-needs-a-trigger.md +0 -65
- package/knowledge/decisions/internals/a-wall-clock-threshold-is-a-load-test-in-disguise.md +0 -49
- package/knowledge/decisions/internals/a-workflow-wire-is-built-from-the-run-not-from-the-rpc-service.md +0 -45
- package/knowledge/decisions/internals/addon-package-roots-resolve-by-walking-node-module-search-paths.md +0 -26
- package/knowledge/decisions/internals/addon-pikku-meta-ships-at-the-package-root-or-under-dist.md +0 -32
- package/knowledge/decisions/internals/addon-singleton-services-are-cached-per-namespace-not-per-package.md +0 -33
- package/knowledge/decisions/internals/addon-workflow-names-are-prefixed-with-the-consumer-namespace.md +0 -28
- package/knowledge/decisions/internals/agent-agui-bridge-obeys-the-client-ordering-contract.md +0 -29
- package/knowledge/decisions/internals/agent-audio-chunks-carry-the-format-the-provider-returned.md +0 -20
- package/knowledge/decisions/internals/agent-context-waits-for-a-tool-result-still-being-written.md +0 -21
- package/knowledge/decisions/internals/agent-credential-suspensions-hide-the-tool-result.md +0 -26
- package/knowledge/decisions/internals/agent-delegate-and-supervise-hide-different-text.md +0 -26
- package/knowledge/decisions/internals/agent-llm-tool-arguments-have-nulls-stripped.md +0 -23
- package/knowledge/decisions/internals/agent-model-config-stays-a-single-resolution-seam.md +0 -25
- package/knowledge/decisions/internals/agent-onerror-hooks-cannot-change-the-failure.md +0 -22
- package/knowledge/decisions/internals/agent-runner-methods-must-keep-their-receiver.md +0 -22
- package/knowledge/decisions/internals/agent-speech-travels-as-a-custom-agui-event.md +0 -22
- package/knowledge/decisions/internals/agent-stream-persistence-is-best-effort.md +0 -27
- package/knowledge/decisions/internals/agent-sub-agents-inherit-the-parent-context-block.md +0 -26
- package/knowledge/decisions/internals/agent-tool-execute-failures-are-logged-unconditionally.md +0 -25
- package/knowledge/decisions/internals/agent-voice-input-transcribes-audio-parts-in-place.md +0 -22
- package/knowledge/decisions/internals/agent-working-memory-is-persisted-only-when-valid.md +0 -25
- package/knowledge/decisions/internals/an-addon-scope-root-loses-to-a-root-the-host-already-declares.md +0 -39
- package/knowledge/decisions/internals/an-agent-interrupt-is-not-a-failure.md +0 -23
- package/knowledge/decisions/internals/an-agent-is-offered-under-its-registry-key-and-only-within-the-virtual-users-scopes.md +0 -27
- package/knowledge/decisions/internals/an-agent-run-owned-by-another-instance-says-so.md +0 -25
- package/knowledge/decisions/internals/an-agent-stream-send-must-return-the-inner-sends-promise.md +0 -22
- package/knowledge/decisions/internals/an-empty-text-part-is-omitted-from-an-agent-message.md +0 -20
- package/knowledge/decisions/internals/an-empty-transcript-is-not-recorded.md +0 -22
- package/knowledge/decisions/internals/an-oauth2-credential-implies-an-optional-app-secret.md +0 -26
- package/knowledge/decisions/internals/an-unref-d-timer-cannot-be-awaited-under-node-test.md +0 -66
- package/knowledge/decisions/internals/analytics-identity-resolvers-run-in-declared-order.md +0 -22
- package/knowledge/decisions/internals/channel-message-handlers-accept-three-config-shapes.md +0 -30
- package/knowledge/decisions/internals/channel-middleware-caches-only-statically-resolved-middleware.md +0 -31
- package/knowledge/decisions/internals/channel-state-accessors-are-unsound-generics-that-every-implementation-asserts.md +0 -33
- package/knowledge/decisions/internals/channel-state-is-per-socket-session-state-is-per-user.md +0 -29
- package/knowledge/decisions/internals/channel-user-id-is-persisted-after-onconnect-middleware-runs.md +0 -28
- package/knowledge/decisions/internals/cli-option-names-are-camelcase-in-state-and-kebab-on-the-command-line.md +0 -27
- package/knowledge/decisions/internals/cli-parse-errors-are-routed-by-message-prefix.md +0 -28
- package/knowledge/decisions/internals/cli-stdout-is-reserved-for-machine-readable-output.md +0 -34
- package/knowledge/decisions/internals/cli-unknown-long-options-warn-instead-of-failing.md +0 -29
- package/knowledge/decisions/internals/core-column-form-is-an-axis-of-its-own.md +0 -84
- package/knowledge/decisions/internals/core-data-classification-brand-is-an-optional-property.md +0 -41
- package/knowledge/decisions/internals/core-function-runner-restores-the-wire-fields-it-overwrites.md +0 -44
- package/knowledge/decisions/internals/core-hot-reload-merges-generated-meta-never-replaces-it.md +0 -39
- package/knowledge/decisions/internals/core-hot-reload-owns-its-module-registry.md +0 -42
- package/knowledge/decisions/internals/core-middleware-order-is-scope-then-priority.md +0 -39
- package/knowledge/decisions/internals/core-schema-defaults-apply-on-every-transport.md +0 -43
- package/knowledge/decisions/internals/core-scopes-are-an-and-gate-separate-from-permissions.md +0 -38
- package/knowledge/decisions/internals/core-state-is-a-global-map-written-only-at-registration-time.md +0 -44
- package/knowledge/decisions/internals/email-meta-is-read-uncached-because-codegen-rewrites-it-mid-session.md +0 -27
- package/knowledge/decisions/internals/feature-flag-declarations-refuse-an-empty-anyof-and-conflicting-scopes.md +0 -22
- package/knowledge/decisions/internals/feature-flags-fail-open-and-never-enforce-access.md +0 -28
- package/knowledge/decisions/internals/flag-sync-rewrites-only-the-declared-text.md +0 -24
- package/knowledge/decisions/internals/gateway-adapters-resolve-lazily-and-are-promise-cached.md +0 -32
- package/knowledge/decisions/internals/gateway-listener-middleware-runs-without-an-rpc-on-the-wire.md +0 -43
- package/knowledge/decisions/internals/gateway-webhook-challenges-echo-bytes-not-json.md +0 -28
- package/knowledge/decisions/internals/gateway-wiring-is-a-meta-wiring-over-http-and-channels.md +0 -31
- package/knowledge/decisions/internals/generated-src-paths-in-pikku-meta-are-absolute.md +0 -26
- package/knowledge/decisions/internals/global-middleware-resolves-from-the-root-namespace-too.md +0 -32
- package/knowledge/decisions/internals/hot-reload-reads-the-changed-source-never-a-compiled-copy.md +0 -38
- package/knowledge/decisions/internals/hot-reload-writes-into-the-function-map-captured-at-startup.md +0 -26
- package/knowledge/decisions/internals/http-request-bodies-are-read-once-and-shared.md +0 -32
- package/knowledge/decisions/internals/http-route-groups-cascade-config-in-a-fixed-order.md +0 -28
- package/knowledge/decisions/internals/http-router-matches-normalized-paths-but-returns-registered-ones.md +0 -30
- package/knowledge/decisions/internals/http-runner-logs-through-a-trace-scoped-logger-functions-do-not.md +0 -26
- package/knowledge/decisions/internals/http-set-cookie-headers-are-appended-never-joined.md +0 -28
- package/knowledge/decisions/internals/http-sse-streams-flush-headers-only-after-middleware.md +0 -32
- package/knowledge/decisions/internals/http-wiring-without-metadata-is-skipped-not-fatal.md +0 -26
- package/knowledge/decisions/internals/in-a-scenario-a-4xx-is-data-not-an-exception.md +0 -25
- package/knowledge/decisions/internals/in-memory-workflow-history-aliases-the-live-step-object.md +0 -26
- package/knowledge/decisions/internals/index.md +0 -182
- package/knowledge/decisions/internals/istanbul-statement-counts-attach-to-the-start-line-only.md +0 -25
- package/knowledge/decisions/internals/local-trigger-and-gateway-services-assume-a-single-process.md +0 -26
- package/knowledge/decisions/internals/mcp-wire-names-are-assigned-over-the-whole-registry.md +0 -39
- package/knowledge/decisions/internals/node-only-builtins-are-imported-dynamically.md +0 -24
- package/knowledge/decisions/internals/one-project-shape-check-two-validators.md +0 -53
- package/knowledge/decisions/internals/only-exposed-functions-enter-a-virtual-user-catalogue.md +0 -21
- package/knowledge/decisions/internals/queue-group-concurrency-keeps-one-shared-queue-fair.md +0 -28
- package/knowledge/decisions/internals/queue-jobs-always-carry-an-explicit-attempts-count.md +0 -27
- package/knowledge/decisions/internals/remote-addons-dispatch-over-http-instead-of-local-meta.md +0 -31
- package/knowledge/decisions/internals/role-names-cannot-contain-the-scope-separator.md +0 -30
- package/knowledge/decisions/internals/rpc-names-resolve-through-package-scope-before-root.md +0 -32
- package/knowledge/decisions/internals/scenario-agent-calls-sign-in-on-401-only.md +0 -31
- package/knowledge/decisions/internals/scenario-given-and-when-are-sugar-but-then-is-not.md +0 -24
- package/knowledge/decisions/internals/scenario-meta-lives-apart-from-app-meta-but-merges-when-read-off-disk.md +0 -26
- package/knowledge/decisions/internals/scenario-steps-return-drained-response-records.md +0 -27
- package/knowledge/decisions/internals/scenarios-live-in-files-named-for-them.md +0 -48
- package/knowledge/decisions/internals/scope-roots-may-be-co-declared-by-an-addon-and-its-host-app.md +0 -30
- package/knowledge/decisions/internals/serverless-channel-disconnect-must-tolerate-a-missing-channel.md +0 -28
- package/knowledge/decisions/internals/side-effects-are-an-allowlist-not-a-boolean.md +0 -34
- package/knowledge/decisions/internals/speech-synthesis-picks-a-voice-per-sentence-and-warns-once.md +0 -24
- package/knowledge/decisions/internals/the-agent-done-event-goes-through-the-middleware-and-is-awaited.md +0 -26
- package/knowledge/decisions/internals/the-api-report-pins-members-not-just-names.md +0 -43
- package/knowledge/decisions/internals/the-core-scope-validator-refuses-separator-wildcard-and-empty-segments.md +0 -22
- package/knowledge/decisions/internals/the-dev-queue-copies-prod-timing-and-serialization-semantics.md +0 -30
- package/knowledge/decisions/internals/the-ecosystem-entry-point-carries-the-adapter-surface.md +0 -83
- package/knowledge/decisions/internals/the-embedding-model-is-pinned-per-service-and-doc-query-embedding-is-split.md +0 -29
- package/knowledge/decisions/internals/the-in-memory-workflow-service-is-inline-only-and-single-process.md +0 -27
- package/knowledge/decisions/internals/the-kek-salt-is-scoped-to-the-key-version.md +0 -40
- package/knowledge/decisions/internals/the-mcp-handshake-is-challenged-only-when-every-target-is-gated.md +0 -29
- package/knowledge/decisions/internals/the-middleware-resolution-cache-is-deliberately-unbounded.md +0 -40
- package/knowledge/decisions/internals/the-per-invocation-rpc-view-is-a-class.md +0 -40
- package/knowledge/decisions/internals/the-pikku-user-id-resolves-in-a-fixed-order.md +0 -24
- package/knowledge/decisions/internals/the-runner-resolves-wire-services-itself.md +0 -31
- package/knowledge/decisions/internals/the-schema-service-is-never-stubbed.md +0 -26
- package/knowledge/decisions/internals/the-transcript-event-is-sent-ahead-of-the-run.md +0 -25
- package/knowledge/decisions/internals/the-virtual-user-catalogue-is-the-only-gate-on-what-may-be-called.md +0 -21
- package/knowledge/decisions/internals/the-virtual-user-prompt-says-json-because-of-json-object-mode.md +0 -22
- package/knowledge/decisions/internals/the-virtual-user-runtime-is-exported-from-the-virtual-user-entry-point.md +0 -28
- package/knowledge/decisions/internals/the-worker-disposition-is-the-one-that-is-not-testing.md +0 -22
- package/knowledge/decisions/internals/thread-history-records-the-transcript-not-the-audio.md +0 -25
- package/knowledge/decisions/internals/trigger-declaration-is-split-from-trigger-source.md +0 -33
- package/knowledge/decisions/internals/typed-secret-service-caches-for-the-process-lifetime.md +0 -26
- package/knowledge/decisions/internals/validate-checks-virtual-users-through-a-shared-module.md +0 -43
- package/knowledge/decisions/internals/validate-runs-checks-by-precondition.md +0 -115
- package/knowledge/decisions/internals/virtual-user-conversation-drives-the-target-through-a-transport-seam.md +0 -24
- package/knowledge/decisions/internals/virtual-user-conversation-verdicts-are-llm-self-evaluations.md +0 -25
- package/knowledge/decisions/internals/virtual-user-conversations-seed-a-hidden-kickoff-message.md +0 -23
- package/knowledge/decisions/internals/virtual-user-step-order-comes-from-insertion-order.md +0 -21
- package/knowledge/decisions/internals/virtual-users-are-declared-in-one-definevirtualusers-call-per-codebase.md +0 -30
- package/knowledge/decisions/internals/voice-output-speaks-unless-voice-input-explicitly-says-otherwise.md +0 -24
- package/knowledge/decisions/internals/webhook-delivery-history-records-every-attempt-best-effort.md +0 -26
- package/knowledge/decisions/internals/webhook-service-collaborators-are-constructor-args-not-locator-lookups.md +0 -25
- package/knowledge/decisions/internals/whether-a-run-is-inline-is-read-from-the-run-record.md +0 -58
- package/knowledge/decisions/internals/wiring-registries-erase-the-generics-their-wire-functions-capture.md +0 -35
- package/knowledge/decisions/internals/workflow-approval-expiry-is-decided-from-a-recorded-deadline.md +0 -34
- package/knowledge/decisions/internals/workflow-core-never-imports-a-browser-driver.md +0 -42
- package/knowledge/decisions/internals/workflow-dsl-meta-separates-runtime-expressions-from-literals.md +0 -38
- package/knowledge/decisions/internals/workflow-features-resolve-scenarios-by-object-identity.md +0 -29
- package/knowledge/decisions/internals/workflow-graph-inline-and-queued-runs-share-one-planner.md +0 -42
- package/knowledge/decisions/internals/workflow-graph-node-notes-are-excluded-from-the-graph-hash.md +0 -25
- package/knowledge/decisions/internals/workflow-inline-runs-report-their-run-id-before-they-can-fail.md +0 -29
- package/knowledge/decisions/internals/workflow-invocation-id-is-the-dedupe-key-not-step-id.md +0 -43
- package/knowledge/decisions/internals/workflow-queued-step-dispatch-requires-an-explicit-opt-in.md +0 -29
- package/knowledge/decisions/internals/workflow-queues-are-per-workflow-by-default.md +0 -42
- package/knowledge/decisions/internals/workflow-repeated-step-names-get-an-ordinal-suffix.md +0 -33
- package/knowledge/decisions/internals/workflow-replay-reads-its-steps-once-and-caches-only-the-immutable-half.md +0 -32
- package/knowledge/decisions/internals/workflow-retries-are-owned-by-the-workflow-not-the-queue.md +0 -31
- package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md +0 -39
- package/knowledge/decisions/internals/workflow-run-mirror-is-never-a-source-of-truth.md +0 -29
- package/knowledge/decisions/internals/workflow-run-polling-backs-off-to-the-callers-ceiling.md +0 -33
- package/knowledge/decisions/internals/workflow-run-timeline-is-a-pure-fold-over-durable-history.md +0 -37
- package/knowledge/decisions/internals/workflow-scenario-assertions-never-retry-and-record-one-step.md +0 -54
- package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md +0 -43
- package/knowledge/decisions/internals/workflow-scenario-prose-is-rendered-from-typed-calls-not-parsed-from-english.md +0 -32
- package/knowledge/decisions/internals/workflow-scenario-quarantine-reason-lives-in-code.md +0 -18
- package/knowledge/decisions/internals/workflow-scenario-step-targets-are-string-literals-for-the-inspector.md +0 -34
- package/knowledge/decisions/internals/workflow-step-compensation-runs-as-its-own-durable-step.md +0 -29
- package/knowledge/decisions/internals/workflow-step-dispatch-failure-is-transient-not-a-run-failure.md +0 -33
- package/knowledge/decisions/internals/workflow-step-lock-is-held-only-to-claim-the-step.md +0 -34
- package/knowledge/decisions/internals/workflow-step-rpc-name-is-provenance-only.md +0 -34
- package/knowledge/decisions/internals/workflow-suspend-and-approval-reasons-are-durable-step-identities.md +0 -38
- package/knowledge/decisions/internals/workflow-suspended-runs-keep-their-in-process-context.md +0 -30
- package/knowledge/decisions/security/a-bearer-token-checked-against-a-secret-reads-it-per-request.md +0 -26
- package/knowledge/decisions/security/a-call-without-a-session-raises-missing-session-not-forbidden.md +0 -20
- package/knowledge/decisions/security/a-caller-cookie-wins-over-the-jar-for-the-same-name.md +0 -23
- package/knowledge/decisions/security/a-channel-lifecycle-acts-as-the-socket-upgrade-session.md +0 -16
- package/knowledge/decisions/security/a-channel-requires-a-session-unless-it-says-auth-false.md +0 -26
- package/knowledge/decisions/security/a-credential-read-path-follows-its-declared-type-not-absence.md +0 -32
- package/knowledge/decisions/security/a-credential-type-is-a-literal-the-inspector-checks-at-declaration.md +0 -27
- package/knowledge/decisions/security/a-dropped-audit-write-is-always-logged.md +0 -28
- package/knowledge/decisions/security/a-first-party-cookie-is-written-only-after-its-purposes-consent.md +0 -33
- package/knowledge/decisions/security/a-function-never-receives-the-secret-service.md +0 -37
- package/knowledge/decisions/security/a-graph-run-starts-at-an-entry-node-the-graph-declared.md +0 -33
- package/knowledge/decisions/security/a-permission-gets-a-wire-it-cannot-reply-on.md +0 -33
- package/knowledge/decisions/security/a-public-function-says-so-with-auth-false.md +0 -34
- package/knowledge/decisions/security/a-readonly-session-reaches-only-readonly-functions.md +0 -25
- package/knowledge/decisions/security/a-scaffold-flag-says-a-surface-exists-not-who-may-call-it.md +0 -52
- package/knowledge/decisions/security/a-scheduled-virtual-user-run-needs-no-admin-at-run-time.md +0 -27
- package/knowledge/decisions/security/a-scoped-credential-view-is-limited-to-declared-names.md +0 -26
- package/knowledge/decisions/security/a-scoped-secret-view-reads-only-declared-keys-and-never-writes.md +0 -25
- package/knowledge/decisions/security/a-secret-is-sent-only-to-the-hosts-it-declares.md +0 -29
- package/knowledge/decisions/security/a-step-can-name-an-identity-no-virtual-user-holds-through-per-call-headers.md +0 -25
- package/knowledge/decisions/security/a-step-runs-the-function-the-workflow-dispatched-it-with.md +0 -37
- package/knowledge/decisions/security/a-stopped-run-by-id-skips-the-ownership-check.md +0 -24
- package/knowledge/decisions/security/a-vault-secret-redacts-on-serialization-and-throws-on-coercion.md +0 -29
- package/knowledge/decisions/security/a-virtual-user-catalogue-entry-is-filtered-by-scope-and-approval-is-denied-by-default.md +0 -30
- package/knowledge/decisions/security/a-virtual-user-environment-fails-closed.md +0 -38
- package/knowledge/decisions/security/a-virtual-user-is-never-offered-a-step-that-would-forge-its-own-oracle.md +0 -27
- package/knowledge/decisions/security/a-virtual-user-never-runs-against-production.md +0 -23
- package/knowledge/decisions/security/a-virtual-user-reads-its-roles-from-the-apps-own-rpc-before-better-auth.md +0 -27
- package/knowledge/decisions/security/a-virtual-user-run-treats-an-unresolved-environment-as-production.md +0 -41
- package/knowledge/decisions/security/a-virtual-user-scopes-are-expanded-from-its-roles-once-at-run-preparation.md +0 -25
- package/knowledge/decisions/security/a-virtual-user-whose-roles-drift-from-the-declaration-refuses-to-run.md +0 -32
- package/knowledge/decisions/security/a-workflow-run-is-read-and-approved-by-its-owner.md +0 -50
- package/knowledge/decisions/security/addon-auth-and-tags-only-tighten.md +0 -43
- package/knowledge/decisions/security/addon-config-gates-apply-only-at-the-namespaced-rpc-boundary.md +0 -52
- package/knowledge/decisions/security/addon-scopes-are-resolved-where-the-function-runs.md +0 -46
- package/knowledge/decisions/security/addon-screen-scopes-hide-and-do-not-enforce.md +0 -20
- package/knowledge/decisions/security/agent-approval-forwarding-requires-a-symbol-brand.md +0 -27
- package/knowledge/decisions/security/agent-credential-requests-are-symbol-branded.md +0 -37
- package/knowledge/decisions/security/agent-gate-requires-a-session-only-when-auth-is-true.md +0 -31
- package/knowledge/decisions/security/agent-ownership-failures-never-echo-the-resource.md +0 -23
- package/knowledge/decisions/security/agent-resume-re-runs-the-authorization-gate.md +0 -22
- package/knowledge/decisions/security/agent-sessionless-deployments-have-no-thread-ownership.md +0 -39
- package/knowledge/decisions/security/agent-thread-ownership-composes-the-session-principal.md +0 -30
- package/knowledge/decisions/security/agent-tool-filtering-reads-the-live-function-config.md +0 -24
- package/knowledge/decisions/security/an-addon-header-can-only-narrow-the-session.md +0 -26
- package/knowledge/decisions/security/an-addon-instance-reads-only-the-secrets-and-credentials-it-is-named.md +0 -33
- package/knowledge/decisions/security/an-addon-may-reach-only-itself-and-the-addons-it-uses.md +0 -16
- package/knowledge/decisions/security/an-agent-approval-is-claimed-before-the-tool-runs.md +0 -33
- package/knowledge/decisions/security/an-api-key-is-jwt-decoded-into-the-session.md +0 -26
- package/knowledge/decisions/security/an-approval-answer-outlives-the-run-it-answered.md +0 -59
- package/knowledge/decisions/security/an-empty-owners-constraint-matches-nothing.md +0 -30
- package/knowledge/decisions/security/an-exposed-ungated-function-is-a-codegen-warning.md +0 -52
- package/knowledge/decisions/security/an-external-virtual-user-caller-presents-one-signed-statement.md +0 -38
- package/knowledge/decisions/security/an-inbound-webhook-source-dispatches-only-verified-requests.md +0 -31
- package/knowledge/decisions/security/an-mcp-call-with-no-http-request-stays-anonymous.md +0 -18
- package/knowledge/decisions/security/an-mcp-refusal-is-decided-before-dispatch.md +0 -48
- package/knowledge/decisions/security/an-oauth2-credential-is-read-by-its-account-row.md +0 -40
- package/knowledge/decisions/security/an-omitted-user-id-addresses-the-platform-credential.md +0 -32
- package/knowledge/decisions/security/an-upload-is-counted-as-it-arrives-not-buffered-then-measured.md +0 -24
- package/knowledge/decisions/security/analytics-identity-is-stamped-from-the-session-not-the-event.md +0 -24
- package/knowledge/decisions/security/app-access-is-a-scope-tree-synthesised-from-virtual-users.md +0 -26
- package/knowledge/decisions/security/approval-policy-decides-who-answers-a-tool-call.md +0 -27
- package/knowledge/decisions/security/auth-false-on-a-session-function-warns-and-still-requires-one.md +0 -25
- package/knowledge/decisions/security/bearer-token-hashes-are-unpeppered-sha256.md +0 -18
- package/knowledge/decisions/security/consent-is-read-from-a-cookie-and-a-recognised-denial-counts-as-refusal.md +0 -29
- package/knowledge/decisions/security/console-addon-privileged-functions-gate-themselves.md +0 -84
- package/knowledge/decisions/security/core-safe-fetch-blocks-ssrf-by-host-literal-not-dns.md +0 -39
- package/knowledge/decisions/security/core-secrets-use-a-per-secret-dek-wrapped-by-a-kek.md +0 -37
- package/knowledge/decisions/security/cors-defaults-to-any-origin-and-refuses-the-wildcard-with-credentials.md +0 -22
- package/knowledge/decisions/security/credential-backends-share-one-conformance-suite-for-per-user-isolation.md +0 -29
- package/knowledge/decisions/security/each-stage-has-one-virtual-user-key-pair.md +0 -27
- package/knowledge/decisions/security/gateway-handlers-run-through-the-function-runner-gate.md +0 -41
- package/knowledge/decisions/security/gateway-middleware-sessions-must-be-bridged-onto-the-wire.md +0 -30
- package/knowledge/decisions/security/global-permissions-and-function-permissions-are-independent-gates.md +0 -40
- package/knowledge/decisions/security/hmac-verification-fails-closed-on-empty-inputs.md +0 -25
- package/knowledge/decisions/security/http-error-detail-is-withheld-from-clients-in-production.md +0 -33
- package/knowledge/decisions/security/http-request-bodies-are-bounded-before-they-are-buffered.md +0 -46
- package/knowledge/decisions/security/index.md +0 -135
- package/knowledge/decisions/security/local-content-refuses-private-buckets-under-the-public-segment.md +0 -21
- package/knowledge/decisions/security/mail-is-allowlisted-before-a-virtual-user-run-sees-it.md +0 -38
- package/knowledge/decisions/security/mcp-internal-error-details-are-double-gated-on-production.md +0 -27
- package/knowledge/decisions/security/mcp-resources-tools-and-prompts-take-sessionless-functions.md +0 -18
- package/knowledge/decisions/security/origin-locked-routes-match-the-origin-exactly.md +0 -22
- package/knowledge/decisions/security/oss-auth-works-without-pikku-studio-cloud.md +0 -26
- package/knowledge/decisions/security/outbound-webhooks-use-an-allowlist-when-configured.md +0 -24
- package/knowledge/decisions/security/passphrases-are-stretched-key-material-is-expanded.md +0 -40
- package/knowledge/decisions/security/permission-auth-filtering-requires-live-permission-functions.md +0 -31
- package/knowledge/decisions/security/pikku-carries-virtual-user-scopes-as-data-and-the-app-grants-them.md +0 -35
- package/knowledge/decisions/security/queue-job-identities-are-signed-at-enqueue.md +0 -69
- package/knowledge/decisions/security/queue-jobs-carry-the-producers-pikku-user-id.md +0 -39
- package/knowledge/decisions/security/remote-addon-tokens-are-client-credentials-not-mesh-trust.md +0 -34
- package/knowledge/decisions/security/scaffold-features-are-authenticated-unless-opted-out.md +0 -55
- package/knowledge/decisions/security/scenario-step-functions-are-never-externally-invocable.md +0 -30
- package/knowledge/decisions/security/scope-resolution-happens-at-the-session-boundary-and-sync-never-deletes.md +0 -28
- package/knowledge/decisions/security/scoped-content-access-is-a-root-folder-with-longest-prefix-grants.md +0 -31
- package/knowledge/decisions/security/self-authentication-is-declared-not-detected.md +0 -34
- package/knowledge/decisions/security/services-without-secrets-get-a-throwing-secrets-accessor.md +0 -22
- package/knowledge/decisions/security/shared-guards-refuse-to-mutate-or-shadow-a-system-role.md +0 -34
- package/knowledge/decisions/security/signed-content-urls-bind-the-request-path.md +0 -37
- package/knowledge/decisions/security/signed-uploads-are-verified-by-the-same-check-as-signed-reads.md +0 -26
- package/knowledge/decisions/security/system-role-scopes-must-be-declared-with-define-scope.md +0 -24
- package/knowledge/decisions/security/system-roles-are-additive-and-immutable.md +0 -16
- package/knowledge/decisions/security/the-channel-rpc-does-not-send-the-callers-session.md +0 -21
- package/knowledge/decisions/security/the-remote-jobs-inbox-fails-closed-without-a-secret.md +0 -24
- package/knowledge/decisions/security/the-remote-rpc-gate-fails-closed-and-binds-the-token-to-its-function.md +0 -34
- package/knowledge/decisions/security/the-workflow-status-stream-rechecks-ownership-on-every-poll.md +0 -16
- package/knowledge/decisions/security/two-credentials-on-one-key-must-share-a-read-mode.md +0 -29
- package/knowledge/decisions/security/verified-bearer-claims-are-pass-through-data-that-core-never-fills.md +0 -23
- package/knowledge/decisions/security/virtual-user-catalogue-excludes-the-machinery-that-runs-virtual-users.md +0 -25
- package/knowledge/decisions/security/virtual-user-conversation-missing-approval-decisions-default-to-denied.md +0 -22
- package/knowledge/decisions/security/virtual-user-run-records-are-gated-behind-a-read-scope.md +0 -18
- package/knowledge/decisions/security/virtual-user-sign-in-does-not-exist-in-production.md +0 -25
- package/knowledge/decisions/security/virtual-user-sign-in-has-one-door.md +0 -42
- package/knowledge/decisions/security/virtual-user-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md +0 -29
- package/knowledge/decisions/security/virtual-user-sign-in-only-works-for-virtual-user-flagged-users.md +0 -29
- package/knowledge/decisions/security/webhook-bodies-are-signed-before-they-are-enqueued.md +0 -25
- package/knowledge/decisions/security/wire-addon-expose-selects-the-rpc-surface.md +0 -51
- package/knowledge/decisions/security/workflow-approval-payloads-are-validated-on-replay-inside-the-workflow.md +0 -40
- package/knowledge/decisions/security/workflow-helper-functions-are-sessionless-by-declaration.md +0 -18
- package/knowledge/decisions/security/workflow-queued-steps-rehydrate-their-session-from-the-run-wire.md +0 -32
- package/knowledge/decisions/security/workflow-scenario-sessions-are-isolated-per-virtual-user-and-per-scenario.md +0 -32
- package/knowledge/decisions/security/workflow-scenario-steps-are-never-network-invocable.md +0 -31
- package/knowledge/decisions/security/workflow-virtual-user-steps-always-use-the-real-transport.md +0 -34
- package/knowledge/decisions/security/writing-a-virtual-user-schedule-is-gated-by-its-own-scope.md +0 -18
- package/knowledge/index.md +0 -24
- package/knowledge/questions/a-bearer-jwt-with-no-identity-becomes-a-session.md +0 -24
- package/knowledge/questions/channel-middleware-accepts-bare-factories-that-nothing-resolves.md +0 -35
- package/knowledge/questions/dev-quick-login-as-impersonation.md +0 -25
- package/knowledge/questions/does-a-delayed-rpc-run-as-the-session-it-was-scheduled-with.md +0 -26
- package/knowledge/questions/does-a-user-id-with-a-colon-read-another-users-credentials.md +0 -27
- package/knowledge/questions/does-a-wirecli-command-need-a-session-by-default.md +0 -26
- package/knowledge/questions/does-an-adversarial-in-scope-success-count-as-a-finding.md +0 -26
- package/knowledge/questions/does-approve-step-need-the-run-owners-session-or-the-gates-approvers.md +0 -34
- package/knowledge/questions/does-cors-origin-true-reflect-any-origin-with-credentials.md +0 -20
- package/knowledge/questions/does-skip-user-session-do-anything-on-a-channel.md +0 -24
- package/knowledge/questions/does-the-store-session-match-the-other-two.md +0 -19
- package/knowledge/questions/index.md +0 -41
- package/knowledge/questions/is-the-agent-score-worker-reachable-without-a-session.md +0 -21
- package/knowledge/questions/live-scheduled-tests-may-write.md +0 -19
- package/knowledge/questions/provision-virtual-users-has-no-caller-in-this-repo.md +0 -23
- package/knowledge/questions/remote-secret-refuses-requests-without-a-remote-token-on-every-path.md +0 -32
- package/knowledge/questions/should-a-middleware-set-session-persist-to-the-store.md +0 -25
- package/knowledge/questions/should-a-scoped-secret-view-throw-from-has-secret-for-a-disallowed-key.md +0 -23
- package/knowledge/questions/should-a-wrong-bearer-token-be-anonymous-or-refused.md +0 -35
- package/knowledge/questions/should-an-empty-webhook-signing-secret-send-unsigned.md +0 -23
- package/knowledge/questions/should-http-virtual-user-sessions-reset-between-scenarios-in-one-run.md +0 -27
- package/knowledge/questions/should-the-cookie-jar-scope-cookies-to-the-api-origin.md +0 -26
- package/knowledge/questions/should-voice-input-fetch-audio-urls-without-a-host-allowlist.md +0 -20
- package/knowledge/questions/staging-impersonation-rules.md +0 -27
- package/knowledge/questions/unauthorized-channel-replies-escape-the-declared-out-type.md +0 -44
- package/knowledge/questions/virtual-user-keys-on-cloud-stages-are-pikku-studios-to-build.md +0 -33
- package/knowledge/questions/virtual-user-statement-replay-is-per-process.md +0 -20
- package/knowledge/questions/what-an-impersonated-session-carries.md +0 -22
- package/run-tests.sh +0 -68
- package/scripts/generate-api-report.d.mts +0 -1
- package/scripts/generate-api-report.mjs +0 -96
- package/scripts/generate-api-report.mts +0 -333
- package/src/public-surface.json +0 -637
- package/src/public-surface.json.README +0 -43
- /package/dist/{function/compensation-name.d.ts → compensation-name.d.ts} +0 -0
- /package/dist/{function/compensation-name.js → compensation-name.js} +0 -0
package/knowledge/decisions/internals/workflow-retries-are-owned-by-the-workflow-not-the-queue.md
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: Workflow step retries are owned by the workflow, never by the queue
|
|
4
|
-
description: A step's retry count is resolved once and always passed to the queue as `attempts`, so the queue can never apply its own default
|
|
5
|
-
tags: workflow
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Workflow step retries are owned by the workflow, never by the queue
|
|
9
|
-
|
|
10
|
-
A step's retry policy comes from the step itself, falling back to
|
|
11
|
-
`DEFAULT_STEP_RETRIES` (5) when unset. The default is deliberately greater than
|
|
12
|
-
zero so a transient failure — a DB blip, a downstream restart, a deploy — is
|
|
13
|
-
ridden out without the author asking for it; that is safe only because every
|
|
14
|
-
step gets a stable `invocationId` to dedupe on. An explicit `retries: 0` means
|
|
15
|
-
exactly once and must be honoured.
|
|
16
|
-
|
|
17
|
-
`resolveStepJobOptions` in `pikku-workflow-service.ts` therefore ALWAYS emits
|
|
18
|
-
`attempts`, even when it is 1. Backoff defaults to exponential whenever at least
|
|
19
|
-
one retry remains, so retries ride out an outage instead of firing instantly; a
|
|
20
|
-
concrete `retryDelay` (`15000`, `'15s'`) selects fixed backoff, and only the
|
|
21
|
-
literal `'exponential'` selects exponential explicitly. `rpcStep` resolves the
|
|
22
|
-
policy once, before both persistence and dispatch, so the value stored on the
|
|
23
|
-
step row — which drives `retriesExhausted` — is the same number the queue turns
|
|
24
|
-
into `attempts`. `queueGraphNode` in `graph/graph-runner.ts` defaults node
|
|
25
|
-
retries to `DEFAULT_STEP_RETRIES` for the same reason.
|
|
26
|
-
|
|
27
|
-
**What this rules out:** dropping `attempts` when it equals 1 "because that is
|
|
28
|
-
the default anyway", resolving retries separately at the persistence and
|
|
29
|
-
dispatch sites, or letting the queue adapter's own `retry_limit` decide. Any of
|
|
30
|
-
those lets the queue re-run a step the workflow said to run once, or lets the
|
|
31
|
-
engine believe retries are exhausted while the queue keeps retrying.
|
package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: Workflow run capabilities are extensions, not subclasses
|
|
4
|
-
description: Scenario support lives in a separate module behind `setRunExtension` because a bundler drops an unused module but never an unused class member
|
|
5
|
-
tags: workflow
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Workflow run capabilities are extensions, not subclasses
|
|
9
|
-
|
|
10
|
-
`PikkuWorkflowService` names nothing about what a `WorkflowRunExtension` is for.
|
|
11
|
-
An extension is installed with `setRunExtension(create)` and receives a narrow
|
|
12
|
-
`WorkflowRunEngine` handle — `inlineStep`, `updateRunStatus`,
|
|
13
|
-
`onChildWorkflowFailed`, `verifyStepName` — so recording a durable step stays
|
|
14
|
-
available to it without becoming public API on every workflow service a
|
|
15
|
-
production app instantiates.
|
|
16
|
-
|
|
17
|
-
The reason it is not a subclass is bundle size: a bundler drops an unused
|
|
18
|
-
_module_ but never an unused class member. Anything declared on
|
|
19
|
-
`PikkuWorkflowService` ships in every server built on Pikku, along with
|
|
20
|
-
everything it imports. `PikkuScenarioService` (`pikku-scenario-service.ts`) is
|
|
21
|
-
the one implementation today — steps, virtual users, lifecycle hooks, the browser
|
|
22
|
-
provider and the assertion wire members — and scenarios only ever run from
|
|
23
|
-
`pikku scenario run`, so the whole surface stays behind an import that only the
|
|
24
|
-
runner makes. It is not a workflow service in its own right because a scenario
|
|
25
|
-
is not a different kind of run; it is the same durable run with a step
|
|
26
|
-
vocabulary on top. `scenario-service.test.ts` asserts that none of those members
|
|
27
|
-
leak onto the base class.
|
|
28
|
-
|
|
29
|
-
`createScenarioRunner` in the same file bundles the two lines
|
|
30
|
-
`pikku scenario run` needs so no caller has to remember the capability is
|
|
31
|
-
installed rather than inherited. It pairs the extension with
|
|
32
|
-
`InMemoryWorkflowService`, which is the right engine because a scenario run is a
|
|
33
|
-
single external process driving a deployed app over its real transport: there
|
|
34
|
-
is nothing to persist and no second worker to resume it.
|
|
35
|
-
|
|
36
|
-
**What this rules out:** moving scenario steps, virtual users, hooks or the browser
|
|
37
|
-
provider onto `PikkuWorkflowService`, making `PikkuScenarioService` extend it,
|
|
38
|
-
or widening `WorkflowRunEngine` into "just pass the service" — each one puts the
|
|
39
|
-
scenario runtime, and its transitive imports, into every deployed Pikku server.
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: The workflow run mirror is an observability sink, never a second source of truth
|
|
4
|
-
description: Every mirrored write happens after the authoritative write lands, and a mirror failure can never fail the workflow
|
|
5
|
-
tags: workflow
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# The workflow run mirror is an observability sink, never a second source of truth
|
|
9
|
-
|
|
10
|
-
`WorkflowRunMirror` lets an executor shadow every state write to an external
|
|
11
|
-
read store — typically a DB the console UI queries while the run itself lives in
|
|
12
|
-
a Durable Object or Redis. Both properties that make it safe follow from the
|
|
13
|
-
single shape of `PikkuWorkflowService.mirrored()` in
|
|
14
|
-
`pikku-workflow-service.ts`: the mirror is only ever told about a write that has
|
|
15
|
-
already landed in the canonical store, and a mirror that is down or throwing is
|
|
16
|
-
caught, logged at warn, and otherwise invisible to the workflow. Even the log
|
|
17
|
-
call is wrapped, because singleton services may not be initialised yet.
|
|
18
|
-
|
|
19
|
-
Every public write method is a thin `mirrored(() => …Impl(...), (mirror) => …)`
|
|
20
|
-
pair over a `protected abstract` implementation. That pairing is the reason a
|
|
21
|
-
mirror method added to the interface but never wired into the service would
|
|
22
|
-
write nothing at runtime — `workflow-mirror.test.ts` spells out the full method
|
|
23
|
-
list to catch exactly that.
|
|
24
|
-
|
|
25
|
-
**What this rules out:** reading run or step state back from the mirror,
|
|
26
|
-
awaiting the mirror before returning the authoritative result, letting a mirror
|
|
27
|
-
rejection propagate, or writing to the mirror first so the two "stay in sync" —
|
|
28
|
-
any of which turns an index into a second, divergent source of truth that can
|
|
29
|
-
take the workflow down with it.
|
package/knowledge/decisions/internals/workflow-run-polling-backs-off-to-the-callers-ceiling.md
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: Workflow run polling starts short and backs off to the caller's ceiling
|
|
4
|
-
description: `pollIntervalMs` is a ceiling, not a cadence, and the wait lives in its own method so the schedule can be asserted without the clock
|
|
5
|
-
tags: workflow
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Workflow run polling starts short and backs off to the caller's ceiling
|
|
9
|
-
|
|
10
|
-
`awaitRunEnd` in `pikku-workflow-service.ts` reads a run until it reaches an end
|
|
11
|
-
state, starting at `WORKFLOW_POLL_MIN_MS` (10ms) and multiplying by
|
|
12
|
-
`WORKFLOW_POLL_FACTOR` (1.6) up to the caller's `maxIntervalMs`. A fixed
|
|
13
|
-
interval is wrong at both ends: it makes a workflow that finished in
|
|
14
|
-
milliseconds wait out the whole interval anyway, and it keeps reading a
|
|
15
|
-
long-running one at full rate for its entire life. Backing off returns quick
|
|
16
|
-
runs promptly while a slow run's read cost grows logarithmically rather than
|
|
17
|
-
linearly with duration. So `runToCompletion`'s `pollIntervalMs` is a ceiling,
|
|
18
|
-
not a cadence.
|
|
19
|
-
|
|
20
|
-
An inline sub-workflow uses a lower ceiling, `WORKFLOW_CHILD_POLL_MAX_MS`
|
|
21
|
-
(500ms), because the parent step is blocked on it: every wait there is added
|
|
22
|
-
latency in the middle of a workflow rather than at its edge.
|
|
23
|
-
|
|
24
|
-
`waitBeforeNextRead` exists as its own method purely so the schedule can be
|
|
25
|
-
asserted directly (`workflow-run-polling.test.ts`). Timing a poll loop by the
|
|
26
|
-
clock measures the host's scheduler as much as the policy — `setTimeout(40)`
|
|
27
|
-
routinely returns late on a loaded CI runner — which makes the obvious test both
|
|
28
|
-
slow and flaky.
|
|
29
|
-
|
|
30
|
-
**What this rules out:** replacing the backoff with a fixed `pollIntervalMs`
|
|
31
|
-
sleep, reading `pollIntervalMs` as the first wait, giving child runs the
|
|
32
|
-
top-level ceiling, or inlining `waitBeforeNextRead` back into the loop as a bare
|
|
33
|
-
`setTimeout`.
|
package/knowledge/decisions/internals/workflow-run-timeline-is-a-pure-fold-over-durable-history.md
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: The workflow run timeline is a pure fold over durable history, with the row's status as the authority
|
|
4
|
-
description: No IO in the fold keeps time-travel transport-independent; the terminal event comes from `status`, not from a timestamp every backend populates
|
|
5
|
-
tags: workflow
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# The workflow run timeline is a pure fold over durable history, with the row's status as the authority
|
|
9
|
-
|
|
10
|
-
`run-timeline.ts` turns `getRunHistory` — one row per step _attempt_, each with
|
|
11
|
-
lifecycle timestamps — into a flat, chronologically ordered event stream, and
|
|
12
|
-
folds that stream up to any point to recover what the run "knew" then: the same
|
|
13
|
-
step cache a replay would hold, plus the walked path. Both functions are pure,
|
|
14
|
-
with no IO, so they are trivially testable and the same fold works for the
|
|
15
|
-
Redis, Kysely and in-memory stores alike.
|
|
16
|
-
|
|
17
|
-
The terminal event is driven by the row's authoritative `status`, falling back
|
|
18
|
-
to `updatedAt` when the specific stamp is absent, because the lifecycle
|
|
19
|
-
timestamps are not populated by every backend — Kysely leaves
|
|
20
|
-
`succeededAt`/`runningAt` null. The intermediate `scheduled` and `running`
|
|
21
|
-
events are optional enrichment, emitted only when the backend recorded them; the
|
|
22
|
-
`pending` event always exists and is the one that carries provenance
|
|
23
|
-
(`fromStepName`).
|
|
24
|
-
|
|
25
|
-
Ordering is defensive: events sort by timestamp, then by `LIFECYCLE_ORDER`, then
|
|
26
|
-
by original index, so rows sharing an instant stay deterministic across
|
|
27
|
-
backends. In the fold, a retry's `pending` event reopens the step and drops the
|
|
28
|
-
prior result and error.
|
|
29
|
-
|
|
30
|
-
The index conventions are fixed and callers depend on them: `TimelineEvent.seq`
|
|
31
|
-
is a monotonic 0-based position, `attempt` is 1-based, and
|
|
32
|
-
`reconstructStateAt(at)` is inclusive whether `at` is a seq or a `Date` — a
|
|
33
|
-
point before the first event yields the empty initial state with `seq` of `-1`.
|
|
34
|
-
|
|
35
|
-
**What this rules out:** reading state inside the fold, deriving the terminal
|
|
36
|
-
event from `succeededAt`/`failedAt` alone, trusting history to arrive sorted, or
|
|
37
|
-
letting a retry's reopening event keep the previous attempt's outcome.
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: Scenario steps default to no retries, and a whole poll is one durable step
|
|
4
|
-
description: Retrying a failed assertion is wrong for a test primitive; recording the poll as one step means replay returns the outcome, not the loop
|
|
5
|
-
tags: workflow
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Scenario steps default to no retries, and a whole poll is one durable step
|
|
9
|
-
|
|
10
|
-
`ScenarioStepOptions.retries` defaults to 0, unlike an ordinary workflow step
|
|
11
|
-
which inherits `DEFAULT_STEP_RETRIES`. `PikkuScenarioService.scenarioStep`
|
|
12
|
-
applies that default explicitly (`options?.retries ?? 0`). Retrying a failed
|
|
13
|
-
assertion is the wrong behaviour for a test primitive: it converts a real
|
|
14
|
-
failure into a slow flake and hides the very race the scenario was written to
|
|
15
|
-
catch.
|
|
16
|
-
|
|
17
|
-
`expectEventually` is the sanctioned way to wait. The entire poll — invoke,
|
|
18
|
-
check the predicate, sleep, repeat until `within` elapses — runs inside a single
|
|
19
|
-
`inlineStep`, so it is ONE recorded step and a replay returns the cached
|
|
20
|
-
outcome rather than re-polling. `expectError` and `expectService` are the same
|
|
21
|
-
shape: one durable step whose body contains the whole assertion, with a failure
|
|
22
|
-
message that names the step, the target, and what was actually seen.
|
|
23
|
-
|
|
24
|
-
`pollUntil` in `scenario-poll.ts` is the step-level equivalent, and its
|
|
25
|
-
`undefined` convention is deliberate: `undefined` means "not yet" and nothing
|
|
26
|
-
else, because `false`, `0` and `''` are all real answers — a probe asking
|
|
27
|
-
whether something happened reports `false` when it did not. It returns
|
|
28
|
-
`undefined` at the deadline rather than throwing, leaving the error to the
|
|
29
|
-
caller, who is the only one who knows what was being waited for. Its own
|
|
30
|
-
defaults are shorter than the assertion wrappers': `within` 15s, `interval`
|
|
31
|
-
250ms.
|
|
32
|
-
|
|
33
|
-
`requireScenarioEnv` (`scenario-step-guards.ts`) exists for the mirror-image
|
|
34
|
-
reason: `env` is optional on the step wire because most steps need nothing from
|
|
35
|
-
it, so the narrowing happens in one place with a message that says what to do,
|
|
36
|
-
instead of every step file writing its own guard. The virtual user is not narrowed at
|
|
37
|
-
all — a step that runs as somebody declares `virtualUser: true` (or a `browser`
|
|
38
|
-
binding, which cannot be provisioned without a window to open), and the runner
|
|
39
|
-
injects `wire.virtualUser` non-optionally into every binding and refuses to dispatch
|
|
40
|
-
the step without one. A wire member can be required per binding; a property of
|
|
41
|
-
one cannot, which is why it is not on `scenarioStep`. `scenarioStep`'s `verifyStepName` call doubles as the guard for `then`
|
|
42
|
-
being a wire member — an accidental `await scenario` calls it with a resolve
|
|
43
|
-
function, which lands as a loud named error instead of a silent hang.
|
|
44
|
-
|
|
45
|
-
The assertion options are lenient by design so a scenario reads as intent
|
|
46
|
-
rather than as an exact-match harness: `matches` is a substring test when it is
|
|
47
|
-
a string and a full match only when it is a `RegExp`; `calledWith` deep-equals
|
|
48
|
-
the first argument only; `times` means at-least-once unless a count is given;
|
|
49
|
-
`within` defaults to `'30s'` and `interval` to `'1s'`.
|
|
50
|
-
|
|
51
|
-
**What this rules out:** giving scenario steps the workflow retry default,
|
|
52
|
-
recording each poll iteration as its own step, treating a falsy `pollUntil`
|
|
53
|
-
result as "not yet", making `pollUntil` throw on timeout, or narrowing `virtualUser`
|
|
54
|
-
by hand inside individual step files.
|
package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
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 `virtualUsers`) 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:`.
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: Scenario prose is rendered out of typed calls, not parsed into them
|
|
4
|
-
description: 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. 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.
|
|
@@ -1,18 +0,0 @@
|
|
|
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.
|
|
@@ -1,34 +0,0 @@
|
|
|
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 through a regex registry, `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
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: A step's compensation runs as a durable step of its own, declared on the function
|
|
4
|
-
description: A refund or rollback must not fire twice on replay, so it is recorded as `<step>:compensate`; `onError` is gone
|
|
5
|
-
tags: workflow
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# A step's compensation runs as a durable step of its own, declared on the function
|
|
9
|
-
|
|
10
|
-
A function declares `compensate` inline on `pikkuFunc`. When a workflow unwinds,
|
|
11
|
-
`driveUnwind` (`workflow-compensation.ts`) runs it as the step
|
|
12
|
-
`<step>:compensate` through the same RPC path as a forward step. Durability is
|
|
13
|
-
the point: a compensation is typically a refund or a rollback, and a bare invoke
|
|
14
|
-
would fire again on every replay. Recorded as a step, a second pass finds it
|
|
15
|
-
`succeeded` and returns the cached result. It uses the forward step's retry
|
|
16
|
-
defaults, and a compensation cannot itself be compensated.
|
|
17
|
-
|
|
18
|
-
`runPikkuFunc` and the RPC resolver derive the `<id>:compensate` function from
|
|
19
|
-
the forward config lazily, so nothing extra is registered, and it is never
|
|
20
|
-
exposed. What to undo, and in what order, is decided by the pure `planUnwind`
|
|
21
|
-
from the recorded step rows — never from in-memory state, so a crash mid-unwind
|
|
22
|
-
resumes at the next compensation.
|
|
23
|
-
|
|
24
|
-
`onError` (DSL option and graph node field) was removed. Graph nodes recover
|
|
25
|
-
with `recover`, which takes precedence over compensation.
|
|
26
|
-
|
|
27
|
-
**What this rules out:** invoking the compensation inline "since it's just
|
|
28
|
-
cleanup", compensating a compensation, a second unwind of a settled run, and
|
|
29
|
-
swallowing the original failure because a handler succeeded.
|
|
@@ -1,33 +0,0 @@
|
|
|
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.
|
|
@@ -1,34 +0,0 @@
|
|
|
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 step lock across step work exhausted the connection pool and self-deadlocked when it was an advisory lock; it stays claim-only on leases
|
|
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
|
|
19
|
-
then-advisory lock, and therefore its pooled connection, across
|
|
20
|
-
`executeGraphStep` (network I/O plus further pool queries) let concurrent steps
|
|
21
|
-
exhaust the connection pool and self-deadlock.
|
|
22
|
-
|
|
23
|
-
`withStepLock` is now a lease on the app's `leaseService`
|
|
24
|
-
(`workflow-step:<runId>:<step>`), so it pins no connection. It still stays
|
|
25
|
-
claim-only: a lease held across the work would have to outlive it, and a taken
|
|
26
|
-
step lease already means "another dispatch owns it", so the claim answers
|
|
27
|
-
`null`. Kysely and MongoDB claim with a status-guarded conditional update and do
|
|
28
|
-
not take it at all.
|
|
29
|
-
|
|
30
|
-
**What this rules out:** widening the `withStepLock` callback to cover RPC
|
|
31
|
-
invocation, child-workflow start, `setStepResult` or `resumeWorkflow` — the
|
|
32
|
-
"obviously safer" refactor that reintroduces the deadlock. If a stronger
|
|
33
|
-
guarantee is ever needed it has to come from the claim itself, not from a longer
|
|
34
|
-
lock hold.
|
|
@@ -1,34 +0,0 @@
|
|
|
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.
|
|
@@ -1,38 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
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 virtual user 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.
|
package/knowledge/decisions/security/a-bearer-token-checked-against-a-secret-reads-it-per-request.md
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: A bearer token checked against a secret is read per request, and an unreadable secret means no session
|
|
4
|
-
description: The secretId form of authBearer reads the secret on every request; a missing or failing read leaves the request without a session rather than raising an error
|
|
5
|
-
tags: core, middleware, auth
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# A bearer token checked against a secret is read per request, and an unreadable secret means no session
|
|
9
|
-
|
|
10
|
-
In `packages/core/src/middleware/auth-bearer.ts:57-70`, a token given as a
|
|
11
|
-
literal `value` is compared directly (`:59-60`). A token given a `secretId` is
|
|
12
|
-
read from the secret service on each request (`:63-64`). A failed read is caught
|
|
13
|
-
and becomes `undefined` (`:65`), and the code comments that an unset secret means
|
|
14
|
-
the feature is off, never a request error (`:62`).
|
|
15
|
-
|
|
16
|
-
An undefined expected value skips the comparison (`:68`). `userSession` stays
|
|
17
|
-
null, and `setSession` is not called (`:55`, `:75-77`). A malformed scheme is a
|
|
18
|
-
different case: it throws `InvalidSessionError` (`:50-53`).
|
|
19
|
-
|
|
20
|
-
The static and JWT branches of this middleware are covered by the existing
|
|
21
|
-
questions `a-bearer-jwt-with-no-identity-becomes-a-session.md` and
|
|
22
|
-
`should-a-wrong-bearer-token-be-anonymous-or-refused.md`.
|
|
23
|
-
|
|
24
|
-
**What this rules out:** turning a missing or unreadable signing secret into a
|
|
25
|
-
server error, and caching the secret value across requests in the middleware
|
|
26
|
-
closure.
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: A call without a session raises MissingSessionError, and a missing scope raises MissingScopeError
|
|
4
|
-
description: The function runner separates the no-session refusal from the scope and permission refusals, so a caller can tell a missing login from a denied grant
|
|
5
|
-
tags: core, errors, sessions, scopes
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# A call without a session raises MissingSessionError, and a missing scope raises MissingScopeError
|
|
9
|
-
|
|
10
|
-
`resolveSession` in `packages/core/src/function/function-runner.ts` (line 64) loads a stored session when there is a user id. It throws nothing.
|
|
11
|
-
|
|
12
|
-
The refusal is in `executeFunction`. A sessionless function requires a session only when its wiring, its own config, or the addon says `auth: true` (`function-runner.ts:385-395`). That refusal throws `MissingSessionError` (`function-runner.ts:392`). A `pikkuFunc` with no session throws the same error unconditionally (`function-runner.ts:402`). The class is at `packages/core/src/errors/errors.ts:36`.
|
|
13
|
-
|
|
14
|
-
Scope checks use a different error. `verifyScopes` throws `MissingScopeError` (`packages/core/src/scopes.ts:84-86`, class at `packages/core/src/errors/errors.ts:118`).
|
|
15
|
-
|
|
16
|
-
Permission checks use `ForbiddenError` with the message `Permission denied` (`packages/core/src/permissions.ts:155`, `:166`, class at `packages/core/src/errors/errors.ts:57`).
|
|
17
|
-
|
|
18
|
-
So the three refusals are distinct: no login, a missing scope, and a failed permission function.
|
|
19
|
-
|
|
20
|
-
**What this rules out:** reporting a call with no session as a `ForbiddenError`, and reading a `ForbiddenError` from the runner as proof that a session exists but lacks a grant.
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: A cookie the caller sets wins over the jar's copy of the same name
|
|
4
|
-
description: createCookieJar sends the caller's cookie for a name and drops the jar's copy of that name, so one request never carries the same cookie twice
|
|
5
|
-
tags: core, scenario, cookies
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# A cookie the caller sets wins over the jar's copy of the same name
|
|
9
|
-
|
|
10
|
-
In `createCookieJar` (`packages/core/src/services/scenario-cookie-jar.ts`)
|
|
11
|
-
the jar builds the outgoing `cookie` header from the caller's own header and the
|
|
12
|
-
jar's held cookies. A held cookie is left out when the caller's header already
|
|
13
|
-
names it. The code comment says a request that already carries a session "is
|
|
14
|
-
stating which one it means, and emitting the jar's copy alongside it sends the
|
|
15
|
-
same name twice."
|
|
16
|
-
|
|
17
|
-
The rule is per name, not per request. Cookies the caller did not name still go
|
|
18
|
-
out from the jar. The jar's `Set-Cookie` handling, which replaces a reissued
|
|
19
|
-
cookie rather than sending both, is covered by
|
|
20
|
-
[Scenario sessions are isolated per virtual user and reset between scenarios](workflow-scenario-sessions-are-isolated-per-virtual-user-and-per-scenario.md).
|
|
21
|
-
|
|
22
|
-
**What this rules out:** sending two values of one cookie name in a request, and
|
|
23
|
-
letting the jar's held session override a session the caller has chosen to send.
|