@pikku/core 0.12.84 → 0.12.88
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +503 -0
- package/dist/bootstrap-compat/root.d.ts +20 -0
- package/dist/classification/column-form.d.ts +32 -0
- package/dist/classification/column-form.js +42 -0
- package/dist/classification/data-classification.d.ts +64 -0
- package/dist/classification/index.d.ts +13 -0
- package/dist/classification/index.js +2 -0
- package/dist/classification/secret-value.d.ts +56 -0
- package/dist/classification/secret-value.js +46 -0
- package/dist/crypto-utils.d.ts +1 -1
- package/dist/dev/hot-reload.d.ts +1 -1
- package/dist/dev/hot-reload.js +1 -1
- package/dist/ecosystem/agent-scorer.d.ts +1 -1
- package/dist/ecosystem/agent.d.ts +4 -1
- package/dist/ecosystem/channel/local.d.ts +2 -0
- package/dist/ecosystem/channel/local.js +2 -0
- package/dist/ecosystem/channel/serverless.d.ts +9 -0
- package/dist/ecosystem/channel/serverless.js +1 -0
- package/dist/ecosystem/channel.d.ts +3 -0
- package/dist/ecosystem/channel.js +1 -0
- package/dist/ecosystem/cli.d.ts +1 -1
- package/dist/ecosystem/cli.js +1 -1
- package/dist/ecosystem/credential.d.ts +1 -0
- package/dist/ecosystem/crypto-utils.d.ts +8 -0
- package/dist/ecosystem/crypto-utils.js +1 -0
- package/dist/ecosystem/dev.d.ts +1 -0
- package/dist/ecosystem/dev.js +1 -0
- package/{src/ecosystem/testing.ts → dist/ecosystem/errors.d.ts} +3 -3
- package/dist/ecosystem/errors.js +2 -0
- package/dist/ecosystem/function.d.ts +1 -1
- package/dist/ecosystem/function.js +1 -1
- package/dist/ecosystem/http.d.ts +3 -1
- package/dist/ecosystem/http.js +3 -1
- package/dist/ecosystem/mcp.d.ts +1 -1
- package/dist/ecosystem/mcp.js +1 -1
- package/dist/ecosystem/middleware.d.ts +2 -1
- package/dist/ecosystem/middleware.js +2 -1
- package/dist/ecosystem/persona.d.ts +4 -2
- package/dist/ecosystem/persona.js +2 -1
- package/dist/ecosystem/queue.d.ts +4 -2
- package/dist/ecosystem/queue.js +3 -1
- package/dist/ecosystem/role.d.ts +1 -0
- package/dist/ecosystem/rpc.d.ts +2 -0
- package/dist/ecosystem/rpc.js +1 -0
- package/dist/ecosystem/scenario.d.ts +8 -2
- package/dist/ecosystem/scenario.js +5 -1
- package/dist/ecosystem/scheduler.d.ts +2 -1
- package/dist/ecosystem/scheduler.js +2 -1
- package/dist/ecosystem/schema.d.ts +2 -1
- package/dist/ecosystem/schema.js +1 -1
- package/dist/ecosystem/scope.d.ts +2 -0
- package/dist/ecosystem/scope.js +1 -0
- package/dist/ecosystem/secret.d.ts +2 -0
- package/dist/ecosystem/secret.js +1 -0
- package/dist/ecosystem/services/local-content.d.ts +2 -1
- package/dist/ecosystem/services/local-content.js +1 -1
- package/dist/ecosystem/services/local-meta.d.ts +1 -0
- package/dist/ecosystem/services/local-meta.js +1 -0
- package/dist/ecosystem/services.d.ts +11 -3
- package/dist/ecosystem/services.js +7 -1
- package/dist/ecosystem/trigger.d.ts +1 -0
- package/dist/ecosystem/trigger.js +1 -1
- package/dist/ecosystem/types.d.ts +6 -3
- package/dist/ecosystem/types.js +3 -2
- package/dist/ecosystem/variable.d.ts +1 -0
- package/dist/ecosystem/virtual-user.d.ts +3 -0
- package/dist/ecosystem/virtual-user.js +3 -0
- package/dist/ecosystem/workflow.d.ts +2 -0
- package/dist/ecosystem/workflow.js +2 -0
- package/dist/errors/index.d.ts +8 -0
- package/dist/errors/index.js +1 -0
- package/dist/errors/serialized-error.d.ts +7 -0
- package/dist/function/function-meta.types.d.ts +139 -0
- package/dist/function/function-runner.d.ts +3 -2
- package/dist/function/function-runner.js +31 -11
- package/dist/function/functions.types.d.ts +10 -2
- package/dist/function/index.d.ts +8 -2
- package/dist/function/index.js +4 -1
- package/dist/function/pikku-request.d.ts +8 -0
- package/dist/function/pikku-request.js +15 -0
- package/dist/middleware/auth-apikey.d.ts +2 -10
- package/dist/middleware/auth-apikey.js +1 -1
- package/dist/middleware/auth-bearer.d.ts +2 -10
- package/dist/middleware/auth-bearer.js +1 -1
- package/dist/middleware/auth-cookie.d.ts +2 -10
- package/dist/middleware/auth-cookie.js +1 -1
- package/dist/middleware/cors.d.ts +5 -11
- package/dist/middleware/cors.js +13 -6
- package/dist/middleware/index.d.ts +3 -0
- package/dist/middleware/index.js +1 -0
- package/dist/middleware/middleware-factories.d.ts +9 -0
- package/dist/middleware/middleware-factories.js +19 -0
- package/dist/middleware/middleware.types.d.ts +27 -0
- package/dist/middleware/middleware.types.js +1 -0
- package/dist/middleware/remote-auth.d.ts +2 -2
- package/dist/middleware/remote-auth.js +1 -1
- package/dist/middleware/telemetry.d.ts +4 -20
- package/dist/middleware/telemetry.js +1 -1
- package/dist/middleware-runner.d.ts +2 -1
- package/dist/pikku-state.d.ts +2 -1
- package/dist/services/audit-service.d.ts +1 -1
- package/dist/services/credential-wire-service.js +1 -1
- package/dist/services/email-service.d.ts +1 -1
- package/dist/services/file-scenario-run-store.d.ts +58 -0
- package/dist/services/file-scenario-run-store.js +214 -0
- package/dist/services/in-memory-workflow-service.d.ts +1 -1
- package/dist/services/index.d.ts +5 -1
- package/dist/services/index.js +3 -0
- package/dist/services/local-secrets.d.ts +1 -1
- package/dist/services/local-secrets.js +1 -1
- package/dist/services/logger.d.ts +7 -7
- package/dist/services/meta-service.d.ts +2 -1
- package/dist/services/scoped-secret-service.d.ts +1 -1
- package/dist/services/secret-service.d.ts +1 -1
- package/dist/services/typed-secret-service.d.ts +16 -2
- package/dist/services/typed-secret-service.js +5 -0
- package/dist/services/webhook-service.d.ts +1 -1
- package/dist/services/workflow-service.d.ts +2 -1
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.js +1 -0
- package/dist/types/core.types.d.ts +30 -180
- package/dist/types/core.types.js +1 -19
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +1 -0
- package/dist/types/state.types.d.ts +3 -1
- package/dist/utils.d.ts +13 -0
- package/dist/utils.js +2 -0
- package/dist/wirings/addon/addon-runner.d.ts +17 -0
- package/dist/wirings/addon/addon-runner.js +150 -0
- package/dist/wirings/addon/index.d.ts +6 -0
- package/dist/wirings/addon/index.js +3 -0
- package/dist/wirings/addon/remote-addon-auth.d.ts +16 -0
- package/dist/wirings/addon/remote-addon-auth.js +39 -0
- package/dist/wirings/addon/wire-addon.d.ts +80 -0
- package/dist/wirings/addon/wire-addon.js +120 -0
- package/dist/wirings/addon/wire-remote-addon.d.ts +22 -0
- package/dist/wirings/addon/wire-remote-addon.js +11 -0
- package/dist/wirings/agent/agent-memory.d.ts +11 -0
- package/dist/wirings/agent/agent-memory.js +17 -2
- package/dist/wirings/agent/agent-prepare.d.ts +3 -3
- package/dist/wirings/agent/agent-prepare.js +1 -1
- package/dist/wirings/agent/agent-runner.js +2 -3
- package/dist/wirings/agent/agent-stream.js +117 -93
- package/dist/wirings/agent/agent-utils.d.ts +13 -0
- package/dist/wirings/agent/agent-utils.js +16 -0
- package/dist/wirings/agent/agent.types.d.ts +12 -10
- package/dist/wirings/agent/index.d.ts +1 -1
- package/dist/wirings/agent/voice-input.js +1 -1
- package/dist/wirings/agent/voice-output.js +1 -1
- package/dist/wirings/agent-scorer/agent-scorer-judge.d.ts +13 -0
- package/dist/wirings/agent-scorer/agent-scorer-judge.js +52 -0
- package/dist/wirings/agent-scorer/agent-scorer.d.ts +7 -1
- package/dist/wirings/agent-scorer/agent-scorer.js +1 -0
- package/dist/wirings/agent-scorer/agent-scorer.types.d.ts +20 -0
- package/dist/wirings/agent-scorer/index.d.ts +1 -1
- package/dist/wirings/channel/channel-common.d.ts +2 -1
- package/dist/wirings/channel/channel-middleware-runner.d.ts +2 -1
- package/dist/wirings/channel/channel.types.d.ts +1 -1
- package/dist/wirings/channel/serverless/index.d.ts +1 -0
- package/dist/wirings/cli/channel/index.d.ts +1 -1
- package/dist/wirings/cli/cli-runner.d.ts +2 -1
- package/dist/wirings/cli/cli-runner.js +4 -1
- package/dist/wirings/cli/cli.types.d.ts +21 -2
- package/dist/wirings/cli/command-parser.js +157 -23
- package/dist/wirings/gateway/gateway.types.d.ts +2 -1
- package/dist/wirings/http/http-runner.d.ts +1 -1
- package/dist/wirings/http/http-runner.js +1 -1
- package/dist/wirings/http/http.types.d.ts +2 -2
- package/dist/wirings/http/index.d.ts +1 -0
- package/dist/wirings/http/index.js +1 -0
- package/dist/wirings/http/pikku-fetch-http-request.js +1 -1
- package/dist/wirings/http/pikku-fetch-http-response.js +2 -2
- package/dist/wirings/mcp/mcp.types.d.ts +1 -1
- package/dist/wirings/persona/index.d.ts +1 -1
- package/dist/wirings/persona/index.js +1 -1
- package/dist/wirings/persona/persona.types.d.ts +14 -0
- package/dist/wirings/queue/queue.types.d.ts +1 -1
- package/dist/wirings/queue/signed-queue-service.d.ts +1 -1
- package/dist/wirings/rpc/index.d.ts +0 -6
- package/dist/wirings/rpc/index.js +0 -3
- package/dist/wirings/rpc/remote-addon-auth.d.ts +1 -1
- package/dist/wirings/rpc/remote-addon-auth.js +1 -1
- package/dist/wirings/rpc/rpc-runner.js +2 -2
- package/dist/wirings/rpc/wire-addon.d.ts +1 -1
- package/dist/wirings/scheduler/scheduler.types.d.ts +2 -1
- package/dist/wirings/scope/index.d.ts +1 -0
- package/dist/wirings/scope/index.js +1 -0
- package/dist/wirings/secret/secret.types.d.ts +10 -0
- package/dist/wirings/secret/validate-secret-definitions.js +2 -0
- package/dist/wirings/variable/validate-variable-definitions.js +2 -0
- package/dist/wirings/variable/variable.types.d.ts +15 -0
- package/dist/wirings/virtual-user/index.d.ts +1 -1
- package/dist/wirings/virtual-user/index.js +1 -1
- package/dist/wirings/virtual-user/prepare-virtual-user-run.d.ts +1 -1
- package/dist/wirings/virtual-user/virtual-user-derive.d.ts +1 -1
- package/dist/wirings/workflow/graph/graph-node.d.ts +9 -2
- package/dist/wirings/workflow/graph/graph-node.js +2 -0
- package/dist/wirings/workflow/graph/graph-runner.d.ts +1 -0
- package/dist/wirings/workflow/graph/graph-runner.js +283 -31
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +16 -1
- package/dist/wirings/workflow/index.d.ts +2 -0
- package/dist/wirings/workflow/index.js +1 -0
- package/dist/wirings/workflow/pikku-scenario-service.d.ts +15 -5
- package/dist/wirings/workflow/pikku-scenario-service.js +44 -16
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +22 -7
- package/dist/wirings/workflow/pikku-workflow-service.js +28 -29
- package/dist/wirings/workflow/run-timeline.d.ts +1 -1
- package/dist/wirings/workflow/scenario-run.types.d.ts +171 -0
- package/dist/wirings/workflow/scenario-run.types.js +1 -0
- package/dist/wirings/workflow/scenario-step-guards.d.ts +1 -2
- package/dist/wirings/workflow/scenario-step-guards.js +0 -8
- package/dist/wirings/workflow/scenario-step.types.d.ts +27 -12
- package/dist/wirings/workflow/workflow-approval.js +2 -1
- package/dist/wirings/workflow/workflow-run-engine.types.d.ts +2 -1
- package/dist/wirings/workflow/workflow-step-claim.d.ts +16 -0
- package/dist/wirings/workflow/workflow-step-claim.js +27 -0
- package/dist/wirings/workflow/workflow.types.d.ts +2 -1
- package/knowledge/decisions/index.md +2 -0
- package/knowledge/decisions/internals/a-scenario-step-template-is-offered-unfilled.md +1 -1
- package/knowledge/decisions/internals/a-secret-that-fails-to-decrypt-fails-the-whole-read.md +1 -1
- package/knowledge/decisions/internals/a-virtual-user-run-is-not-a-workflow-and-not-a-queued-job.md +2 -2
- package/knowledge/decisions/internals/a-wall-clock-threshold-is-a-load-test-in-disguise.md +6 -6
- package/knowledge/decisions/internals/a-workflow-wire-is-built-from-the-run-not-from-the-rpc-service.md +1 -1
- package/knowledge/decisions/internals/addon-singleton-services-are-cached-per-namespace-not-per-package.md +1 -1
- package/knowledge/decisions/internals/addon-workflow-names-are-prefixed-with-the-consumer-namespace.md +1 -1
- package/knowledge/decisions/internals/an-addon-scope-root-loses-to-a-root-the-host-already-declares.md +1 -1
- package/knowledge/decisions/internals/channel-message-handlers-accept-three-config-shapes.md +1 -1
- package/knowledge/decisions/internals/channel-middleware-caches-only-statically-resolved-middleware.md +1 -1
- package/knowledge/decisions/internals/channel-user-id-is-persisted-after-onconnect-middleware-runs.md +1 -1
- package/knowledge/decisions/internals/cli-option-names-are-camelcase-in-state-and-kebab-on-the-command-line.md +1 -1
- package/knowledge/decisions/internals/cli-parse-errors-are-routed-by-message-prefix.md +1 -1
- package/knowledge/decisions/internals/cli-unknown-long-options-warn-instead-of-failing.md +1 -1
- package/knowledge/decisions/internals/core-column-form-is-an-axis-of-its-own.md +4 -4
- package/knowledge/decisions/internals/core-data-classification-brand-is-an-optional-property.md +1 -1
- package/knowledge/decisions/internals/core-function-runner-restores-the-wire-fields-it-overwrites.md +3 -3
- package/knowledge/decisions/internals/core-hot-reload-merges-generated-meta-never-replaces-it.md +2 -2
- package/knowledge/decisions/internals/core-hot-reload-owns-its-module-registry.md +2 -2
- package/knowledge/decisions/internals/core-middleware-order-is-scope-then-priority.md +1 -1
- package/knowledge/decisions/internals/core-schema-defaults-apply-on-every-transport.md +1 -1
- package/knowledge/decisions/internals/core-scopes-are-an-and-gate-separate-from-permissions.md +3 -3
- package/knowledge/decisions/internals/gateway-adapters-resolve-lazily-and-are-promise-cached.md +1 -1
- package/knowledge/decisions/internals/gateway-listener-middleware-runs-without-an-rpc-on-the-wire.md +4 -4
- package/knowledge/decisions/internals/gateway-wiring-is-a-meta-wiring-over-http-and-channels.md +1 -1
- package/knowledge/decisions/internals/http-router-matches-normalized-paths-but-returns-registered-ones.md +1 -1
- package/knowledge/decisions/internals/in-a-scenario-a-4xx-is-data-not-an-exception.md +1 -1
- package/knowledge/decisions/internals/in-memory-workflow-history-aliases-the-live-step-object.md +1 -1
- package/knowledge/decisions/internals/index.md +4 -2
- package/knowledge/decisions/internals/istanbul-statement-counts-attach-to-the-start-line-only.md +1 -1
- package/knowledge/decisions/internals/one-project-shape-check-two-validators.md +1 -1
- package/knowledge/decisions/internals/queue-jobs-always-carry-an-explicit-attempts-count.md +1 -1
- package/knowledge/decisions/internals/remote-addons-dispatch-over-http-instead-of-local-meta.md +1 -1
- package/knowledge/decisions/internals/rpc-names-resolve-through-package-scope-before-root.md +1 -1
- package/knowledge/decisions/internals/scenario-given-and-when-are-sugar-but-then-is-not.md +2 -2
- package/knowledge/decisions/internals/scenarios-live-in-files-named-for-them.md +5 -5
- package/knowledge/decisions/internals/the-actor-prompt-says-json-because-of-json-object-mode.md +1 -1
- package/knowledge/decisions/internals/the-api-report-pins-members-not-just-names.md +1 -1
- package/knowledge/decisions/internals/the-ecosystem-entry-point-carries-the-adapter-surface.md +43 -19
- package/knowledge/decisions/internals/the-persona-runtime-is-exported-from-the-persona-entry-point.md +1 -1
- package/knowledge/decisions/internals/the-worker-disposition-is-the-one-that-is-not-testing.md +1 -1
- package/knowledge/decisions/internals/validate-runs-checks-by-precondition.md +3 -3
- package/knowledge/decisions/internals/virtual-user-step-order-comes-from-insertion-order.md +1 -1
- package/knowledge/decisions/internals/webhook-delivery-history-records-every-attempt-best-effort.md +1 -1
- package/knowledge/decisions/internals/wiring-registries-erase-the-generics-their-wire-functions-capture.md +1 -1
- package/knowledge/decisions/internals/workflow-approval-expiry-is-decided-from-a-recorded-deadline.md +1 -1
- package/knowledge/decisions/internals/workflow-core-never-imports-a-browser-driver.md +1 -1
- package/knowledge/decisions/internals/workflow-inline-runs-report-their-run-id-before-they-can-fail.md +1 -1
- package/knowledge/decisions/internals/workflow-invocation-id-is-the-dedupe-key-not-step-id.md +1 -1
- package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md +1 -1
- package/knowledge/decisions/internals/workflow-run-timeline-is-a-pure-fold-over-durable-history.md +1 -1
- package/knowledge/decisions/internals/workflow-scenario-assertions-never-retry-and-record-one-step.md +9 -5
- package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md +1 -1
- package/knowledge/decisions/internals/workflow-step-rpc-name-is-provenance-only.md +2 -2
- package/knowledge/decisions/internals/workflow-suspend-and-approval-reasons-are-durable-step-identities.md +1 -1
- package/knowledge/decisions/security/a-function-never-receives-the-secret-service.md +1 -1
- package/knowledge/decisions/security/a-scaffold-flag-says-a-surface-exists-not-who-may-call-it.md +47 -0
- package/knowledge/decisions/security/a-step-runs-the-function-the-workflow-dispatched-it-with.md +1 -1
- package/knowledge/decisions/security/a-virtual-user-is-never-offered-a-step-that-would-forge-its-own-oracle.md +2 -3
- package/knowledge/decisions/security/actor-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md +1 -1
- package/knowledge/decisions/security/addon-auth-and-tags-only-tighten.md +1 -1
- package/knowledge/decisions/security/agent-gate-requires-a-session-only-when-auth-is-true.md +1 -1
- package/knowledge/decisions/security/an-approval-answer-outlives-the-run-it-answered.md +3 -3
- package/knowledge/decisions/security/console-addon-privileged-functions-gate-themselves.md +4 -3
- package/knowledge/decisions/security/core-safe-fetch-blocks-ssrf-by-host-literal-not-dns.md +1 -1
- package/knowledge/decisions/security/gateway-middleware-sessions-must-be-bridged-onto-the-wire.md +2 -2
- package/knowledge/decisions/security/global-permissions-and-function-permissions-are-independent-gates.md +1 -1
- package/knowledge/decisions/security/http-request-bodies-are-bounded-before-they-are-buffered.md +2 -2
- package/knowledge/decisions/security/index.md +4 -1
- package/knowledge/decisions/security/mcp-internal-error-details-are-double-gated-on-production.md +1 -1
- package/knowledge/decisions/security/queue-jobs-carry-the-producers-pikku-user-id.md +3 -3
- package/knowledge/decisions/security/remote-addon-tokens-are-client-credentials-not-mesh-trust.md +1 -1
- package/knowledge/decisions/security/scaffold-features-are-authenticated-unless-opted-out.md +8 -2
- package/knowledge/decisions/security/self-authentication-is-declared-not-detected.md +1 -1
- package/knowledge/decisions/security/signed-content-urls-bind-the-request-path.md +2 -2
- package/knowledge/index.md +3 -1
- package/knowledge/questions/channel-middleware-accepts-bare-factories-that-nothing-resolves.md +1 -1
- package/knowledge/questions/index.md +2 -0
- package/package.json +14 -13
- package/run-tests.sh +0 -0
- package/scripts/generate-api-report.d.mts +1 -1
- package/scripts/generate-api-report.mjs +67 -60
- package/scripts/generate-api-report.mts +11 -45
- package/src/api-report.test.ts +70 -1
- package/src/app-alias-surface.test.ts +179 -0
- package/src/app-leaf-surface.test.ts +217 -0
- package/src/bootstrap-compat/root.ts +20 -0
- package/src/{column-form.test.ts → classification/column-form.test.ts} +2 -2
- package/src/{data-classification.ts → classification/data-classification.ts} +1 -5
- package/src/classification/index.ts +38 -0
- package/src/{secret-value.test.ts → classification/secret-value.test.ts} +2 -2
- package/src/{secret-value.ts → classification/secret-value.ts} +1 -6
- package/src/crypto-utils.ts +1 -1
- package/src/dev/hot-reload.ts +1 -1
- package/src/dev/reload-meta.test.ts +1 -1
- package/src/errors/index.ts +9 -0
- package/src/errors/serialized-error.ts +9 -0
- package/src/factory-functions.test.ts +4 -2
- package/src/function/function-meta.types.ts +151 -0
- package/src/function/function-runner.test.ts +4 -2
- package/src/function/function-runner.ts +47 -14
- package/src/function/functions.types.ts +11 -7
- package/src/function/index.ts +24 -5
- package/src/function/list.types.ts +1 -3
- package/src/middleware/auth-apikey.ts +4 -2
- package/src/middleware/auth-bearer.test.ts +1 -1
- package/src/middleware/auth-bearer.ts +4 -2
- package/src/middleware/auth-cookie.ts +4 -1
- package/src/middleware/cors.test.ts +126 -5
- package/src/middleware/cors.ts +19 -8
- package/src/middleware/index.ts +16 -0
- package/src/middleware/middleware-factories.ts +62 -0
- package/src/middleware/middleware.types.ts +61 -0
- package/src/middleware/remote-auth.test.ts +1 -1
- package/src/middleware/remote-auth.ts +1 -1
- package/src/middleware/telemetry.ts +4 -2
- package/src/middleware-runner.test.ts +2 -3
- package/src/middleware-runner.ts +2 -2
- package/src/no-root-barrel.test.ts +114 -0
- package/src/permissions.ts +2 -4
- package/src/pikku-state.ts +3 -1
- package/src/public-surface.json +56 -241
- package/src/public-surface.json.README +3 -3
- package/src/public-surface.test.ts +5 -5
- package/src/remote.test.ts +1 -1
- package/src/removed-legacy-exports.test.ts +5 -1
- package/src/services/audit-service.ts +1 -1
- package/src/services/credential-wire-service.ts +1 -1
- package/src/services/email-service.ts +2 -4
- package/src/services/file-scenario-run-store.test.ts +349 -0
- package/src/services/file-scenario-run-store.ts +282 -0
- package/src/services/in-memory-workflow-service.ts +1 -1
- package/src/services/index.ts +13 -1
- package/src/services/local-content-request-handler.ts +1 -2
- package/src/services/local-secrets.ts +1 -1
- package/src/services/logger.ts +7 -7
- package/src/services/meta-service.ts +2 -2
- package/src/services/queue-webhook-service.test.ts +1 -1
- package/src/services/scoped-secret-service.ts +1 -1
- package/src/services/secret-service.ts +1 -1
- package/src/services/typed-secret-service.test.ts +52 -0
- package/src/services/typed-secret-service.ts +26 -2
- package/src/services/webhook-service.ts +1 -1
- package/src/services/workflow-service.ts +2 -1
- package/src/template-alias-surface.test.ts +240 -0
- package/src/testing/index.ts +1 -0
- package/src/types/core.types.ts +33 -285
- package/src/types/index.ts +25 -0
- package/src/types/state.types.ts +6 -5
- package/src/types/typed-credentials.test.ts +72 -0
- package/src/utils.ts +34 -0
- package/src/wirings/{rpc → addon}/addon-scopes.test.ts +1 -1
- package/src/wirings/addon/index.ts +12 -0
- package/src/wirings/{rpc → addon}/remote-addon-auth.ts +4 -1
- package/src/wirings/{rpc → addon}/wire-addon.ts +37 -2
- package/src/wirings/agent/agent-memory.test.ts +73 -0
- package/src/wirings/agent/agent-memory.ts +16 -2
- package/src/wirings/agent/agent-middleware.types.test.ts +41 -0
- package/src/wirings/agent/agent-prepare.ts +8 -5
- package/src/wirings/agent/agent-runner.ts +2 -3
- package/src/wirings/agent/agent-stream-delegate.test.ts +381 -0
- package/src/wirings/agent/agent-stream.ts +160 -81
- package/src/wirings/agent/agent-utils.ts +19 -0
- package/src/wirings/agent/agent.types.ts +12 -11
- package/src/wirings/agent/index.ts +1 -0
- package/src/wirings/agent/voice-input.ts +1 -1
- package/src/wirings/agent/voice-output.test.ts +2 -4
- package/src/wirings/agent/voice-output.ts +1 -1
- package/src/wirings/agent-scorer/agent-scorer-judge.test.ts +145 -0
- package/src/wirings/agent-scorer/agent-scorer-judge.ts +60 -0
- package/src/wirings/agent-scorer/agent-scorer.ts +8 -0
- package/src/wirings/agent-scorer/agent-scorer.types.ts +21 -0
- package/src/wirings/agent-scorer/index.ts +1 -0
- package/src/wirings/channel/channel-common.ts +4 -2
- package/src/wirings/channel/channel-handler.ts +2 -5
- package/src/wirings/channel/channel-middleware-runner.ts +1 -1
- package/src/wirings/channel/channel-rpc.types.ts +1 -5
- package/src/wirings/channel/channel.types.ts +1 -2
- package/src/wirings/channel/local/local-channel-runner.test.ts +1 -2
- package/src/wirings/channel/serverless/index.ts +1 -0
- package/src/wirings/cli/channel/cli-raw-channel-runner.ts +2 -2
- package/src/wirings/cli/channel/index.ts +1 -3
- package/src/wirings/cli/cli-runner.test.ts +1 -1
- package/src/wirings/cli/cli-runner.ts +11 -7
- package/src/wirings/cli/cli.types.ts +24 -3
- package/src/wirings/cli/command-parser.test.ts +388 -1
- package/src/wirings/cli/command-parser.ts +189 -29
- package/src/wirings/gateway/gateway-runner.test.ts +1 -2
- package/src/wirings/gateway/gateway-runner.ts +3 -6
- package/src/wirings/gateway/gateway.types.ts +5 -4
- package/src/wirings/http/http-routes.test.ts +1 -2
- package/src/wirings/http/http-runner-addon-ref.test.ts +238 -0
- package/src/wirings/http/http-runner.test.ts +3 -8
- package/src/wirings/http/http-runner.ts +9 -3
- package/src/wirings/http/http.types.ts +3 -12
- package/src/wirings/http/index.ts +1 -0
- package/src/wirings/http/pikku-fetch-http-request.ts +1 -1
- package/src/wirings/http/pikku-fetch-http-response.ts +3 -2
- package/src/wirings/mcp/mcp-runner.test.ts +1 -1
- package/src/wirings/mcp/mcp.types.ts +1 -2
- package/src/wirings/persona/index.ts +1 -4
- package/src/wirings/persona/persona.types.ts +14 -0
- package/src/wirings/queue/queue-identity.test.ts +1 -1
- package/src/wirings/queue/queue.types.ts +2 -6
- package/src/wirings/queue/signed-queue-service.ts +1 -1
- package/src/wirings/rpc/index.ts +0 -12
- package/src/wirings/rpc/rpc-runner.test.ts +4 -4
- package/src/wirings/rpc/rpc-runner.ts +3 -3
- package/src/wirings/scheduler/scheduler.types.ts +2 -5
- package/src/wirings/scope/index.ts +1 -0
- package/src/wirings/secret/secret.types.ts +10 -0
- package/src/wirings/secret/validate-secret-definitions.test.ts +23 -0
- package/src/wirings/secret/validate-secret-definitions.ts +2 -0
- package/src/wirings/variable/validate-variable-definitions.test.ts +24 -0
- package/src/wirings/variable/validate-variable-definitions.ts +2 -0
- package/src/wirings/variable/variable.types.ts +15 -0
- package/src/wirings/virtual-user/index.ts +1 -4
- package/src/wirings/virtual-user/prepare-virtual-user-run.ts +1 -1
- package/src/wirings/virtual-user/virtual-user-derive.test.ts +1 -1
- package/src/wirings/virtual-user/virtual-user-derive.ts +1 -1
- package/src/wirings/virtual-user/virtual-user.types.ts +1 -5
- package/src/wirings/workflow/graph/graph-foreach-queued.test.ts +569 -0
- package/src/wirings/workflow/graph/graph-foreach.test.ts +626 -0
- package/src/wirings/workflow/graph/graph-node.ts +16 -1
- package/src/wirings/workflow/graph/graph-runner.ts +387 -61
- package/src/wirings/workflow/graph/workflow-graph.types.ts +28 -3
- package/src/wirings/workflow/index.ts +8 -0
- package/src/wirings/workflow/pikku-scenario-service.ts +83 -20
- package/src/wirings/workflow/pikku-workflow-service.ts +37 -35
- package/src/wirings/workflow/run-timeline.ts +1 -1
- package/src/wirings/workflow/scenario-expectations.test.ts +28 -13
- package/src/wirings/workflow/scenario-run.types.ts +186 -0
- package/src/wirings/workflow/scenario-step-guards.ts +1 -14
- package/src/wirings/workflow/scenario-step.test.ts +32 -7
- package/src/wirings/workflow/scenario-step.types.ts +27 -12
- package/src/wirings/workflow/workflow-approval-policy.test.ts +117 -47
- package/src/wirings/workflow/workflow-approval.ts +2 -1
- package/src/wirings/workflow/workflow-run-engine.types.ts +2 -1
- package/src/wirings/workflow/workflow-step-claim.ts +46 -0
- package/src/wirings/workflow/workflow.types.ts +4 -12
- package/src/wirings-stay-decoupled.test.ts +6 -3
- package/tsconfig.tsbuildinfo +1 -1
- package/tsconfig.type-tests.json +4 -2
- package/dist/ecosystem/ai-agent.d.ts +0 -18
- package/dist/ecosystem/ai-agent.js +0 -6
- package/dist/ecosystem/ai-scorer.d.ts +0 -12
- package/dist/ecosystem/ai-scorer.js +0 -5
- package/dist/services/ai-agent-runner-service.d.ts +0 -220
- package/dist/services/ai-run-state-service.d.ts +0 -29
- package/dist/services/ai-storage-service.d.ts +0 -18
- package/dist/services/in-memory-ai-run-state-service.d.ts +0 -19
- package/dist/services/in-memory-ai-run-state-service.js +0 -54
- package/dist/testing/service-tests/ai-storage-service-tests.d.ts +0 -3
- package/dist/testing/service-tests/ai-storage-service-tests.js +0 -302
- package/dist/wirings/ai-agent/agent-rpc.d.ts +0 -15
- package/dist/wirings/ai-agent/agent-rpc.js +0 -53
- package/dist/wirings/ai-agent/ai-agent-agui.d.ts +0 -79
- package/dist/wirings/ai-agent/ai-agent-agui.js +0 -327
- package/dist/wirings/ai-agent/ai-agent-finalize.d.ts +0 -58
- package/dist/wirings/ai-agent/ai-agent-finalize.js +0 -138
- package/dist/wirings/ai-agent/ai-agent-helpers.d.ts +0 -35
- package/dist/wirings/ai-agent/ai-agent-helpers.js +0 -47
- package/dist/wirings/ai-agent/ai-agent-interrupt.d.ts +0 -153
- package/dist/wirings/ai-agent/ai-agent-interrupt.js +0 -257
- package/dist/wirings/ai-agent/ai-agent-memory.d.ts +0 -42
- package/dist/wirings/ai-agent/ai-agent-memory.js +0 -333
- package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +0 -16
- package/dist/wirings/ai-agent/ai-agent-model-config.js +0 -51
- package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +0 -117
- package/dist/wirings/ai-agent/ai-agent-prepare.js +0 -728
- package/dist/wirings/ai-agent/ai-agent-registry.d.ts +0 -16
- package/dist/wirings/ai-agent/ai-agent-registry.js +0 -51
- package/dist/wirings/ai-agent/ai-agent-runner.d.ts +0 -7
- package/dist/wirings/ai-agent/ai-agent-runner.js +0 -580
- package/dist/wirings/ai-agent/ai-agent-stream.d.ts +0 -41
- package/dist/wirings/ai-agent/ai-agent-stream.js +0 -1029
- package/dist/wirings/ai-agent/ai-agent-turn.d.ts +0 -57
- package/dist/wirings/ai-agent/ai-agent-turn.js +0 -82
- package/dist/wirings/ai-agent/ai-agent-utils.d.ts +0 -1
- package/dist/wirings/ai-agent/ai-agent-utils.js +0 -1
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +0 -625
- package/dist/wirings/ai-agent/index.d.ts +0 -12
- package/dist/wirings/ai-agent/index.js +0 -10
- package/dist/wirings/ai-agent/voice-input.d.ts +0 -69
- package/dist/wirings/ai-agent/voice-input.js +0 -150
- package/dist/wirings/ai-agent/voice-output.d.ts +0 -85
- package/dist/wirings/ai-agent/voice-output.js +0 -196
- package/dist/wirings/ai-scorer/ai-scorer-grade.d.ts +0 -26
- package/dist/wirings/ai-scorer/ai-scorer-grade.js +0 -33
- package/dist/wirings/ai-scorer/ai-scorer-judge.d.ts +0 -17
- package/dist/wirings/ai-scorer/ai-scorer-judge.js +0 -92
- package/dist/wirings/ai-scorer/ai-scorer-live.d.ts +0 -15
- package/dist/wirings/ai-scorer/ai-scorer-live.js +0 -38
- package/dist/wirings/ai-scorer/ai-scorer-registry.d.ts +0 -18
- package/dist/wirings/ai-scorer/ai-scorer-registry.js +0 -46
- package/dist/wirings/ai-scorer/ai-scorer-sampling.d.ts +0 -8
- package/dist/wirings/ai-scorer/ai-scorer-sampling.js +0 -31
- package/dist/wirings/ai-scorer/ai-scorer-snapshots.d.ts +0 -10
- package/dist/wirings/ai-scorer/ai-scorer-snapshots.js +0 -40
- package/dist/wirings/ai-scorer/ai-scorer-worker.d.ts +0 -15
- package/dist/wirings/ai-scorer/ai-scorer-worker.js +0 -58
- package/dist/wirings/ai-scorer/ai-scorer.d.ts +0 -39
- package/dist/wirings/ai-scorer/ai-scorer.js +0 -40
- package/dist/wirings/ai-scorer/ai-scorer.types.d.ts +0 -90
- package/dist/wirings/ai-scorer/ai-scorer.types.js +0 -4
- package/dist/wirings/ai-scorer/index.d.ts +0 -6
- package/dist/wirings/ai-scorer/index.js +0 -5
- package/src/ecosystem/agent-scorer.ts +0 -24
- package/src/ecosystem/agent.ts +0 -42
- package/src/ecosystem/channel/local.ts +0 -1
- package/src/ecosystem/channel.ts +0 -22
- package/src/ecosystem/cli/channel.ts +0 -25
- package/src/ecosystem/cli.ts +0 -21
- package/src/ecosystem/credential.ts +0 -10
- package/src/ecosystem/dev.ts +0 -12
- package/src/ecosystem/function.ts +0 -28
- package/src/ecosystem/gateway.ts +0 -4
- package/src/ecosystem/hmac.ts +0 -1
- package/src/ecosystem/http.ts +0 -22
- package/src/ecosystem/mcp.ts +0 -17
- package/src/ecosystem/middleware.ts +0 -27
- package/src/ecosystem/node-host-resolver.ts +0 -1
- package/src/ecosystem/node.ts +0 -5
- package/src/ecosystem/oauth2.ts +0 -4
- package/src/ecosystem/persona.ts +0 -30
- package/src/ecosystem/queue.ts +0 -23
- package/src/ecosystem/remote.ts +0 -9
- package/src/ecosystem/role.ts +0 -13
- package/src/ecosystem/rpc.ts +0 -7
- package/src/ecosystem/safe-fetch.ts +0 -8
- package/src/ecosystem/scenario.ts +0 -32
- package/src/ecosystem/scheduler.ts +0 -5
- package/src/ecosystem/schema.ts +0 -1
- package/src/ecosystem/scope.ts +0 -14
- package/src/ecosystem/secret.ts +0 -15
- package/src/ecosystem/services/istanbul-coverage.ts +0 -1
- package/src/ecosystem/services/local-content-request-handler.ts +0 -16
- package/src/ecosystem/services/local-content.ts +0 -1
- package/src/ecosystem/services/v8-coverage.ts +0 -1
- package/src/ecosystem/services.ts +0 -82
- package/src/ecosystem/trigger.ts +0 -7
- package/src/ecosystem/types.ts +0 -34
- package/src/ecosystem/variable.ts +0 -14
- package/src/ecosystem/virtual-user.ts +0 -48
- package/src/ecosystem/workflow.ts +0 -68
- package/src/ecosystem.ts +0 -40
- package/src/index.ts +0 -244
- /package/dist/{services/ai-agent-runner-service.js → bootstrap-compat/root.js} +0 -0
- /package/dist/{services/ai-run-state-service.js → classification/data-classification.js} +0 -0
- /package/dist/{services/ai-storage-service.js → errors/serialized-error.js} +0 -0
- /package/dist/{wirings/ai-agent/ai-agent.types.js → function/function-meta.types.js} +0 -0
- /package/src/{column-form.ts → classification/column-form.ts} +0 -0
- /package/src/{pikku-request.test.ts → function/pikku-request.test.ts} +0 -0
- /package/src/{pikku-request.ts → function/pikku-request.ts} +0 -0
- /package/src/wirings/{rpc → addon}/addon-auth-tags.test.ts +0 -0
- /package/src/wirings/{rpc → addon}/addon-runner.ts +0 -0
- /package/src/wirings/{rpc → addon}/addon-secrets.test.ts +0 -0
- /package/src/wirings/{rpc → addon}/wire-addon.test.ts +0 -0
- /package/src/wirings/{rpc → addon}/wire-remote-addon.ts +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { CoreUserSession
|
|
1
|
+
import type { CoreUserSession } from '../../types/core.types.js';
|
|
2
|
+
import type { SerializedError } from '../../errors/serialized-error.js';
|
|
2
3
|
import type { GroupConcurrencyConfig, JobGroup, JobOptions } from '../queue/queue.types.js';
|
|
3
4
|
import type { PikkuWorkflowWire, StepState, StepStatus, WorkflowPlannedStep, WorkflowRun, WorkflowRunMirror, WorkflowRunStatus, WorkflowRunWire, WorkflowStatus, WorkflowVersionStatus, WorkflowQueueOptions, WorkflowStepOptions } from './workflow.types.js';
|
|
4
5
|
import type { WorkflowService } from '../../services/workflow-service.js';
|
|
@@ -104,12 +105,12 @@ export declare abstract class PikkuWorkflowService implements WorkflowService {
|
|
|
104
105
|
*
|
|
105
106
|
* Returns nothing by default so a store that cannot express the query keeps
|
|
106
107
|
* working unchanged — and, because it does not opt in, gains no re-dispatches
|
|
107
|
-
* either. A store must have an atomic `
|
|
108
|
-
* or no concurrency for one to exclude: the relay makes
|
|
109
|
-
* routine, and the claim
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
108
|
+
* either. A store must have an atomic `claimStepForExecution` before
|
|
109
|
+
* overriding this, or no concurrency for one to exclude: the relay makes
|
|
110
|
+
* duplicate dispatch routine, and the claim is what keeps a duplicate from
|
|
111
|
+
* becoming a second execution. Every `@pikku/kysely` dialect qualifies on its
|
|
112
|
+
* status-guarded claim, `in-memory` on being inline and single-process;
|
|
113
|
+
* `mongodb` still qualifies on neither.
|
|
113
114
|
*/
|
|
114
115
|
protected findUndispatchedSteps(_before: Date, _limit: number): Promise<Array<{
|
|
115
116
|
runId: string;
|
|
@@ -175,6 +176,20 @@ export declare abstract class PikkuWorkflowService implements WorkflowService {
|
|
|
175
176
|
protected onChildWorkflowFailed(childRun: WorkflowRun, error: Error): Promise<void>;
|
|
176
177
|
private runVersionMismatchFallback;
|
|
177
178
|
executeWorkflowStep(runId: string, stepName: string, rpcName: string, data: any, rpcService: PikkuRPC): Promise<void>;
|
|
179
|
+
/**
|
|
180
|
+
* Take sole ownership of a step before it runs, returning the state to run
|
|
181
|
+
* under — or `null` when another dispatch already owns it.
|
|
182
|
+
*
|
|
183
|
+
* Dispatch is at-least-once by design: the relay re-dispatches steps it
|
|
184
|
+
* believes were dropped, and a queue can redeliver a job it already handed
|
|
185
|
+
* out. This is the one place that keeps a duplicate dispatch from becoming a
|
|
186
|
+
* second execution of a side-effecting step, so it is only as strong as the
|
|
187
|
+
* exclusion it is built on — and `withStepLock` excludes nothing unless the
|
|
188
|
+
* store backs it with a real primitive. A store able to express the decision
|
|
189
|
+
* as one conditional write should override this rather than reach for a lock,
|
|
190
|
+
* which is what `@pikku/kysely` does with a status-guarded `UPDATE`.
|
|
191
|
+
*/
|
|
192
|
+
protected claimStepForExecution(runId: string, stepName: string, rpcName: string): Promise<StepState | null>;
|
|
178
193
|
private executeWorkflowStepInner;
|
|
179
194
|
orchestrateWorkflow(runId: string, rpcService: PikkuRPC): Promise<void>;
|
|
180
195
|
private verifyQueueService;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { runPikkuFunc } from '../../function/function-runner.js';
|
|
2
2
|
import { getSingletonServices, getCreateWireServices, pikkuState, } from '../../pikku-state.js';
|
|
3
3
|
import { getDurationInMilliseconds } from '../../time-utils.js';
|
|
4
|
-
import { ChildWorkflowStartedException, continueGraph, executeGraphStep, runWorkflowGraph, runFromMeta, } from './graph/graph-runner.js';
|
|
4
|
+
import { ChildWorkflowStartedException, continueGraph, executeGraphStep, runWorkflowGraph, runFromMeta, stripInstanceOrdinal, } from './graph/graph-runner.js';
|
|
5
5
|
import { isExpectedError } from '../../errors/error-handler.js';
|
|
6
6
|
import { PikkuMissingMetaError } from '../../errors/errors.js';
|
|
7
7
|
import { RPCNotFoundError } from '../rpc/rpc-runner.js';
|
|
@@ -9,13 +9,14 @@ import { deriveInvocationId } from './workflow-invocation-id.js';
|
|
|
9
9
|
import { approvalDeciderFrom } from './workflow-approval-policy.js';
|
|
10
10
|
import { buildRunTimeline, reconstructStateAt, } from './run-timeline.js';
|
|
11
11
|
import { DEFAULT_STEP_RETRIES, WORKFLOW_CHILD_POLL_MAX_MS, WORKFLOW_END_STATES, WORKFLOW_POLL_FACTOR, WORKFLOW_POLL_MIN_MS, WORKFLOW_TERMINAL_STATES, } from './workflow-constants.js';
|
|
12
|
-
import { WorkflowAsyncException, WorkflowCancelledException, WorkflowDispatchException, WorkflowNotFoundError, WorkflowRunCancelledError, WorkflowRunFailedError, WorkflowRunNotFoundError,
|
|
12
|
+
import { WorkflowAsyncException, WorkflowCancelledException, WorkflowDispatchException, WorkflowNotFoundError, WorkflowRunCancelledError, WorkflowRunFailedError, WorkflowRunNotFoundError, WorkflowStepNameNotString, WorkflowSuspendedException, } from './workflow-errors.js';
|
|
13
13
|
import { resolveWorkflowMeta } from './workflow-meta-resolver.js';
|
|
14
14
|
import { jobGroupFor, orchestratorQueueName, resolveWorkflowConfig, stepJobOptions, stepWorkerQueueName, } from './workflow-queue-routing.js';
|
|
15
15
|
import { wireWorkflowQueueWorkers } from './workflow-queue-wiring.js';
|
|
16
16
|
import { approvalStepNameFor, evaluateApprovalStep, recordApprovalDecision, } from './workflow-approval.js';
|
|
17
17
|
import { auditApprovalDecision } from './workflow-approval-audit.js';
|
|
18
18
|
import { recordSuspension, suspendStepNameFor } from './workflow-suspend.js';
|
|
19
|
+
import { claimStepByReadThenWrite } from './workflow-step-claim.js';
|
|
19
20
|
import { RedispatchBackoff, sweepStalledRuns, sweepUndispatchedSteps, } from './workflow-recovery.js';
|
|
20
21
|
export class PikkuWorkflowService {
|
|
21
22
|
runExtension;
|
|
@@ -261,12 +262,12 @@ export class PikkuWorkflowService {
|
|
|
261
262
|
*
|
|
262
263
|
* Returns nothing by default so a store that cannot express the query keeps
|
|
263
264
|
* working unchanged — and, because it does not opt in, gains no re-dispatches
|
|
264
|
-
* either. A store must have an atomic `
|
|
265
|
-
* or no concurrency for one to exclude: the relay makes
|
|
266
|
-
* routine, and the claim
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
*
|
|
265
|
+
* either. A store must have an atomic `claimStepForExecution` before
|
|
266
|
+
* overriding this, or no concurrency for one to exclude: the relay makes
|
|
267
|
+
* duplicate dispatch routine, and the claim is what keeps a duplicate from
|
|
268
|
+
* becoming a second execution. Every `@pikku/kysely` dialect qualifies on its
|
|
269
|
+
* status-guarded claim, `in-memory` on being inline and single-process;
|
|
270
|
+
* `mongodb` still qualifies on neither.
|
|
270
271
|
*/
|
|
271
272
|
async findUndispatchedSteps(_before, _limit) {
|
|
272
273
|
return [];
|
|
@@ -697,25 +698,24 @@ export class PikkuWorkflowService {
|
|
|
697
698
|
this.exitExecution(runId);
|
|
698
699
|
}
|
|
699
700
|
}
|
|
701
|
+
/**
|
|
702
|
+
* Take sole ownership of a step before it runs, returning the state to run
|
|
703
|
+
* under — or `null` when another dispatch already owns it.
|
|
704
|
+
*
|
|
705
|
+
* Dispatch is at-least-once by design: the relay re-dispatches steps it
|
|
706
|
+
* believes were dropped, and a queue can redeliver a job it already handed
|
|
707
|
+
* out. This is the one place that keeps a duplicate dispatch from becoming a
|
|
708
|
+
* second execution of a side-effecting step, so it is only as strong as the
|
|
709
|
+
* exclusion it is built on — and `withStepLock` excludes nothing unless the
|
|
710
|
+
* store backs it with a real primitive. A store able to express the decision
|
|
711
|
+
* as one conditional write should override this rather than reach for a lock,
|
|
712
|
+
* which is what `@pikku/kysely` does with a status-guarded `UPDATE`.
|
|
713
|
+
*/
|
|
714
|
+
async claimStepForExecution(runId, stepName, rpcName) {
|
|
715
|
+
return this.withStepLock(runId, stepName, () => claimStepByReadThenWrite(this, runId, stepName, rpcName));
|
|
716
|
+
}
|
|
700
717
|
async executeWorkflowStepInner(runId, stepName, rpcName, data, rpcService) {
|
|
701
|
-
const claimed = await this.
|
|
702
|
-
const stepState = await this.getStepState(runId, stepName);
|
|
703
|
-
// knowledge: decisions/security/a-step-runs-the-function-the-workflow-dispatched-it-with.md
|
|
704
|
-
if (stepState.rpcName !== undefined &&
|
|
705
|
-
stepState.rpcName !== (rpcName ?? null)) {
|
|
706
|
-
throw new WorkflowStepFunctionMismatchError(runId, stepName);
|
|
707
|
-
}
|
|
708
|
-
if (stepState.status === 'succeeded' || stepState.status === 'running') {
|
|
709
|
-
return null;
|
|
710
|
-
}
|
|
711
|
-
if (stepState.status === 'failed') {
|
|
712
|
-
return this.createRetryAttempt(stepState.stepId, 'running');
|
|
713
|
-
}
|
|
714
|
-
if (stepState.status === 'pending' || stepState.status === 'scheduled') {
|
|
715
|
-
await this.setStepRunning(stepState.stepId);
|
|
716
|
-
}
|
|
717
|
-
return stepState;
|
|
718
|
-
});
|
|
718
|
+
const claimed = await this.claimStepForExecution(runId, stepName, rpcName);
|
|
719
719
|
if (!claimed) {
|
|
720
720
|
return;
|
|
721
721
|
}
|
|
@@ -735,9 +735,8 @@ export class PikkuWorkflowService {
|
|
|
735
735
|
graphNodeId = stepName;
|
|
736
736
|
}
|
|
737
737
|
else {
|
|
738
|
-
const
|
|
739
|
-
|
|
740
|
-
if (base && base in workflowMeta.nodes)
|
|
738
|
+
const base = stripInstanceOrdinal(stepName);
|
|
739
|
+
if (base !== stepName && base in workflowMeta.nodes)
|
|
741
740
|
graphNodeId = base;
|
|
742
741
|
}
|
|
743
742
|
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What one `pikku scenario run` leaves behind.
|
|
3
|
+
*
|
|
4
|
+
* A run is history: the scenarios it selected, the sentences they were made of,
|
|
5
|
+
* and the images and footage they produced. The sentences are snapshotted into
|
|
6
|
+
* the record rather than looked up later, because a scenario is code and the
|
|
7
|
+
* code moves — a run from last week describes a suite that no longer exists,
|
|
8
|
+
* and re-deriving its ladder from today's source would quietly rewrite it.
|
|
9
|
+
*
|
|
10
|
+
* Everything here is plain serialisable data. That is what lets one record be
|
|
11
|
+
* a JSON file on disk in OSS and a row in Postgres on a hosted project, read
|
|
12
|
+
* back by the same console screen either way.
|
|
13
|
+
*/
|
|
14
|
+
import type { ScenarioBrowserFailure } from './scenario-step.types.js';
|
|
15
|
+
/** What a run filed, in the order it filed it. */
|
|
16
|
+
export type ScenarioArtifactKind = 'screenshot' | 'failure' | 'video';
|
|
17
|
+
/**
|
|
18
|
+
* One image or recording a scenario produced.
|
|
19
|
+
*
|
|
20
|
+
* `path` is relative to the run's artifact root and always uses forward
|
|
21
|
+
* slashes: it is a content key, not a filesystem path. Locally it resolves
|
|
22
|
+
* under the run's directory; on a hosted project it is the object key in a
|
|
23
|
+
* bucket, and the same record works unchanged.
|
|
24
|
+
*/
|
|
25
|
+
export interface ScenarioArtifact {
|
|
26
|
+
/** The scenario label this belongs to, as the report names it. */
|
|
27
|
+
scenario: string;
|
|
28
|
+
kind: ScenarioArtifactKind;
|
|
29
|
+
path: string;
|
|
30
|
+
/** Whose window it was — a two-actor scenario produces two of everything. */
|
|
31
|
+
actor?: string;
|
|
32
|
+
/** The caption the scenario author took a screenshot under. */
|
|
33
|
+
name?: string;
|
|
34
|
+
}
|
|
35
|
+
/** One step of a run, already joined to the prose that declared it. */
|
|
36
|
+
export interface ScenarioStepRow {
|
|
37
|
+
sentence: string;
|
|
38
|
+
status: string;
|
|
39
|
+
durationMs?: number;
|
|
40
|
+
error?: string;
|
|
41
|
+
}
|
|
42
|
+
/** Everything known about why one scenario failed. */
|
|
43
|
+
export interface ScenarioFailureDetail {
|
|
44
|
+
/** The rendered sentence of the failing step; absent if no step failed. */
|
|
45
|
+
sentence?: string;
|
|
46
|
+
message: string;
|
|
47
|
+
stack?: string;
|
|
48
|
+
/**
|
|
49
|
+
* True when the failure was a deliberate one (a PikkuError). Its message is
|
|
50
|
+
* the whole story, so the stack is noise.
|
|
51
|
+
*/
|
|
52
|
+
expected?: boolean;
|
|
53
|
+
browser?: ScenarioBrowserFailure[];
|
|
54
|
+
}
|
|
55
|
+
export interface ScenarioResult {
|
|
56
|
+
name: string;
|
|
57
|
+
status: 'passed' | 'failed';
|
|
58
|
+
durationMs: number;
|
|
59
|
+
output?: unknown;
|
|
60
|
+
error?: string;
|
|
61
|
+
steps?: ScenarioStepRow[];
|
|
62
|
+
failure?: ScenarioFailureDetail;
|
|
63
|
+
/** The scenario registration this ran, which the label alone does not give. */
|
|
64
|
+
scenarioName?: string;
|
|
65
|
+
/** The feature that grouped it, when one did. */
|
|
66
|
+
feature?: string;
|
|
67
|
+
tags?: string[];
|
|
68
|
+
/** Images and footage this scenario produced, filed under the run. */
|
|
69
|
+
artifacts?: ScenarioArtifact[];
|
|
70
|
+
}
|
|
71
|
+
/** One scenario that was not run, and why. */
|
|
72
|
+
export interface ScenarioSkip {
|
|
73
|
+
name: string;
|
|
74
|
+
reason: string;
|
|
75
|
+
}
|
|
76
|
+
export interface ScenarioRunReport {
|
|
77
|
+
environment: string;
|
|
78
|
+
results: ScenarioResult[];
|
|
79
|
+
/**
|
|
80
|
+
* Scenarios not run at all, each carrying why. A skip is only useful if the
|
|
81
|
+
* reader can tell a browser scenario held back by `--no-browser` from one the
|
|
82
|
+
* project itself quarantined, so the reason travels with the name rather than
|
|
83
|
+
* being assumed by the formatter.
|
|
84
|
+
*/
|
|
85
|
+
skipped: ScenarioSkip[];
|
|
86
|
+
/** Feature-level hook failures, which belong to no single scenario. */
|
|
87
|
+
hookFailures: string[];
|
|
88
|
+
}
|
|
89
|
+
export type ScenarioRunStatus = 'running' | 'passed' | 'failed';
|
|
90
|
+
/**
|
|
91
|
+
* A whole run, as it is stored and read back.
|
|
92
|
+
*
|
|
93
|
+
* `status` is `running` from the moment the run is created until it finishes,
|
|
94
|
+
* so a console watching a run in progress can tell "still going" from "nothing
|
|
95
|
+
* came back" — and a run killed halfway stays `running` forever, which is the
|
|
96
|
+
* honest record of what happened to it.
|
|
97
|
+
*/
|
|
98
|
+
export interface ScenarioRunRecord extends ScenarioRunReport {
|
|
99
|
+
runId: string;
|
|
100
|
+
status: ScenarioRunStatus;
|
|
101
|
+
/** The surface the run targeted: `default`, `browser`, … */
|
|
102
|
+
surface: string;
|
|
103
|
+
startedAt: string;
|
|
104
|
+
finishedAt?: string;
|
|
105
|
+
}
|
|
106
|
+
/** Enough of a run to list it without loading its steps and stacks. */
|
|
107
|
+
export interface ScenarioRunSummary {
|
|
108
|
+
runId: string;
|
|
109
|
+
environment: string;
|
|
110
|
+
surface: string;
|
|
111
|
+
status: ScenarioRunStatus;
|
|
112
|
+
startedAt: string;
|
|
113
|
+
finishedAt?: string;
|
|
114
|
+
durationMs?: number;
|
|
115
|
+
passed: number;
|
|
116
|
+
failed: number;
|
|
117
|
+
skipped: number;
|
|
118
|
+
/** Whether anything is there to watch, so a list can say so without a second read. */
|
|
119
|
+
artifacts: number;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Where runs are kept.
|
|
123
|
+
*
|
|
124
|
+
* Deliberately not the workflow service: a scenario run is a workflow run under
|
|
125
|
+
* the hood, but its history has a different lifetime, a different audience, and
|
|
126
|
+
* a different home — a JSON file beside the project locally, a project-scoped
|
|
127
|
+
* table and an object store when hosted.
|
|
128
|
+
*
|
|
129
|
+
* Written progressively rather than at the end, so a suite that dies on its
|
|
130
|
+
* fortieth scenario still leaves the thirty-nine behind.
|
|
131
|
+
*/
|
|
132
|
+
export interface ScenarioRunStore {
|
|
133
|
+
/** Open a run. Called before the first scenario, with `status: 'running'`. */
|
|
134
|
+
start(record: ScenarioRunRecord): Promise<void>;
|
|
135
|
+
/** Append one finished scenario to an open run. */
|
|
136
|
+
recordScenario(runId: string, result: ScenarioResult): Promise<void>;
|
|
137
|
+
/**
|
|
138
|
+
* File the run's artifacts against the scenarios that produced them.
|
|
139
|
+
*
|
|
140
|
+
* Separate from `recordScenario` because a scenario's video does not exist
|
|
141
|
+
* when the scenario ends — it is finalised by the next scenario's reset, and
|
|
142
|
+
* renamed again when the run closes. Artifacts are matched to a result by the
|
|
143
|
+
* label the report knows it under.
|
|
144
|
+
*/
|
|
145
|
+
attachArtifacts(runId: string, artifacts: ScenarioArtifact[]): Promise<void>;
|
|
146
|
+
/** Close a run, settling everything only known once every scenario has run. */
|
|
147
|
+
finish(runId: string, outcome: Pick<ScenarioRunRecord, 'status' | 'finishedAt' | 'skipped' | 'hookFailures'>): Promise<void>;
|
|
148
|
+
/**
|
|
149
|
+
* The bytes of one artifact, by the `path` its record carries.
|
|
150
|
+
*
|
|
151
|
+
* Reading goes through the store because only the store knows where a run's
|
|
152
|
+
* files actually are — a directory beside the project, or an object store
|
|
153
|
+
* behind a bucket. Absent when the run or the path is unknown, which is also
|
|
154
|
+
* the answer for a path that tries to leave the run.
|
|
155
|
+
*
|
|
156
|
+
* The bytes are backed by their own `ArrayBuffer` so they can be handed
|
|
157
|
+
* straight to a `Response` — a view onto a pooled or shared buffer is not a
|
|
158
|
+
* valid body.
|
|
159
|
+
*/
|
|
160
|
+
readArtifact(runId: string, path: string): Promise<{
|
|
161
|
+
body: Uint8Array<ArrayBuffer>;
|
|
162
|
+
contentType: string;
|
|
163
|
+
} | undefined>;
|
|
164
|
+
/** Most recent first. */
|
|
165
|
+
list(options?: {
|
|
166
|
+
limit?: number;
|
|
167
|
+
}): Promise<ScenarioRunSummary[]>;
|
|
168
|
+
get(runId: string): Promise<ScenarioRunRecord | undefined>;
|
|
169
|
+
/** Forget a run and everything it filed. */
|
|
170
|
+
remove(runId: string): Promise<void>;
|
|
171
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,3 +1,2 @@
|
|
|
1
1
|
import type { PikkuScenarioStepWire, ScenarioEnvironment } from './scenario-step.types.js';
|
|
2
|
-
export declare const
|
|
3
|
-
export declare const requireScenarioEnv: (scenarioStep: PikkuScenarioStepWire<unknown> | undefined) => ScenarioEnvironment;
|
|
2
|
+
export declare const requireScenarioEnv: (scenarioStep: PikkuScenarioStepWire | undefined) => ScenarioEnvironment;
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
export const requireActor = (scenarioStep) => {
|
|
2
|
-
const actor = scenarioStep?.actor;
|
|
3
|
-
if (!actor) {
|
|
4
|
-
throw new Error(`[scenario] step '${scenarioStep?.name ?? 'unknown'}' was called without an actor. ` +
|
|
5
|
-
`Pass { actor: actors.<name> } so it runs as that persona.`);
|
|
6
|
-
}
|
|
7
|
-
return actor;
|
|
8
|
-
};
|
|
9
1
|
export const requireScenarioEnv = (scenarioStep) => {
|
|
10
2
|
const env = scenarioStep?.env;
|
|
11
3
|
if (!env) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ScenarioArtifact } from './scenario-run.types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Scenario steps: named, typed units of scenario behaviour.
|
|
4
4
|
*
|
|
@@ -86,7 +86,10 @@ export type ScenarioSurfaceResolution = {
|
|
|
86
86
|
* default to no retries.
|
|
87
87
|
*/
|
|
88
88
|
export interface ScenarioStepOptions {
|
|
89
|
-
/**
|
|
89
|
+
/**
|
|
90
|
+
* The actor this step runs as. Required for a step that declares `actor: true`
|
|
91
|
+
* or a `browser` binding; the runner refuses to dispatch one without it.
|
|
92
|
+
*/
|
|
90
93
|
actor?: unknown;
|
|
91
94
|
/** Overrides the step's own `description` for this call site only. */
|
|
92
95
|
description?: string;
|
|
@@ -107,11 +110,12 @@ export interface ScenarioEnvironment {
|
|
|
107
110
|
/**
|
|
108
111
|
* The `scenarioStep` wire, present on every scenario step invocation.
|
|
109
112
|
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
+
* The persona a step runs as is not here: it arrives as `wire.actor`, injected
|
|
114
|
+
* by the runner and typed as present exactly on the bindings that declared they
|
|
115
|
+
* need one. Keeping it off this interface is what makes that possible — a wire
|
|
116
|
+
* member can be required per binding, a property of one cannot.
|
|
113
117
|
*/
|
|
114
|
-
export interface PikkuScenarioStepWire
|
|
118
|
+
export interface PikkuScenarioStepWire {
|
|
115
119
|
/** Registered step name (also its pikkuFuncId) */
|
|
116
120
|
name: string;
|
|
117
121
|
/** Durable key within the run; may carry an `#ordinal` suffix when repeated */
|
|
@@ -123,12 +127,6 @@ export interface PikkuScenarioStepWire<TActor = ScenarioPersona> {
|
|
|
123
127
|
* per witness, so its body sees this change between invocations.
|
|
124
128
|
*/
|
|
125
129
|
surface: ScenarioSurface;
|
|
126
|
-
/**
|
|
127
|
-
* The actor this step runs as, when one was given. Call RPCs through it
|
|
128
|
-
* (`actor.invoke(...)`) so they run against the target environment as that
|
|
129
|
-
* persona.
|
|
130
|
-
*/
|
|
131
|
-
actor?: TActor;
|
|
132
130
|
/**
|
|
133
131
|
* The environment this run targets. A step runs in the CLI process, where
|
|
134
132
|
* there is no `variables` service — this is how a raw-HTTP step learns the
|
|
@@ -218,11 +216,28 @@ export interface ScenarioBrowserProvider {
|
|
|
218
216
|
* folder — findable only by timestamp.
|
|
219
217
|
*/
|
|
220
218
|
beginScenario?(scenario: string): void;
|
|
219
|
+
/**
|
|
220
|
+
* Report how the scenario that just ran finished.
|
|
221
|
+
*
|
|
222
|
+
* Called after each scenario, and separate from `reset()` because artifacts
|
|
223
|
+
* that only exist once a window closes — a video — are produced by the NEXT
|
|
224
|
+
* scenario's reset, long after the outcome that decides whether to keep them.
|
|
225
|
+
*/
|
|
226
|
+
endScenario?(outcome: 'passed' | 'failed'): void;
|
|
221
227
|
/**
|
|
222
228
|
* Snapshot every open window for a failed scenario. `label` identifies the
|
|
223
229
|
* scenario in artifact filenames. Never throws: a failure to capture must
|
|
224
230
|
* not replace the failure being captured.
|
|
225
231
|
*/
|
|
226
232
|
captureFailure?(label: string): Promise<ScenarioBrowserFailure[]>;
|
|
233
|
+
/**
|
|
234
|
+
* Everything the run filed, each entry naming the scenario it belongs to.
|
|
235
|
+
*
|
|
236
|
+
* Reported by the driver rather than discovered by scanning the directory:
|
|
237
|
+
* only the driver knows which window produced a file and under what caption,
|
|
238
|
+
* and a video's final name is not settled until the run closes. Read after
|
|
239
|
+
* `close()`, which is the first moment the answer is complete.
|
|
240
|
+
*/
|
|
241
|
+
artifacts?(): ScenarioArtifact[];
|
|
227
242
|
close(): Promise<void>;
|
|
228
243
|
}
|
|
@@ -103,7 +103,8 @@ export const evaluateApprovalStep = async (store, runId, reason, approvalStepNam
|
|
|
103
103
|
return stepState.result;
|
|
104
104
|
}
|
|
105
105
|
const stateKey = approvalStateKey(approvalStepName);
|
|
106
|
-
let record = ((await store.getRunState(runId))[stateKey] ??
|
|
106
|
+
let record = ((await store.getRunState(runId))[stateKey] ??
|
|
107
|
+
{});
|
|
107
108
|
const policy = {
|
|
108
109
|
approvers: options.approvers,
|
|
109
110
|
approverScope: options.approverScope,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { PikkuRawWire
|
|
1
|
+
import type { PikkuRawWire } from '../../types/core.types.js';
|
|
2
|
+
import type { SerializedError } from '../../errors/serialized-error.js';
|
|
2
3
|
import type { CoreWorkflow, PikkuWorkflowWire, StepState, WorkflowRun, WorkflowStatus, WorkflowStepOptions } from './workflow.types.js';
|
|
3
4
|
export interface RunLifecycleContext {
|
|
4
5
|
runId: string;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { StepState } from './workflow.types.js';
|
|
2
|
+
/** What claiming a step needs from the workflow service. */
|
|
3
|
+
export type StepClaimStore = {
|
|
4
|
+
getStepState(runId: string, stepName: string): Promise<StepState>;
|
|
5
|
+
setStepRunning(stepId: string): Promise<void>;
|
|
6
|
+
createRetryAttempt(failedStepId: string, status: 'pending' | 'running'): Promise<StepState>;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Decide whether this dispatch owns the step, by reading its state and then
|
|
10
|
+
* writing it — which only excludes a concurrent dispatch when the caller holds
|
|
11
|
+
* a lock that genuinely excludes one.
|
|
12
|
+
*
|
|
13
|
+
* A store that can express the whole decision as a single conditional write
|
|
14
|
+
* should do that instead of calling this.
|
|
15
|
+
*/
|
|
16
|
+
export declare const claimStepByReadThenWrite: (store: StepClaimStore, runId: string, stepName: string, rpcName: string) => Promise<StepState | null>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { WorkflowStepFunctionMismatchError } from './workflow-errors.js';
|
|
2
|
+
/**
|
|
3
|
+
* Decide whether this dispatch owns the step, by reading its state and then
|
|
4
|
+
* writing it — which only excludes a concurrent dispatch when the caller holds
|
|
5
|
+
* a lock that genuinely excludes one.
|
|
6
|
+
*
|
|
7
|
+
* A store that can express the whole decision as a single conditional write
|
|
8
|
+
* should do that instead of calling this.
|
|
9
|
+
*/
|
|
10
|
+
export const claimStepByReadThenWrite = async (store, runId, stepName, rpcName) => {
|
|
11
|
+
const stepState = await store.getStepState(runId, stepName);
|
|
12
|
+
// knowledge: decisions/security/a-step-runs-the-function-the-workflow-dispatched-it-with.md
|
|
13
|
+
if (stepState.rpcName !== undefined &&
|
|
14
|
+
stepState.rpcName !== (rpcName ?? null)) {
|
|
15
|
+
throw new WorkflowStepFunctionMismatchError(runId, stepName);
|
|
16
|
+
}
|
|
17
|
+
if (stepState.status === 'succeeded' || stepState.status === 'running') {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
if (stepState.status === 'failed') {
|
|
21
|
+
return store.createRetryAttempt(stepState.stepId, 'running');
|
|
22
|
+
}
|
|
23
|
+
if (stepState.status === 'pending' || stepState.status === 'scheduled') {
|
|
24
|
+
await store.setStepRunning(stepState.stepId);
|
|
25
|
+
}
|
|
26
|
+
return stepState;
|
|
27
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CommonWireMeta } from '../../types/core.types.js';
|
|
2
|
+
import type { SerializedError } from '../../errors/serialized-error.js';
|
|
2
3
|
import type { CorePikkuFunctionConfig } from '../../function/functions.types.js';
|
|
3
4
|
import type { GroupConcurrencyConfig } from '../queue/queue.types.js';
|
|
4
5
|
export type { WorkflowService } from '../../services/workflow-service.js';
|
|
@@ -14,6 +14,8 @@ here first — several of these exist because the obvious simplification was tri
|
|
|
14
14
|
and broke something.
|
|
15
15
|
|
|
16
16
|
<!-- pikku:knowledge-index -->
|
|
17
|
+
|
|
17
18
|
- [internals](internals/index.md) — a rule about how it works under the hood, and why
|
|
18
19
|
- [security](security/index.md) — a rule about who may do what
|
|
20
|
+
|
|
19
21
|
<!-- /pikku:knowledge-index -->
|
|
@@ -14,7 +14,7 @@ A reporter fills those placeholders from a run that already happened. There is
|
|
|
14
14
|
no run yet at derivation time, so there is nothing to fill them from. More
|
|
15
15
|
importantly, filling them would answer the wrong question: "invites {email}"
|
|
16
16
|
tells the user to choose someone, where "invites ada@example.com" tells it whom
|
|
17
|
-
— and
|
|
17
|
+
— and _whom_ is the scenario author's answer, not something the virtual user
|
|
18
18
|
worked out.
|
|
19
19
|
|
|
20
20
|
**What this rules out:** substituting example or fixture values to make the
|
package/knowledge/decisions/internals/a-secret-that-fails-to-decrypt-fails-the-whole-read.md
CHANGED
|
@@ -37,7 +37,7 @@ that turn that into a one-line fix, and they are known at the catch site and
|
|
|
37
37
|
nowhere after it.
|
|
38
38
|
|
|
39
39
|
This matters most at exactly the moment it is least convenient: a change to
|
|
40
|
-
`deriveKEK` makes
|
|
40
|
+
`deriveKEK` makes _every_ previously stored secret undecryptable at once. Loud
|
|
41
41
|
failure names the first one; silence produces an empty map and a support ticket.
|
|
42
42
|
|
|
43
43
|
**What this rules out:** a `getSecrets` that skips unreadable rows; returning
|
package/knowledge/decisions/internals/a-virtual-user-run-is-not-a-workflow-and-not-a-queued-job.md
CHANGED
|
@@ -18,9 +18,9 @@ Both of the alternatives are the obvious ones, and both are wrong for this.
|
|
|
18
18
|
resumed at the step it died on, and that the same input reaches the same step.
|
|
19
19
|
A virtual user is the opposite by construction — it is an LLM deciding what to
|
|
20
20
|
try next, so no two attempts take the same steps, and there is no step to resume
|
|
21
|
-
|
|
21
|
+
_to_. Recording a run as a workflow puts entries in the workflow store that can
|
|
22
22
|
never be replayed, and gives every operator reading that store a row that lies
|
|
23
|
-
about what it is. The seed makes a run
|
|
23
|
+
about what it is. The seed makes a run _reproducible_ — run it again and it
|
|
24
24
|
explores the same way — which is a different property from resumable, and one
|
|
25
25
|
the record already carries.
|
|
26
26
|
|
|
@@ -13,11 +13,11 @@ per secret turns a 10ms operation into a 4-second one.
|
|
|
13
13
|
|
|
14
14
|
It guarded it with `assert.ok(elapsed < 50)`. Measured on this machine:
|
|
15
15
|
|
|
16
|
-
|
|
|
17
|
-
|
|
|
18
|
-
| one `deriveKEK`
|
|
19
|
-
| 50 `envelopeDecrypt`
|
|
20
|
-
| the old 50ms threshold
|
|
16
|
+
| | |
|
|
17
|
+
| ----------------------------- | ------------------------------- |
|
|
18
|
+
| one `deriveKEK` | ~86ms |
|
|
19
|
+
| 50 `envelopeDecrypt` | 10.8ms |
|
|
20
|
+
| the old 50ms threshold | 4.6x headroom |
|
|
21
21
|
| the failure it guards against | ~4281ms — a **396x** separation |
|
|
22
22
|
|
|
23
23
|
So the assertion had 4.6x of margin to detect a 396x regression. Everything
|
|
@@ -37,7 +37,7 @@ suite grows or CI moves to a noisier runner. Any assertion of the form
|
|
|
37
37
|
ratio against something measured alongside it.
|
|
38
38
|
|
|
39
39
|
Worth knowing: `envelopeDecrypt(kek: CryptoKey, …)` takes the derived key as a
|
|
40
|
-
parameter, so it
|
|
40
|
+
parameter, so it _cannot_ derive one — the property is already enforced by the
|
|
41
41
|
signature, and [[the-api-report-pins-members-not-just-names]] would catch a
|
|
42
42
|
change to it. The test is defence in depth, which is a reason to make it cheap
|
|
43
43
|
and quiet rather than to delete it.
|
|
@@ -18,7 +18,7 @@ pikkuUserId: rpcService.wire?.pikkuUserId,
|
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
`PikkuRPC` has no `wire`. Neither does the object `getContextRPCService`
|
|
21
|
-
actually returns — `ContextAwareRPCService` holds its wire
|
|
21
|
+
actually returns — `ContextAwareRPCService` holds its wire _privately_ and
|
|
22
22
|
exposes `invoke`, `remote`, `exposed`, `startWorkflow`, `agent` and
|
|
23
23
|
`rpcWithWire`, and nothing else. Every one of those reads was `undefined`, and
|
|
24
24
|
the `rpcService: any` parameter type is what kept the compiler quiet about it.
|
|
@@ -17,7 +17,7 @@ One package may be wired twice — the same payments addon against a live and a
|
|
|
17
17
|
sandbox account, say — with different secret and variable names. Caching by
|
|
18
18
|
package name would build the service graph once, from whichever instance called
|
|
19
19
|
first, and silently hand the other instance the wrong credentials. Because the
|
|
20
|
-
overrides have to be visible to the addon's
|
|
20
|
+
overrides have to be visible to the addon's _own_ `createSingletonServices`, they
|
|
21
21
|
are applied by wrapping the parent `secrets` and `variables` services
|
|
22
22
|
(`aliasSecretService`, `aliasVariablesService`) so that every logical name the
|
|
23
23
|
addon reads is remapped to the real project name before resolution. A call with
|
|
@@ -15,7 +15,7 @@ instance namespace when known and otherwise the package's sole namespace via
|
|
|
15
15
|
`findAddonNamespaceForPackage`.
|
|
16
16
|
|
|
17
17
|
Workflows declared by an addon are registered under the addon's package scope,
|
|
18
|
-
but the namespace they answer to is chosen by the
|
|
18
|
+
but the namespace they answer to is chosen by the _consumer_ in `wireAddon`.
|
|
19
19
|
Without the proxy, `runToCompletion('myWorkflow')` written inside the addon
|
|
20
20
|
resolves against root meta, misses, and throws `WorkflowNotFoundError` — leaving
|
|
21
21
|
the addon author no option but to hardcode the consumer-defined namespace, which
|
|
@@ -24,7 +24,7 @@ permissions bug rather than a merge that dropped.
|
|
|
24
24
|
This is a different rule from
|
|
25
25
|
[scope roots may be co-declared by an addon and its host
|
|
26
26
|
app](scope-roots-may-be-co-declared-by-an-addon-and-its-host-app.md): that one
|
|
27
|
-
is about `flattenScopeDefinitions` deduping ids
|
|
27
|
+
is about `flattenScopeDefinitions` deduping ids _within_ a build where both
|
|
28
28
|
declarations are present and identical. This one is about the addon's copy never
|
|
29
29
|
arriving. The consequence for addon authors is the same either way — own a root
|
|
30
30
|
outright, named for the package or vendor, and nest everything under it. It is
|
package/knowledge/decisions/internals/channel-message-handlers-accept-three-config-shapes.md
CHANGED
|
@@ -14,7 +14,7 @@ things a caller may put on `onMessage` or inside `onMessageWiring`:
|
|
|
14
14
|
- a direct function config, where `onMessage.func` is a plain `Function`;
|
|
15
15
|
- a wrapper, where `onMessage.func` is itself a `CorePikkuFunctionConfig` and so
|
|
16
16
|
has its own nested `.func`;
|
|
17
|
-
- a simple wrapper, which carries a plain `Function` under `func`
|
|
17
|
+
- a simple wrapper, which carries a plain `Function` under `func` _and_ a
|
|
18
18
|
sibling `middleware` array.
|
|
19
19
|
|
|
20
20
|
The `isWrapper` check tests exactly that: an object with `func`, where either
|
|
@@ -19,7 +19,7 @@ user's stream and growing memory run over run. It is therefore appended fresh on
|
|
|
19
19
|
every call, after the cached inherited slice.
|
|
20
20
|
|
|
21
21
|
The `uid` matters as much as the cache split. `processMessageHandlers` in
|
|
22
|
-
`channel-handler.ts` builds it from the channel name
|
|
22
|
+
`channel-handler.ts` builds it from the channel name _plus_ the routing property
|
|
23
23
|
and router value (`${name}:${routingProperty}:${routerValue}`, or
|
|
24
24
|
`${name}:default`), because several message routes on one channel may point at
|
|
25
25
|
the same function — a key based on the function alone would serve one route's
|
|
@@ -10,7 +10,7 @@ tags: channel
|
|
|
10
10
|
`runChannelConnect` in
|
|
11
11
|
`packages/core/src/wirings/channel/serverless/serverless-channel-runner.ts`
|
|
12
12
|
reads `userSession.getPikkuUserId()` and calls `channelStore.setPikkuUserId`
|
|
13
|
-
|
|
13
|
+
_after_ `runChannelLifecycleWithMiddleware` has executed the `onConnect`
|
|
14
14
|
lifecycle, not before.
|
|
15
15
|
|
|
16
16
|
Auth middleware runs as part of that lifecycle — it is what inspects the upgrade
|