deepline 0.3.88 → 0.3.90
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/contracts/install-commands.json +29 -0
- package/dist/bundling-sources/sdk/src/client.ts +652 -39
- package/dist/bundling-sources/sdk/src/config.ts +77 -0
- package/dist/bundling-sources/sdk/src/http.ts +76 -30
- package/dist/bundling-sources/sdk/src/index.ts +10 -0
- package/dist/bundling-sources/sdk/src/monitor-fleet-contract.ts +1 -1
- package/dist/bundling-sources/sdk/src/pagination.ts +25 -0
- package/dist/bundling-sources/sdk/src/play.ts +15 -1
- package/dist/bundling-sources/sdk/src/plays/bundle-play-file.ts +3 -3
- package/dist/bundling-sources/sdk/src/release.ts +16 -9
- package/dist/bundling-sources/sdk/src/types.ts +106 -4
- package/dist/bundling-sources/shared_libs/integration-contracts/AGENTS.md +9 -0
- package/dist/bundling-sources/shared_libs/integration-contracts/README.md +3 -0
- package/dist/bundling-sources/shared_libs/integration-contracts/index.ts +2 -0
- package/dist/bundling-sources/shared_libs/monitors/analytics-install-guides.ts +77 -0
- package/dist/bundling-sources/shared_libs/monitors/analytics-public.ts +10 -0
- package/dist/bundling-sources/shared_libs/monitors/billing/charges.ts +125 -0
- package/dist/bundling-sources/shared_libs/monitors/billing/policy-builders.ts +686 -0
- package/dist/bundling-sources/shared_libs/monitors/billing/pricing.ts +54 -0
- package/dist/bundling-sources/shared_libs/monitors/billing/public-pricing.ts +72 -0
- package/dist/bundling-sources/shared_libs/monitors/billing/session.ts +45 -0
- package/dist/bundling-sources/shared_libs/monitors/billing/state.ts +454 -0
- package/dist/bundling-sources/shared_libs/monitors/billing/tamradar.ts +260 -0
- package/dist/bundling-sources/shared_libs/monitors/billing/types.ts +215 -0
- package/dist/bundling-sources/shared_libs/monitors/callback-security.ts +333 -0
- package/dist/bundling-sources/shared_libs/monitors/cursor-page.ts +42 -0
- package/dist/bundling-sources/shared_libs/monitors/deactivation-reasons.ts +16 -0
- package/dist/bundling-sources/shared_libs/monitors/framework-managed-payload-fields.ts +71 -0
- package/dist/bundling-sources/shared_libs/monitors/generated/provider-monitor-callback-admission-targets.ts +16 -0
- package/dist/bundling-sources/shared_libs/monitors/http-error-response.ts +270 -0
- package/dist/bundling-sources/shared_libs/monitors/inbound-publish-key.ts +39 -0
- package/dist/bundling-sources/shared_libs/monitors/inbound-queue.ts +82 -0
- package/dist/bundling-sources/shared_libs/monitors/inventory-reconciliation.ts +59 -0
- package/dist/bundling-sources/shared_libs/monitors/lifecycle-notifications.ts +471 -0
- package/dist/bundling-sources/shared_libs/monitors/org-monitor-limits.ts +1 -1
- package/dist/bundling-sources/shared_libs/monitors/package.json +36 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-callback-verification.ts +1125 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-batch-operation.ts +305 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-capability.ts +964 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-consumer-health.ts +56 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-errors.ts +131 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-identity-claims.ts +535 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-legacy-aliases.ts +16 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-priority-execution.ts +56 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-public-aliases.ts +28 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-runtime-read-eligibility.ts +38 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-state.ts +122 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-status.ts +10 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-upstream-identity.ts +112 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-webhook-monitor-runtime.ts +300 -0
- package/dist/bundling-sources/shared_libs/monitors/quickstart-prompts.ts +22 -0
- package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-dead-letter.ts +245 -0
- package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-message.ts +38 -0
- package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-queue-ack-probe.ts +94 -0
- package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-queue-delivery.ts +60 -0
- package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-queue.ts +60 -0
- package/dist/bundling-sources/shared_libs/monitors/snitcher-install-validation.ts +93 -0
- package/dist/bundling-sources/shared_libs/monitors/snitcher-ip2company.ts +332 -0
- package/dist/bundling-sources/shared_libs/monitors/snitcher-radar.ts +221 -0
- package/dist/bundling-sources/shared_libs/monitors/starter-templates.ts +105 -0
- package/dist/bundling-sources/shared_libs/monitors/tracking-provider-guidance.ts +73 -0
- package/dist/bundling-sources/shared_libs/monitors/tracking-provider-integrations.ts +81 -0
- package/dist/bundling-sources/shared_libs/monitors/tsconfig.json +10 -0
- package/dist/bundling-sources/shared_libs/observability/build-context.ts +13 -0
- package/dist/bundling-sources/shared_libs/observability/log-metadata.ts +160 -0
- package/dist/bundling-sources/shared_libs/observability/request-context.ts +68 -0
- package/dist/bundling-sources/shared_libs/observability/scheduled-jobs.json +654 -0
- package/dist/bundling-sources/shared_libs/observability/scheduled-work-manual.ts +35 -0
- package/dist/bundling-sources/shared_libs/observability/scheduled-work.ts +5 -0
- package/dist/bundling-sources/shared_libs/play-data-plane/neon-constants.ts +9 -0
- package/dist/bundling-sources/shared_libs/play-data-plane/r2.ts +272 -0
- package/dist/bundling-sources/shared_libs/play-runtime/activity-observation.ts +6 -11
- package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +135 -12
- package/dist/bundling-sources/shared_libs/play-runtime/async-operation.ts +66 -1
- package/dist/bundling-sources/shared_libs/play-runtime/async-play-invocation.ts +77 -0
- package/dist/bundling-sources/shared_libs/play-runtime/bounceban-batching.ts +137 -0
- package/dist/bundling-sources/shared_libs/play-runtime/checkpoint-boundaries.ts +70 -0
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +1159 -166
- package/dist/bundling-sources/shared_libs/play-runtime/coordinator-headers.ts +1 -32
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +103 -0
- package/dist/bundling-sources/shared_libs/play-runtime/daytona-payload-contract.ts +68 -0
- package/dist/bundling-sources/shared_libs/play-runtime/daytona-sandbox-janitor.ts +103 -0
- package/dist/bundling-sources/shared_libs/play-runtime/daytona-sandbox-reaper.ts +725 -0
- package/dist/bundling-sources/shared_libs/play-runtime/default-batch-strategies.ts +20 -1
- package/dist/bundling-sources/shared_libs/play-runtime/durable-call-cache.ts +29 -0
- package/dist/bundling-sources/shared_libs/play-runtime/execution-capabilities.ts +29 -0
- package/dist/bundling-sources/shared_libs/play-runtime/execution-gateway-invocation-fence.ts +442 -0
- package/dist/bundling-sources/shared_libs/play-runtime/execution-protocol.ts +7 -1
- package/dist/bundling-sources/shared_libs/play-runtime/fixture-behavior.ts +18 -0
- package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-rate-state-backend.ts +9 -0
- package/dist/bundling-sources/shared_libs/play-runtime/governor/policy.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/governor/rate-state-backend.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/contracts.ts +66 -0
- package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/job.ts +145 -0
- package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/ports.ts +21 -0
- package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/postgres-store.ts +170 -0
- package/dist/bundling-sources/shared_libs/play-runtime/internal-bootstrap-token.ts +1322 -0
- package/dist/bundling-sources/shared_libs/play-runtime/internal-step-ids.ts +2 -2
- package/dist/bundling-sources/shared_libs/play-runtime/lane-retirement-gate.ts +189 -0
- package/dist/bundling-sources/shared_libs/play-runtime/launch-source-policy.ts +112 -0
- package/dist/bundling-sources/shared_libs/play-runtime/map-execution-frame.ts +8 -0
- package/dist/bundling-sources/shared_libs/play-runtime/perf-trace.ts +127 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-artifact-runtime-contract.ts +5 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-run-recovery-policy.ts +24 -1
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/contracts.ts +56 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/index.ts +13 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/job.ts +41 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/ports.ts +17 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/postgres-adapter.ts +54 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/contracts.ts +114 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/engine-suspension.ts +108 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/index.ts +36 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/job.ts +97 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/ports.ts +104 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/postgres-fence-adapter.ts +263 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/worker-terminal-projection.ts +64 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/projection/contracts.ts +29 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/projection/gateway-adapter.ts +56 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/projection/index.ts +15 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/projection/job.ts +65 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/projection/ports.ts +17 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/contracts.ts +42 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/index.ts +17 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/job.ts +142 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/ports.ts +42 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/postgres-adapter.ts +102 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/contracts.ts +60 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/index.ts +16 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/job.ts +78 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/ports.ts +54 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/postgres-adapter.ts +71 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runtime-batching-registry.ts +4 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runtime-semantics.ts +28 -0
- package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +4 -0
- package/dist/bundling-sources/shared_libs/play-runtime/receipt-status.ts +5 -8
- package/dist/bundling-sources/shared_libs/play-runtime/run-failure.ts +23 -2
- package/dist/bundling-sources/shared_libs/play-runtime/run-identity.ts +168 -0
- package/dist/bundling-sources/shared_libs/play-runtime/run-snapshot-stream.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +90 -13
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +6 -12
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-start-admission.ts +68 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +21 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/bundle.ts +0 -1
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/runtime-sandbox-reconciliation.ts +14 -43
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +67 -213
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-authority.ts +201 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-capacity-policy.ts +20 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-contract.ts +6 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-env.ts +12 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-operation-contract.ts +67 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-release-environment.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-sandbox-contract.ts +68 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-scheduler-topology.ts +38 -2
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-telemetry.ts +108 -0
- package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/contract.ts +4 -0
- package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/runner-backend-adapter.ts +3 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +37 -1
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-deadline-reconciliation.ts +88 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-play-deploy-task.ts +124 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-play-run-task.ts +68 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-pool.ts +193 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-queue-lifecycle.ts +269 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-queue-suffix.ts +73 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +6642 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-shared.ts +897 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-worker-metrics.ts +120 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-worker-required-env.ts +76 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd.ts +476 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/gateway-heavy-request-admission.ts +47 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/gateway-progress-registry.ts +147 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/index.ts +27 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/lazy.ts +50 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/play-run-recovery.ts +98 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-budget-state.ts +260 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-pool.ts +1416 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-progress.ts +1255 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-rate-state.ts +942 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +14636 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/receipt-gateway.ts +888 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-outbox-recovery.ts +355 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-terminal-transition.ts +46 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runner-push.ts +60 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-api-origin.ts +33 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-receipt-gateway-health.ts +64 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-capacity.ts +835 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-ledger-reconciliation.ts +1218 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-operation.ts +207 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-scheduler-schema.ts +10 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/scheduler-capacity.ts +123 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/scheduler-launch-read-observability.ts +78 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/submit-admission.ts +169 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/terminal-contract.ts +20 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/worker-queue-metrics.ts +34 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/worker-resource-metrics.ts +249 -0
- package/dist/bundling-sources/shared_libs/play-runtime/sheet-attempt-sql.ts +7 -0
- package/dist/bundling-sources/shared_libs/play-runtime/step-progress.ts +296 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-call/native-batch.ts +3 -3
- package/dist/bundling-sources/shared_libs/play-runtime/tool-call/runtime-step-receipts-adapter.ts +20 -1
- package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +60 -15
- package/dist/bundling-sources/shared_libs/play-runtime/tool-execution-outcome.ts +20 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-http-errors.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/transient-service-error.ts +12 -0
- package/dist/bundling-sources/shared_libs/play-runtime/vercel-protection.ts +14 -1
- package/dist/bundling-sources/shared_libs/play-runtime/work-receipt-storage-contract.ts +165 -0
- package/dist/bundling-sources/shared_libs/play-runtime/work-receipts.ts +15 -23
- package/dist/bundling-sources/shared_libs/play-runtime/workflow-executor-auth.ts +169 -0
- package/dist/bundling-sources/shared_libs/play-runtime/zerobounce-batching.ts +122 -0
- package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +8 -3
- package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +454 -17
- package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +19 -4
- package/dist/bundling-sources/shared_libs/plays/contracts.ts +8 -14
- package/dist/bundling-sources/shared_libs/plays/core.ts +11 -6
- package/dist/bundling-sources/shared_libs/plays/deployment-status.ts +1 -1
- package/dist/bundling-sources/shared_libs/plays/docflow-binding-owner.ts +16 -11
- package/dist/bundling-sources/shared_libs/plays/docflow.ts +1 -1
- package/dist/bundling-sources/shared_libs/plays/email-status.ts +1 -1
- package/dist/bundling-sources/shared_libs/plays/play-grep-search.ts +39 -0
- package/dist/bundling-sources/shared_libs/plays/resolve-static-pipeline.ts +1 -1
- package/dist/bundling-sources/shared_libs/plays/share/copy.ts +271 -0
- package/dist/bundling-sources/shared_libs/plays/share/metrics.ts +140 -0
- package/dist/bundling-sources/shared_libs/plays/share/public-read-model.ts +86 -0
- package/dist/bundling-sources/shared_libs/plays/share/seo-quality.ts +181 -0
- package/dist/bundling-sources/shared_libs/plays/share/static-pipeline-summary.ts +658 -0
- package/dist/bundling-sources/shared_libs/plays/share/types.ts +197 -0
- package/dist/bundling-sources/shared_libs/plays/slack-hitl-timeout-error.ts +37 -0
- package/dist/bundling-sources/shared_libs/plays/slug.ts +115 -0
- package/dist/bundling-sources/shared_libs/plays/static-pipeline.ts +50 -15
- package/dist/bundling-sources/shared_libs/plays/tool-category-descriptions.ts +2 -2
- package/dist/bundling-sources/shared_libs/plays/tool-result-types.ts +1 -1
- package/dist/bundling-sources/shared_libs/product-notifications/catalog.ts +877 -0
- package/dist/bundling-sources/shared_libs/product-notifications/configuration-draft.ts +456 -0
- package/dist/bundling-sources/shared_libs/product-notifications/configuration.ts +566 -0
- package/dist/bundling-sources/shared_libs/product-notifications/content.ts +28 -0
- package/dist/bundling-sources/shared_libs/product-notifications/default-policy.ts +60 -0
- package/dist/bundling-sources/shared_libs/product-notifications/email.ts +246 -0
- package/dist/bundling-sources/shared_libs/product-notifications/evaluation.ts +280 -0
- package/dist/bundling-sources/shared_libs/product-notifications/events.ts +433 -0
- package/dist/bundling-sources/shared_libs/product-notifications/legacy-slack.ts +80 -0
- package/dist/bundling-sources/shared_libs/product-notifications/overflow.ts +18 -0
- package/dist/bundling-sources/shared_libs/product-notifications/rolling-limit.ts +24 -0
- package/dist/bundling-sources/shared_libs/product-notifications/slack-delivery.ts +624 -0
- package/dist/bundling-sources/shared_libs/product-notifications/slack-payload.ts +140 -0
- package/dist/bundling-sources/shared_libs/product-notifications/slack-transport.ts +75 -0
- package/dist/bundling-sources/shared_libs/product-notifications/workspace.ts +38 -0
- package/dist/bundling-sources/shared_libs/runtime-env.ts +12 -0
- package/dist/bundling-sources/shared_libs/security/email-blacklist.ts +42 -0
- package/dist/bundling-sources/shared_libs/security/header-safe-env.ts +35 -0
- package/dist/bundling-sources/shared_libs/security/internal-actor.ts +50 -0
- package/dist/bundling-sources/shared_libs/security/secret-redaction.ts +267 -0
- package/dist/bundling-sources/shared_libs/security/slack-sanitize.ts +133 -0
- package/dist/cli/getting-started.d.mts +52 -0
- package/dist/cli/getting-started.d.ts +52 -0
- package/dist/cli/getting-started.js +65 -0
- package/dist/cli/getting-started.mjs +36 -0
- package/dist/cli/index.d.mts +9 -0
- package/dist/cli/index.d.ts +9 -0
- package/dist/cli/index.js +1611 -453
- package/dist/cli/index.mjs +1596 -447
- package/dist/{compiler-manifest-Dbov16F7.d.mts → compiler-manifest-BaJfE-5H.d.mts} +136 -10
- package/dist/{compiler-manifest-Dbov16F7.d.ts → compiler-manifest-BaJfE-5H.d.ts} +136 -10
- package/dist/index.d.mts +910 -155
- package/dist/index.d.ts +910 -155
- package/dist/index.js +550 -64
- package/dist/index.mjs +550 -64
- package/dist/install-integrity.json +193 -4
- package/dist/monitor-fleet-contract.d.mts +138 -0
- package/dist/monitor-fleet-contract.d.ts +138 -0
- package/dist/monitor-fleet-contract.js +404 -0
- package/dist/monitor-fleet-contract.mjs +367 -0
- package/dist/plays/bundle-play-file.d.mts +8 -3
- package/dist/plays/bundle-play-file.d.ts +8 -3
- package/dist/plays/bundle-play-file.mjs +100 -20
- package/dist/release.d.mts +255 -0
- package/dist/release.d.ts +255 -0
- package/dist/release.js +215 -0
- package/dist/release.mjs +188 -0
- package/package.json +23 -4
- /package/dist/bundling-sources/shared_libs/{integrations/bettercontact-execution-policy.ts → integration-contracts/bettercontact/execution-policy.ts} +0 -0
- /package/dist/bundling-sources/shared_libs/{integrations/theirstack-execution-policy.ts → integration-contracts/theirstack/execution-policy.ts} +0 -0
package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-progress.ts
ADDED
|
@@ -0,0 +1,1255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live step/progress ledger reporting for Node runtime workers.
|
|
3
|
+
*
|
|
4
|
+
* Projection of the runner liveNodeProgress event stream: the runner's event stream is
|
|
5
|
+
* folded into a PlayVisualNodeProgressMap and posted as `update_run_status`
|
|
6
|
+
* patches through the app runtime API. The server-side run ledger
|
|
7
|
+
* (buildPlayRunLedgerEventsFromStatusPatch in run-ledger.ts) converts those
|
|
8
|
+
* patches into step.started/step.progress/step.completed events — nothing is
|
|
9
|
+
* reimplemented here beyond producing the same progress patches.
|
|
10
|
+
*
|
|
11
|
+
* PERF: the runner event path is hot. Nothing here awaits in that path:
|
|
12
|
+
* observations merge into the latest state while at most one upload is active.
|
|
13
|
+
* Runtime Sheet row durability belongs to the context-level row writer.
|
|
14
|
+
*/
|
|
15
|
+
import { PlayStepLifecycleTracker } from '../step-lifecycle-tracker';
|
|
16
|
+
import {
|
|
17
|
+
updateRunStatusViaAppRuntime,
|
|
18
|
+
type RuntimeStatusUpdate,
|
|
19
|
+
} from '../app-runtime-api';
|
|
20
|
+
import type { PlayVisualNodeProgressMap } from '../worker-api-types';
|
|
21
|
+
import type { PlayExecutionEvent } from '../ctx-types';
|
|
22
|
+
import type {
|
|
23
|
+
PlayRunnerLogEvent,
|
|
24
|
+
PlayRunnerResult,
|
|
25
|
+
} from '../protocol';
|
|
26
|
+
import type { PlaySchedulerSubmitInput } from '../scheduler-backend';
|
|
27
|
+
import type { DocflowObservationRecord } from '../docflow-observation';
|
|
28
|
+
import {
|
|
29
|
+
getTopLevelPipelineSubsteps,
|
|
30
|
+
type PlayStaticPipeline,
|
|
31
|
+
type PlayStaticSubstep,
|
|
32
|
+
} from '../../plays/static-pipeline';
|
|
33
|
+
import { getStaticSubstepNodeId } from '../step-progress';
|
|
34
|
+
import { runtimeApiBaseUrlFromLaunch } from './runtime-api-origin';
|
|
35
|
+
|
|
36
|
+
// Patterns mirrored from runner events — they parse
|
|
37
|
+
// the same Node play-runner log stream.
|
|
38
|
+
const MAP_START_LOG_PATTERN =
|
|
39
|
+
/Starting map over (\d+) items .* \((?:table namespace|key): ([^;)]+)(?:; (\d+) (?:already satisfied|duplicate keys skipped); (\d+) pending)?\)/i;
|
|
40
|
+
const PERF_MAP_SETUP_LOG_PATTERN =
|
|
41
|
+
/^\[perf\] runtime map setup table=([^\s]+) rows=(\d+)\b/i;
|
|
42
|
+
const PLAY_TOOL_BATCH_LOG_PATTERN =
|
|
43
|
+
/(?:^|\]\s*)Executing tool batch\s+([A-Za-z0-9_:-]+):\s+(\d+)\s+calls\b/i;
|
|
44
|
+
const CTX_LOG_TIMESTAMP_PREFIX_RE = /^\[\d{4}-\d{2}-\d{2}T[\d:.]+Z\]\s+/;
|
|
45
|
+
const LIVE_LOG_TAIL_LIMIT = 1_000;
|
|
46
|
+
|
|
47
|
+
function docflowInvocationSequence(invocationId?: string): number {
|
|
48
|
+
if (!invocationId) return -1;
|
|
49
|
+
const sequence = Number(invocationId.split(':').at(-1));
|
|
50
|
+
return Number.isSafeInteger(sequence) && sequence >= 0 ? sequence : -1;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// PERF: progress flushes
|
|
54
|
+
// here throttle purely on the adaptive interval. The bypass would chain ~800
|
|
55
|
+
// HTTP posts on a 200k-row run and finalize() awaits that chain. Worst case
|
|
56
|
+
// the live ledger lags by one interval; the forced finalize flush lands final
|
|
57
|
+
// truth.
|
|
58
|
+
function getAdaptiveRunEventIntervalMs(totalRows: number): number {
|
|
59
|
+
if (totalRows >= 1_000_000) return 30_000;
|
|
60
|
+
if (totalRows >= 100_000) return 15_000;
|
|
61
|
+
if (totalRows >= 10_000) return 8_000;
|
|
62
|
+
return 1_500;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function staticPipelineFromContractSnapshot(
|
|
66
|
+
value: unknown,
|
|
67
|
+
): PlayStaticPipeline | null {
|
|
68
|
+
if (!value || typeof value !== 'object') return null;
|
|
69
|
+
const staticPipeline = (value as { staticPipeline?: unknown }).staticPipeline;
|
|
70
|
+
if (!staticPipeline || typeof staticPipeline !== 'object') return null;
|
|
71
|
+
return staticPipeline as PlayStaticPipeline;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Build ordered list of all static pipeline node IDs with their types.
|
|
76
|
+
* Used to track step-level timing for the Gantt waterfall.
|
|
77
|
+
*/
|
|
78
|
+
export function buildOrderedNodeList(
|
|
79
|
+
contractSnapshot: unknown,
|
|
80
|
+
): Array<{ nodeId: string; type: PlayStaticSubstep['type'] }> {
|
|
81
|
+
const substeps = getTopLevelPipelineSubsteps(
|
|
82
|
+
staticPipelineFromContractSnapshot(contractSnapshot),
|
|
83
|
+
);
|
|
84
|
+
return substeps.map((substep, index) => ({
|
|
85
|
+
nodeId: getStaticSubstepNodeId(substep, index),
|
|
86
|
+
type: substep.type,
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Map logical dataset namespaces to their static-pipeline node IDs. */
|
|
91
|
+
type StaticDatasetNodeRef = {
|
|
92
|
+
nodeId: string;
|
|
93
|
+
logicalNamespace: string;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
type RuntimeDatasetNodeRef = StaticDatasetNodeRef & {
|
|
97
|
+
artifactTableNamespace: string;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
function buildMapNodeLookup(
|
|
101
|
+
contractSnapshot: unknown,
|
|
102
|
+
): Map<string, StaticDatasetNodeRef> {
|
|
103
|
+
const substeps = getTopLevelPipelineSubsteps(
|
|
104
|
+
staticPipelineFromContractSnapshot(contractSnapshot),
|
|
105
|
+
);
|
|
106
|
+
const lookup = new Map<string, StaticDatasetNodeRef>();
|
|
107
|
+
for (let index = 0; index < substeps.length; index += 1) {
|
|
108
|
+
const substep = substeps[index]!;
|
|
109
|
+
if (substep.type !== 'dataset') continue;
|
|
110
|
+
const logicalNamespace =
|
|
111
|
+
substep.tableNamespace?.trim() || substep.field.trim();
|
|
112
|
+
if (!logicalNamespace) continue;
|
|
113
|
+
lookup.set(logicalNamespace, {
|
|
114
|
+
nodeId: getStaticSubstepNodeId(substep, index),
|
|
115
|
+
logicalNamespace,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return lookup;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function buildMapNodeIdLookup(
|
|
122
|
+
contractSnapshot: unknown,
|
|
123
|
+
): Map<string, string> {
|
|
124
|
+
return new Map(
|
|
125
|
+
[...buildMapNodeLookup(contractSnapshot).entries()].map(
|
|
126
|
+
([namespace, ref]) => [namespace, ref.nodeId],
|
|
127
|
+
),
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function resolveDatasetNodeRefFromTableNamespace(
|
|
132
|
+
lookup: ReadonlyMap<string, StaticDatasetNodeRef>,
|
|
133
|
+
physicalNamespace: string,
|
|
134
|
+
): RuntimeDatasetNodeRef | null {
|
|
135
|
+
const trimmed = physicalNamespace.trim();
|
|
136
|
+
if (!trimmed) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
for (const [logicalNamespace, ref] of lookup.entries()) {
|
|
140
|
+
if (
|
|
141
|
+
trimmed === logicalNamespace ||
|
|
142
|
+
trimmed.startsWith(`${logicalNamespace}_`)
|
|
143
|
+
) {
|
|
144
|
+
return {
|
|
145
|
+
...ref,
|
|
146
|
+
artifactTableNamespace: trimmed,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function rowsProcessedMessage(
|
|
154
|
+
completed: number,
|
|
155
|
+
total: number | undefined,
|
|
156
|
+
): string | undefined {
|
|
157
|
+
return total !== undefined && total > 0
|
|
158
|
+
? `${Math.max(0, completed).toLocaleString()} / ${total.toLocaleString()} rows processed`
|
|
159
|
+
: undefined;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function callsInFlightMessage(input: {
|
|
163
|
+
activeRows: number;
|
|
164
|
+
completedRows: number;
|
|
165
|
+
totalRows: number;
|
|
166
|
+
}): string {
|
|
167
|
+
const active = input.activeRows.toLocaleString();
|
|
168
|
+
return input.totalRows > 0
|
|
169
|
+
? `${active} calls in flight · ${input.completedRows.toLocaleString()} / ${input.totalRows.toLocaleString()} rows processed`
|
|
170
|
+
: `${active} calls in flight`;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export type PostgresSchedulerProgressReporter = {
|
|
174
|
+
/**
|
|
175
|
+
* Consume one raw runner event. Synchronous and cheap on purpose: this is
|
|
176
|
+
* called for EVERY runner event before any stdout sampling.
|
|
177
|
+
*/
|
|
178
|
+
onRunnerEvent(event: unknown): void;
|
|
179
|
+
/**
|
|
180
|
+
* Fold durable docflow observations (read from the scheduler observations
|
|
181
|
+
* table at worker finalize, ADR 0016 rule 3) into the live node progress so a
|
|
182
|
+
* completed absurd run persists docflow node I/O even when the live
|
|
183
|
+
* `docflow.node.*` events were dropped mid-run. Terminal reconciliation only:
|
|
184
|
+
* a durable record supersedes the event-fed nodeIo for its node when it is at
|
|
185
|
+
* least as recent (attempt, then invocation sequence).
|
|
186
|
+
*/
|
|
187
|
+
applyDurableObservations(observations: DocflowObservationRecord[]): void;
|
|
188
|
+
/**
|
|
189
|
+
* Record the data-plane row-outcome counts read from the runtime sheet
|
|
190
|
+
* tables at worker finalize (ADR 0016 rule 3). Sheets exist regardless of
|
|
191
|
+
* runner mode (a detached Daytona push run streams no events and can omit
|
|
192
|
+
* its terminal checkpoint entirely), so these counts are the reconciliation
|
|
193
|
+
* of record: finalize applies them AFTER the checkpoint mapFrames, and they
|
|
194
|
+
* win whenever the two disagree or frames are missing. Works from an empty
|
|
195
|
+
* liveNodeProgress — a zero-event run still persists real map step progress.
|
|
196
|
+
*/
|
|
197
|
+
applyTerminalSheetOutcomes(
|
|
198
|
+
outcomes: Array<{
|
|
199
|
+
tableNamespace: string;
|
|
200
|
+
completed: number;
|
|
201
|
+
failed: number;
|
|
202
|
+
total: number;
|
|
203
|
+
}>,
|
|
204
|
+
): void;
|
|
205
|
+
/**
|
|
206
|
+
* Apply terminal step transitions from the runner result and await the
|
|
207
|
+
* final ledger flush. The inline executor returns the result instead of
|
|
208
|
+
* emitting a `result` event, so it is passed in here.
|
|
209
|
+
*/
|
|
210
|
+
finalize(
|
|
211
|
+
result?: PlayRunnerResult | null,
|
|
212
|
+
options?: {
|
|
213
|
+
status?: 'running' | 'completed' | 'failed';
|
|
214
|
+
/** Propagate a running-state transport failure to the caller. */
|
|
215
|
+
required?: boolean;
|
|
216
|
+
replayAllTerminalLogs?: boolean;
|
|
217
|
+
terminalLogProducerAttempt?: number;
|
|
218
|
+
skipTerminalLogReplay?: boolean;
|
|
219
|
+
},
|
|
220
|
+
): Promise<void>;
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
export type PostgresSchedulerDurableLogMode =
|
|
224
|
+
| 'progress_reporter'
|
|
225
|
+
| 'direct_worker';
|
|
226
|
+
|
|
227
|
+
function shouldPublishDurableLogEvent(
|
|
228
|
+
mode: PostgresSchedulerDurableLogMode,
|
|
229
|
+
event:
|
|
230
|
+
| Pick<PlayRunnerLogEvent, 'source' | 'line'>
|
|
231
|
+
| { source?: unknown; line?: unknown },
|
|
232
|
+
): boolean {
|
|
233
|
+
// Daytona host lifecycle logs use source "worker" (sandbox
|
|
234
|
+
// create/upload/execute). Keep those in worker logs while still storing
|
|
235
|
+
// play-authored ctx.log events in the durable Run Log Stream. The one
|
|
236
|
+
// exception is the structured performance marker: it is bounded (one
|
|
237
|
+
// terminal phase observation per runner phase), run-scoped, and is the
|
|
238
|
+
// canonical black-box regression signal for dispatcher throughput. Do not
|
|
239
|
+
// broaden this to arbitrary worker output.
|
|
240
|
+
return (
|
|
241
|
+
mode !== 'direct_worker' ||
|
|
242
|
+
event.source !== 'worker' ||
|
|
243
|
+
(typeof event.line === 'string' && event.line.startsWith('[perf-trace] '))
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function shouldPublishTerminalResultLog(
|
|
248
|
+
mode: PostgresSchedulerDurableLogMode,
|
|
249
|
+
line: string,
|
|
250
|
+
): boolean {
|
|
251
|
+
return mode !== 'direct_worker' || CTX_LOG_TIMESTAMP_PREFIX_RE.test(line);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
type TerminalLogReplayPayload = NonNullable<
|
|
255
|
+
RuntimeStatusUpdate['terminalLogReplay']
|
|
256
|
+
>;
|
|
257
|
+
|
|
258
|
+
function terminalReplayLinesForMode(input: {
|
|
259
|
+
resultLogs: readonly string[];
|
|
260
|
+
durableLogMode: PostgresSchedulerDurableLogMode;
|
|
261
|
+
}): string[] {
|
|
262
|
+
return input.resultLogs
|
|
263
|
+
.map((line) => line.trim())
|
|
264
|
+
.filter(
|
|
265
|
+
(line) =>
|
|
266
|
+
line.length > 0 &&
|
|
267
|
+
shouldPublishTerminalResultLog(input.durableLogMode, line),
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function terminalReplayPayloadForMode(input: {
|
|
272
|
+
resultLogs: readonly string[];
|
|
273
|
+
durableLogMode: PostgresSchedulerDurableLogMode;
|
|
274
|
+
liveLogs: readonly string[];
|
|
275
|
+
liveLogsTotalCount: number;
|
|
276
|
+
replayAllTerminalLogs: boolean;
|
|
277
|
+
producerAttempt?: number;
|
|
278
|
+
}): TerminalLogReplayPayload | null {
|
|
279
|
+
let lines = terminalReplayLinesForMode(input);
|
|
280
|
+
// Detached recovery is a complete attempt-local buffer. Its total count
|
|
281
|
+
// gives the replay an offset of zero on that attempt's positional channel;
|
|
282
|
+
// producerAttempt fences stale deliveries while the ledger absorbs only an
|
|
283
|
+
// exact retransmission from that same attempt.
|
|
284
|
+
let totalCount = lines.length;
|
|
285
|
+
if (
|
|
286
|
+
input.durableLogMode === 'direct_worker' &&
|
|
287
|
+
!input.replayAllTerminalLogs
|
|
288
|
+
) {
|
|
289
|
+
const observedCounts = new Map<string, number>();
|
|
290
|
+
for (const line of input.liveLogs) {
|
|
291
|
+
const key = line.trim().replace(CTX_LOG_TIMESTAMP_PREFIX_RE, '');
|
|
292
|
+
if (!key) continue;
|
|
293
|
+
observedCounts.set(key, (observedCounts.get(key) ?? 0) + 1);
|
|
294
|
+
}
|
|
295
|
+
const boundedLines: string[] = [];
|
|
296
|
+
for (const line of lines) {
|
|
297
|
+
const key = line.trim().replace(CTX_LOG_TIMESTAMP_PREFIX_RE, '');
|
|
298
|
+
const remaining = observedCounts.get(key) ?? 0;
|
|
299
|
+
if (remaining > 0) {
|
|
300
|
+
observedCounts.set(key, remaining - 1);
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
boundedLines.push(line);
|
|
304
|
+
}
|
|
305
|
+
lines = boundedLines;
|
|
306
|
+
totalCount = input.liveLogsTotalCount + lines.length;
|
|
307
|
+
}
|
|
308
|
+
if (lines.length === 0) {
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
return {
|
|
312
|
+
lines,
|
|
313
|
+
...(input.replayAllTerminalLogs ? { dedupeMode: 'exact' as const } : {}),
|
|
314
|
+
...(typeof input.producerAttempt === 'number'
|
|
315
|
+
? { producerAttempt: input.producerAttempt }
|
|
316
|
+
: {}),
|
|
317
|
+
totalCount,
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export function createPostgresSchedulerProgressReporter(input: {
|
|
322
|
+
launch: PlaySchedulerSubmitInput;
|
|
323
|
+
durableLogMode?: PostgresSchedulerDurableLogMode;
|
|
324
|
+
producerAttempt?: number;
|
|
325
|
+
isCurrentAttempt?: () => boolean | Promise<boolean>;
|
|
326
|
+
/** Durable log position before this reporter's first event. Push runners own
|
|
327
|
+
* this cursor so successive batches may land on different gateway Machines. */
|
|
328
|
+
initialLiveLogTotalCount?: number;
|
|
329
|
+
}): PostgresSchedulerProgressReporter {
|
|
330
|
+
const launch = input.launch;
|
|
331
|
+
const durableLogMode = input.durableLogMode ?? 'progress_reporter';
|
|
332
|
+
const producerAttempt = input.producerAttempt;
|
|
333
|
+
const isCurrentAttempt = input.isCurrentAttempt ?? (() => true);
|
|
334
|
+
const orderedNodes = buildOrderedNodeList(launch.contractSnapshot);
|
|
335
|
+
const mapNodeLookup = buildMapNodeLookup(launch.contractSnapshot);
|
|
336
|
+
const runtimeApi = {
|
|
337
|
+
baseUrl: runtimeApiBaseUrlFromLaunch(launch),
|
|
338
|
+
executorToken: launch.executorToken,
|
|
339
|
+
vercelProtectionBypassToken: launch.vercelProtectionBypassToken ?? null,
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
let liveNodeProgress: PlayVisualNodeProgressMap = {};
|
|
343
|
+
let liveNodeProgressDirty = false;
|
|
344
|
+
let liveLogs: string[] = [];
|
|
345
|
+
let liveLogsTotalCount = input.initialLiveLogTotalCount ?? 0;
|
|
346
|
+
let liveLogsDirty = false;
|
|
347
|
+
let lastFlushAt = 0;
|
|
348
|
+
let totalRows = 0;
|
|
349
|
+
let activeMapNodeId: string | null = null;
|
|
350
|
+
let pendingDatasetLifecycleEvents: Array<
|
|
351
|
+
Extract<PlayExecutionEvent, { type: 'dataset.lifecycle' }>
|
|
352
|
+
> = [];
|
|
353
|
+
const pendingActivityObservations = new Map<
|
|
354
|
+
string,
|
|
355
|
+
Extract<PlayExecutionEvent, { type: 'activity.observed' }>['observation']
|
|
356
|
+
>();
|
|
357
|
+
|
|
358
|
+
type ProgressFlushRequest = {
|
|
359
|
+
status: 'running' | 'completed' | 'failed';
|
|
360
|
+
required: boolean;
|
|
361
|
+
terminalLogReplay: TerminalLogReplayPayload | null;
|
|
362
|
+
waiters: Array<{
|
|
363
|
+
resolve: () => void;
|
|
364
|
+
reject: (error: unknown) => void;
|
|
365
|
+
}>;
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
let activeProgressUpload: Promise<void> | null = null;
|
|
369
|
+
let pendingProgressUpload: ProgressFlushRequest | null = null;
|
|
370
|
+
|
|
371
|
+
const mergeProgressFlushRequest = (
|
|
372
|
+
current: ProgressFlushRequest | null,
|
|
373
|
+
next: Omit<ProgressFlushRequest, 'waiters'>,
|
|
374
|
+
waiter: ProgressFlushRequest['waiters'][number],
|
|
375
|
+
): ProgressFlushRequest => ({
|
|
376
|
+
status:
|
|
377
|
+
next.status !== 'running'
|
|
378
|
+
? next.status
|
|
379
|
+
: (current?.status ?? next.status),
|
|
380
|
+
required: next.required || current?.required === true,
|
|
381
|
+
terminalLogReplay:
|
|
382
|
+
next.terminalLogReplay ?? current?.terminalLogReplay ?? null,
|
|
383
|
+
waiters: [...(current?.waiters ?? []), waiter],
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
const requeueProgressEvents = (input: {
|
|
387
|
+
datasetLifecycleEvents: typeof pendingDatasetLifecycleEvents;
|
|
388
|
+
activityObservations: Array<
|
|
389
|
+
Extract<PlayExecutionEvent, { type: 'activity.observed' }>['observation']
|
|
390
|
+
>;
|
|
391
|
+
}): void => {
|
|
392
|
+
pendingDatasetLifecycleEvents = [
|
|
393
|
+
...input.datasetLifecycleEvents,
|
|
394
|
+
...pendingDatasetLifecycleEvents,
|
|
395
|
+
];
|
|
396
|
+
for (const observation of input.activityObservations) {
|
|
397
|
+
const newer = pendingActivityObservations.get(observation.activityId);
|
|
398
|
+
if (!newer || newer.observedAt < observation.observedAt) {
|
|
399
|
+
pendingActivityObservations.set(observation.activityId, observation);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
const startProgressUploadPump = (): void => {
|
|
405
|
+
if (activeProgressUpload || !pendingProgressUpload) return;
|
|
406
|
+
|
|
407
|
+
// Start on the next microtask so an attempt-fence change made by the
|
|
408
|
+
// scheduler in the same turn can invalidate queued observations before
|
|
409
|
+
// any transport side effect begins.
|
|
410
|
+
activeProgressUpload = Promise.resolve()
|
|
411
|
+
.then(async () => {
|
|
412
|
+
while (pendingProgressUpload) {
|
|
413
|
+
const request = pendingProgressUpload;
|
|
414
|
+
pendingProgressUpload = null;
|
|
415
|
+
|
|
416
|
+
const nextProgress = { ...liveNodeProgress };
|
|
417
|
+
const nextLogs = liveLogs.slice();
|
|
418
|
+
const nextLogTotalCount = liveLogsTotalCount;
|
|
419
|
+
const nextDatasetLifecycleEvents = pendingDatasetLifecycleEvents;
|
|
420
|
+
pendingDatasetLifecycleEvents = [];
|
|
421
|
+
const nextActivityObservations = [
|
|
422
|
+
...pendingActivityObservations.values(),
|
|
423
|
+
];
|
|
424
|
+
pendingActivityObservations.clear();
|
|
425
|
+
liveNodeProgressDirty = false;
|
|
426
|
+
liveLogsDirty = false;
|
|
427
|
+
|
|
428
|
+
try {
|
|
429
|
+
if (await isCurrentAttempt()) {
|
|
430
|
+
await updateRunStatusViaAppRuntime(runtimeApi, {
|
|
431
|
+
playId: launch.runId,
|
|
432
|
+
status: request.status,
|
|
433
|
+
liveNodeProgress: nextProgress,
|
|
434
|
+
liveLogs: nextLogs,
|
|
435
|
+
liveLogTotalCount: nextLogTotalCount,
|
|
436
|
+
liveLogProducerAttempt: producerAttempt,
|
|
437
|
+
datasetLifecycleEvents: nextDatasetLifecycleEvents,
|
|
438
|
+
activityObservations: nextActivityObservations,
|
|
439
|
+
terminalLogReplay: request.terminalLogReplay,
|
|
440
|
+
lastCheckpointAt: Date.now(),
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
request.waiters.forEach(({ resolve }) => resolve());
|
|
444
|
+
} catch (error) {
|
|
445
|
+
requeueProgressEvents({
|
|
446
|
+
datasetLifecycleEvents: nextDatasetLifecycleEvents,
|
|
447
|
+
activityObservations: nextActivityObservations,
|
|
448
|
+
});
|
|
449
|
+
console.warn('[postgres-scheduler.progress_flush_failed]', {
|
|
450
|
+
runId: launch.runId,
|
|
451
|
+
error: error instanceof Error ? error.message : String(error),
|
|
452
|
+
});
|
|
453
|
+
if (request.required) {
|
|
454
|
+
request.waiters.forEach(({ reject }) => reject(error));
|
|
455
|
+
} else {
|
|
456
|
+
request.waiters.forEach(({ resolve }) => resolve());
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
})
|
|
461
|
+
.finally(() => {
|
|
462
|
+
activeProgressUpload = null;
|
|
463
|
+
if (pendingProgressUpload) startProgressUploadPump();
|
|
464
|
+
});
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
const flush = (input?: {
|
|
468
|
+
force?: boolean;
|
|
469
|
+
status?: 'running' | 'completed' | 'failed';
|
|
470
|
+
required?: boolean;
|
|
471
|
+
terminalLogReplay?: TerminalLogReplayPayload | null;
|
|
472
|
+
}): Promise<void> => {
|
|
473
|
+
const force = input?.force === true;
|
|
474
|
+
const status = input?.status ?? 'running';
|
|
475
|
+
const required = input?.required === true;
|
|
476
|
+
if (
|
|
477
|
+
!force &&
|
|
478
|
+
!liveNodeProgressDirty &&
|
|
479
|
+
!liveLogsDirty &&
|
|
480
|
+
pendingDatasetLifecycleEvents.length === 0 &&
|
|
481
|
+
pendingActivityObservations.size === 0
|
|
482
|
+
) {
|
|
483
|
+
return activeProgressUpload ?? Promise.resolve();
|
|
484
|
+
}
|
|
485
|
+
const now = Date.now();
|
|
486
|
+
if (
|
|
487
|
+
!force &&
|
|
488
|
+
now - lastFlushAt < getAdaptiveRunEventIntervalMs(totalRows)
|
|
489
|
+
) {
|
|
490
|
+
return activeProgressUpload ?? Promise.resolve();
|
|
491
|
+
}
|
|
492
|
+
lastFlushAt = now;
|
|
493
|
+
const requested = new Promise<void>((resolve, reject) => {
|
|
494
|
+
pendingProgressUpload = mergeProgressFlushRequest(
|
|
495
|
+
pendingProgressUpload,
|
|
496
|
+
{
|
|
497
|
+
status,
|
|
498
|
+
required,
|
|
499
|
+
terminalLogReplay: input?.terminalLogReplay ?? null,
|
|
500
|
+
},
|
|
501
|
+
{ resolve, reject },
|
|
502
|
+
);
|
|
503
|
+
});
|
|
504
|
+
startProgressUploadPump();
|
|
505
|
+
return requested;
|
|
506
|
+
};
|
|
507
|
+
|
|
508
|
+
const scheduleFlush = (force = false) => {
|
|
509
|
+
// A best-effort event flush can coalesce with a required terminal flush.
|
|
510
|
+
// The upload pump logs failure and rejects the terminal caller; consume
|
|
511
|
+
// only this detached observer's rejection to avoid an unhandled promise.
|
|
512
|
+
void flush({ force }).catch(() => undefined);
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
const appendLiveLog = (line: string) => {
|
|
516
|
+
const trimmed = line.trim();
|
|
517
|
+
if (!trimmed) {
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
liveLogsTotalCount += 1;
|
|
521
|
+
liveLogs = [...liveLogs, trimmed];
|
|
522
|
+
if (liveLogs.length > LIVE_LOG_TAIL_LIMIT) {
|
|
523
|
+
liveLogs = liveLogs.slice(liveLogs.length - LIVE_LOG_TAIL_LIMIT);
|
|
524
|
+
}
|
|
525
|
+
liveLogsDirty = true;
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
const setNodeProgress = (
|
|
529
|
+
nodeId: string,
|
|
530
|
+
patch: Partial<PlayVisualNodeProgressMap[string]>,
|
|
531
|
+
) => {
|
|
532
|
+
const current = liveNodeProgress[nodeId] ?? {};
|
|
533
|
+
const nextCompleted = Number(patch.completed ?? current.completed ?? 0);
|
|
534
|
+
const nextTotal = Number(patch.total ?? current.total ?? 0);
|
|
535
|
+
const clearCompletedAt =
|
|
536
|
+
patch.completedAt === undefined &&
|
|
537
|
+
Number.isFinite(nextCompleted) &&
|
|
538
|
+
Number.isFinite(nextTotal) &&
|
|
539
|
+
nextTotal > 0 &&
|
|
540
|
+
nextCompleted < nextTotal;
|
|
541
|
+
liveNodeProgress = {
|
|
542
|
+
...liveNodeProgress,
|
|
543
|
+
[nodeId]: {
|
|
544
|
+
...(current.completed !== undefined
|
|
545
|
+
? { completed: current.completed }
|
|
546
|
+
: {}),
|
|
547
|
+
...(current.total !== undefined ? { total: current.total } : {}),
|
|
548
|
+
...(current.failed !== undefined ? { failed: current.failed } : {}),
|
|
549
|
+
...(current.startedRows !== undefined
|
|
550
|
+
? { startedRows: current.startedRows }
|
|
551
|
+
: {}),
|
|
552
|
+
...(current.activeRows !== undefined
|
|
553
|
+
? { activeRows: current.activeRows }
|
|
554
|
+
: {}),
|
|
555
|
+
...(current.waitingRows !== undefined
|
|
556
|
+
? { waitingRows: current.waitingRows }
|
|
557
|
+
: {}),
|
|
558
|
+
...(current.completedRows !== undefined
|
|
559
|
+
? { completedRows: current.completedRows }
|
|
560
|
+
: {}),
|
|
561
|
+
...(current.message !== undefined ? { message: current.message } : {}),
|
|
562
|
+
...(current.artifactTableNamespace !== undefined
|
|
563
|
+
? { artifactTableNamespace: current.artifactTableNamespace }
|
|
564
|
+
: {}),
|
|
565
|
+
...(current.startedAt !== undefined
|
|
566
|
+
? { startedAt: current.startedAt }
|
|
567
|
+
: {}),
|
|
568
|
+
...(current.completedAt !== undefined && !clearCompletedAt
|
|
569
|
+
? { completedAt: current.completedAt }
|
|
570
|
+
: {}),
|
|
571
|
+
...(current.nodeIo !== undefined ? { nodeIo: current.nodeIo } : {}),
|
|
572
|
+
...(patch.completed !== undefined
|
|
573
|
+
? { completed: patch.completed }
|
|
574
|
+
: {}),
|
|
575
|
+
...(patch.total !== undefined ? { total: patch.total } : {}),
|
|
576
|
+
...(patch.failed !== undefined ? { failed: patch.failed } : {}),
|
|
577
|
+
...(patch.startedRows !== undefined
|
|
578
|
+
? { startedRows: patch.startedRows }
|
|
579
|
+
: {}),
|
|
580
|
+
...(patch.activeRows !== undefined
|
|
581
|
+
? { activeRows: patch.activeRows }
|
|
582
|
+
: {}),
|
|
583
|
+
...(patch.waitingRows !== undefined
|
|
584
|
+
? { waitingRows: patch.waitingRows }
|
|
585
|
+
: {}),
|
|
586
|
+
...(patch.completedRows !== undefined
|
|
587
|
+
? { completedRows: patch.completedRows }
|
|
588
|
+
: {}),
|
|
589
|
+
...(patch.message !== undefined ? { message: patch.message } : {}),
|
|
590
|
+
...(patch.artifactTableNamespace !== undefined
|
|
591
|
+
? { artifactTableNamespace: patch.artifactTableNamespace }
|
|
592
|
+
: {}),
|
|
593
|
+
...(patch.startedAt !== undefined
|
|
594
|
+
? { startedAt: patch.startedAt }
|
|
595
|
+
: {}),
|
|
596
|
+
...(patch.completedAt !== undefined
|
|
597
|
+
? { completedAt: patch.completedAt }
|
|
598
|
+
: {}),
|
|
599
|
+
...(patch.nodeIo !== undefined ? { nodeIo: patch.nodeIo } : {}),
|
|
600
|
+
updatedAt: Date.now(),
|
|
601
|
+
},
|
|
602
|
+
};
|
|
603
|
+
liveNodeProgressDirty = true;
|
|
604
|
+
};
|
|
605
|
+
|
|
606
|
+
// Every lifecycle transition flows through setNodeProgress so the
|
|
607
|
+
// liveNodeProgress patch stream is canonical.
|
|
608
|
+
const stepLifecycle = new PlayStepLifecycleTracker(
|
|
609
|
+
orderedNodes,
|
|
610
|
+
() => liveNodeProgress,
|
|
611
|
+
(event) => {
|
|
612
|
+
const patch: Partial<PlayVisualNodeProgressMap[string]> =
|
|
613
|
+
event.transition === 'started'
|
|
614
|
+
? { startedAt: event.at }
|
|
615
|
+
: { completedAt: event.at };
|
|
616
|
+
setNodeProgress(event.nodeId, patch);
|
|
617
|
+
scheduleFlush();
|
|
618
|
+
},
|
|
619
|
+
);
|
|
620
|
+
stepLifecycle.markPreDatasetStepsStarted();
|
|
621
|
+
|
|
622
|
+
const markMapStartedFromLog = (line: string) => {
|
|
623
|
+
const match = line.match(MAP_START_LOG_PATTERN);
|
|
624
|
+
if (!match) {
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
const total = Number(match[1] ?? 0);
|
|
628
|
+
const physicalNamespace = match[2]?.trim() ?? '';
|
|
629
|
+
const alreadySatisfied = Number(match[3] ?? 0);
|
|
630
|
+
const nodeRef = resolveDatasetNodeRefFromTableNamespace(
|
|
631
|
+
mapNodeLookup,
|
|
632
|
+
physicalNamespace,
|
|
633
|
+
);
|
|
634
|
+
if (!nodeRef) {
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
activeMapNodeId = nodeRef.nodeId;
|
|
638
|
+
if (Number.isFinite(total) && total > totalRows) {
|
|
639
|
+
totalRows = total;
|
|
640
|
+
}
|
|
641
|
+
stepLifecycle.onMapStarted(nodeRef.nodeId);
|
|
642
|
+
// Streamed maps emit this diagnostic once per source page. The value in
|
|
643
|
+
// the log is page-local duplicate reuse, not cumulative durable progress.
|
|
644
|
+
// Preserve the typed commit-event counters already folded for prior pages;
|
|
645
|
+
// otherwise every new page transiently resets completed to zero and makes
|
|
646
|
+
// waitingRows contradict the canonical total.
|
|
647
|
+
const current = liveNodeProgress[nodeRef.nodeId] ?? {};
|
|
648
|
+
const effectiveTotal = Math.max(
|
|
649
|
+
Number.isFinite(total) && total > 0 ? total : 0,
|
|
650
|
+
Number(current.total ?? 0),
|
|
651
|
+
);
|
|
652
|
+
const completed = Math.max(
|
|
653
|
+
0,
|
|
654
|
+
Number(current.completed ?? 0),
|
|
655
|
+
Number.isFinite(alreadySatisfied) ? alreadySatisfied : 0,
|
|
656
|
+
);
|
|
657
|
+
const failed = Math.max(0, Number(current.failed ?? 0));
|
|
658
|
+
const settled = completed + failed;
|
|
659
|
+
setNodeProgress(nodeRef.nodeId, {
|
|
660
|
+
completed,
|
|
661
|
+
failed,
|
|
662
|
+
total: effectiveTotal > 0 ? effectiveTotal : undefined,
|
|
663
|
+
startedRows: Math.max(Number(current.startedRows ?? 0), settled),
|
|
664
|
+
activeRows: 0,
|
|
665
|
+
waitingRows:
|
|
666
|
+
effectiveTotal > 0 ? Math.max(0, effectiveTotal - settled) : undefined,
|
|
667
|
+
completedRows: completed,
|
|
668
|
+
artifactTableNamespace: nodeRef.artifactTableNamespace,
|
|
669
|
+
startedAt: current.startedAt ?? Date.now(),
|
|
670
|
+
message: rowsProcessedMessage(completed, effectiveTotal),
|
|
671
|
+
});
|
|
672
|
+
};
|
|
673
|
+
|
|
674
|
+
const markMapStartedFromPerfLog = (line: string) => {
|
|
675
|
+
const normalizedLine = line.replace(CTX_LOG_TIMESTAMP_PREFIX_RE, '');
|
|
676
|
+
const match = normalizedLine.match(PERF_MAP_SETUP_LOG_PATTERN);
|
|
677
|
+
if (!match) {
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
const nodeRef = resolveDatasetNodeRefFromTableNamespace(
|
|
681
|
+
mapNodeLookup,
|
|
682
|
+
match[1] ?? '',
|
|
683
|
+
);
|
|
684
|
+
if (!nodeRef) {
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
const total = Number(match[2] ?? 0);
|
|
688
|
+
activeMapNodeId = nodeRef.nodeId;
|
|
689
|
+
if (Number.isFinite(total) && total > totalRows) {
|
|
690
|
+
totalRows = total;
|
|
691
|
+
}
|
|
692
|
+
stepLifecycle.onMapStarted(nodeRef.nodeId);
|
|
693
|
+
const current = liveNodeProgress[nodeRef.nodeId] ?? {};
|
|
694
|
+
const effectiveTotal = Math.max(
|
|
695
|
+
Number.isFinite(total) && total > 0 ? total : 0,
|
|
696
|
+
Number(current.total ?? 0),
|
|
697
|
+
);
|
|
698
|
+
const completed = Math.max(0, Number(current.completed ?? 0));
|
|
699
|
+
const failed = Math.max(0, Number(current.failed ?? 0));
|
|
700
|
+
const settled = completed + failed;
|
|
701
|
+
setNodeProgress(nodeRef.nodeId, {
|
|
702
|
+
completed,
|
|
703
|
+
failed,
|
|
704
|
+
total: effectiveTotal > 0 ? effectiveTotal : undefined,
|
|
705
|
+
startedRows: Math.max(Number(current.startedRows ?? 0), settled),
|
|
706
|
+
activeRows: 0,
|
|
707
|
+
waitingRows:
|
|
708
|
+
effectiveTotal > 0 ? Math.max(0, effectiveTotal - settled) : undefined,
|
|
709
|
+
completedRows: completed,
|
|
710
|
+
artifactTableNamespace: nodeRef.artifactTableNamespace,
|
|
711
|
+
startedAt: current.startedAt ?? Date.now(),
|
|
712
|
+
message: rowsProcessedMessage(completed, effectiveTotal),
|
|
713
|
+
});
|
|
714
|
+
};
|
|
715
|
+
|
|
716
|
+
const markToolBatchInFlightFromLog = (line: string) => {
|
|
717
|
+
if (!activeMapNodeId) {
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
720
|
+
const match = line.match(PLAY_TOOL_BATCH_LOG_PATTERN);
|
|
721
|
+
if (!match) {
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
const callCount = Number(match[2] ?? 0);
|
|
725
|
+
if (!Number.isFinite(callCount) || callCount <= 0) {
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
const current = liveNodeProgress[activeMapNodeId] ?? {};
|
|
729
|
+
const completed = Number(current.completed ?? 0);
|
|
730
|
+
const failed = Number(current.failed ?? 0);
|
|
731
|
+
const total = Number(current.total ?? 0);
|
|
732
|
+
const settled = completed + failed;
|
|
733
|
+
const activeRows =
|
|
734
|
+
total > 0 ? Math.min(callCount, Math.max(0, total - settled)) : callCount;
|
|
735
|
+
const startedRows = Math.max(
|
|
736
|
+
Number(current.startedRows ?? 0),
|
|
737
|
+
settled + activeRows,
|
|
738
|
+
);
|
|
739
|
+
setNodeProgress(activeMapNodeId, {
|
|
740
|
+
startedRows: total > 0 ? Math.min(total, startedRows) : startedRows,
|
|
741
|
+
activeRows,
|
|
742
|
+
waitingRows:
|
|
743
|
+
total > 0 ? Math.max(0, total - settled - activeRows) : undefined,
|
|
744
|
+
completedRows: completed,
|
|
745
|
+
message: callsInFlightMessage({
|
|
746
|
+
activeRows,
|
|
747
|
+
completedRows: completed,
|
|
748
|
+
totalRows: total,
|
|
749
|
+
}),
|
|
750
|
+
});
|
|
751
|
+
};
|
|
752
|
+
|
|
753
|
+
const applyExecutionEvent = (event: PlayExecutionEvent) => {
|
|
754
|
+
if (event.type === 'docflow.node.hit') {
|
|
755
|
+
setNodeProgress(event.nodeId, {
|
|
756
|
+
startedAt: event.at,
|
|
757
|
+
completedAt: event.at,
|
|
758
|
+
});
|
|
759
|
+
scheduleFlush(true);
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
if (
|
|
763
|
+
event.type === 'docflow.node.started' ||
|
|
764
|
+
event.type === 'docflow.node.completed' ||
|
|
765
|
+
event.type === 'docflow.node.failed'
|
|
766
|
+
) {
|
|
767
|
+
const current = liveNodeProgress[event.nodeId];
|
|
768
|
+
const currentAttempt = current?.nodeIo?.attempt ?? -1;
|
|
769
|
+
if (event.attempt < currentAttempt) return;
|
|
770
|
+
if (
|
|
771
|
+
event.attempt === currentAttempt &&
|
|
772
|
+
docflowInvocationSequence(event.invocationId) <
|
|
773
|
+
docflowInvocationSequence(current?.nodeIo?.invocationId)
|
|
774
|
+
) {
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
if (event.type === 'docflow.node.started') {
|
|
778
|
+
liveNodeProgress = {
|
|
779
|
+
...liveNodeProgress,
|
|
780
|
+
[event.nodeId]: {
|
|
781
|
+
startedAt: event.at,
|
|
782
|
+
updatedAt: event.at,
|
|
783
|
+
nodeIo: {
|
|
784
|
+
attempt: event.attempt,
|
|
785
|
+
invocationId: event.invocationId,
|
|
786
|
+
inputs: event.inputs,
|
|
787
|
+
...(event.inputsTruncated ? { inputsTruncated: true } : {}),
|
|
788
|
+
},
|
|
789
|
+
},
|
|
790
|
+
};
|
|
791
|
+
liveNodeProgressDirty = true;
|
|
792
|
+
scheduleFlush(true);
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
if (event.type === 'docflow.node.completed') {
|
|
796
|
+
setNodeProgress(event.nodeId, {
|
|
797
|
+
startedAt: current?.startedAt ?? event.at,
|
|
798
|
+
completedAt: event.at,
|
|
799
|
+
nodeIo: {
|
|
800
|
+
attempt: event.attempt,
|
|
801
|
+
invocationId: event.invocationId,
|
|
802
|
+
inputs: event.inputs,
|
|
803
|
+
...(event.inputsTruncated ? { inputsTruncated: true } : {}),
|
|
804
|
+
outputs: event.outputs,
|
|
805
|
+
...(event.outputsTruncated ? { outputsTruncated: true } : {}),
|
|
806
|
+
error: null,
|
|
807
|
+
},
|
|
808
|
+
});
|
|
809
|
+
scheduleFlush(true);
|
|
810
|
+
return;
|
|
811
|
+
}
|
|
812
|
+
if (event.type === 'docflow.node.failed') {
|
|
813
|
+
setNodeProgress(event.nodeId, {
|
|
814
|
+
startedAt: current?.startedAt ?? event.at,
|
|
815
|
+
completedAt: event.at,
|
|
816
|
+
nodeIo: {
|
|
817
|
+
attempt: event.attempt,
|
|
818
|
+
invocationId: event.invocationId,
|
|
819
|
+
inputs: event.inputs,
|
|
820
|
+
...(event.inputsTruncated ? { inputsTruncated: true } : {}),
|
|
821
|
+
error: event.error,
|
|
822
|
+
},
|
|
823
|
+
});
|
|
824
|
+
scheduleFlush(true);
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
if (event.type === 'activity.observed') {
|
|
829
|
+
pendingActivityObservations.set(
|
|
830
|
+
event.observation.activityId,
|
|
831
|
+
event.observation,
|
|
832
|
+
);
|
|
833
|
+
scheduleFlush(true);
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
if (event.type === 'dataset.lifecycle') {
|
|
837
|
+
pendingDatasetLifecycleEvents.push(event);
|
|
838
|
+
scheduleFlush(true);
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
// ADR 0018: tool-node lifecycle is an explicit typed runtime event. It
|
|
842
|
+
// replaces the `Calling tool: <id>` / `Tool <id> failed` stdout regexes
|
|
843
|
+
// this reporter used to run over the customer log channel.
|
|
844
|
+
if (event.type === 'tool.call.started') {
|
|
845
|
+
stepLifecycle.onToolCalled(event.toolId);
|
|
846
|
+
scheduleFlush();
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
if (event.type === 'tool.call.settled') {
|
|
850
|
+
if (event.outcome === 'failed') {
|
|
851
|
+
stepLifecycle.onToolFailed(event.toolId);
|
|
852
|
+
scheduleFlush(true);
|
|
853
|
+
}
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
if (!event.type.startsWith('map.')) {
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
// The inline Node runner emits map events with mapNodeId null (unlike the
|
|
860
|
+
// workers runtime), so fall back to resolving the static-pipeline node
|
|
861
|
+
// from the event's table namespace — same lookup the log parser uses.
|
|
862
|
+
const nodeId =
|
|
863
|
+
event.mapNodeId?.trim() ||
|
|
864
|
+
resolveDatasetNodeRefFromTableNamespace(
|
|
865
|
+
mapNodeLookup,
|
|
866
|
+
event.artifactTableNamespace || event.logicalNamespace,
|
|
867
|
+
)?.nodeId;
|
|
868
|
+
if (!nodeId) {
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
activeMapNodeId = nodeId;
|
|
872
|
+
const eventTotalRows = 'totalRows' in event ? event.totalRows : undefined;
|
|
873
|
+
if (
|
|
874
|
+
typeof eventTotalRows === 'number' &&
|
|
875
|
+
Number.isFinite(eventTotalRows) &&
|
|
876
|
+
eventTotalRows > totalRows
|
|
877
|
+
) {
|
|
878
|
+
totalRows = eventTotalRows;
|
|
879
|
+
}
|
|
880
|
+
if (
|
|
881
|
+
event.type === 'map.preparing' ||
|
|
882
|
+
event.type === 'map.started' ||
|
|
883
|
+
event.type === 'map.resumed'
|
|
884
|
+
) {
|
|
885
|
+
stepLifecycle.onMapStarted(nodeId);
|
|
886
|
+
setNodeProgress(nodeId, {
|
|
887
|
+
completed: event.completedRows,
|
|
888
|
+
failed: 0,
|
|
889
|
+
total: eventTotalRows,
|
|
890
|
+
startedRows: event.completedRows,
|
|
891
|
+
activeRows: 0,
|
|
892
|
+
waitingRows:
|
|
893
|
+
typeof eventTotalRows === 'number'
|
|
894
|
+
? Math.max(0, eventTotalRows - event.completedRows)
|
|
895
|
+
: undefined,
|
|
896
|
+
completedRows: event.completedRows,
|
|
897
|
+
artifactTableNamespace: event.artifactTableNamespace,
|
|
898
|
+
startedAt: Date.now(),
|
|
899
|
+
message:
|
|
900
|
+
event.type === 'map.preparing'
|
|
901
|
+
? 'Preparing durable table...'
|
|
902
|
+
: rowsProcessedMessage(event.completedRows, eventTotalRows ?? 0),
|
|
903
|
+
});
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
if (event.type === 'map.progress') {
|
|
907
|
+
const current = liveNodeProgress[nodeId] ?? {};
|
|
908
|
+
const settled = Math.max(0, event.completedRows + event.failedRows);
|
|
909
|
+
const progressTotalRows = Math.max(
|
|
910
|
+
typeof event.totalRows === 'number' && Number.isFinite(event.totalRows)
|
|
911
|
+
? event.totalRows
|
|
912
|
+
: 0,
|
|
913
|
+
Number(current.total ?? 0),
|
|
914
|
+
);
|
|
915
|
+
const startedRows = Math.max(settled, Number(current.startedRows ?? 0));
|
|
916
|
+
const activeRows = Math.max(0, startedRows - settled);
|
|
917
|
+
setNodeProgress(nodeId, {
|
|
918
|
+
completed: event.completedRows,
|
|
919
|
+
failed: event.failedRows,
|
|
920
|
+
total: progressTotalRows > 0 ? progressTotalRows : undefined,
|
|
921
|
+
startedRows,
|
|
922
|
+
activeRows,
|
|
923
|
+
waitingRows:
|
|
924
|
+
progressTotalRows > 0
|
|
925
|
+
? Math.max(0, progressTotalRows - startedRows)
|
|
926
|
+
: undefined,
|
|
927
|
+
completedRows: event.completedRows,
|
|
928
|
+
artifactTableNamespace: event.artifactTableNamespace,
|
|
929
|
+
message: rowsProcessedMessage(event.completedRows, progressTotalRows),
|
|
930
|
+
});
|
|
931
|
+
return;
|
|
932
|
+
}
|
|
933
|
+
if (event.type === 'map.completed' || event.type === 'map.failed') {
|
|
934
|
+
if (event.type === 'map.failed') {
|
|
935
|
+
stepLifecycle.onMapFailed(nodeId);
|
|
936
|
+
} else {
|
|
937
|
+
stepLifecycle.onMapCompleted(nodeId);
|
|
938
|
+
}
|
|
939
|
+
const processedRows = Math.max(0, event.completedRows + event.failedRows);
|
|
940
|
+
const terminalTotal =
|
|
941
|
+
typeof event.totalRows === 'number' && Number.isFinite(event.totalRows)
|
|
942
|
+
? event.totalRows
|
|
943
|
+
: 0;
|
|
944
|
+
setNodeProgress(nodeId, {
|
|
945
|
+
completed: event.completedRows,
|
|
946
|
+
failed: event.failedRows,
|
|
947
|
+
total: event.totalRows,
|
|
948
|
+
startedRows:
|
|
949
|
+
terminalTotal > 0
|
|
950
|
+
? Math.min(terminalTotal, processedRows)
|
|
951
|
+
: processedRows,
|
|
952
|
+
activeRows: 0,
|
|
953
|
+
waitingRows: 0,
|
|
954
|
+
completedRows: event.completedRows,
|
|
955
|
+
artifactTableNamespace: event.artifactTableNamespace,
|
|
956
|
+
completedAt: Date.now(),
|
|
957
|
+
message: rowsProcessedMessage(event.completedRows, event.totalRows),
|
|
958
|
+
});
|
|
959
|
+
activeMapNodeId = null;
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
if (event.type === 'map.suspended') {
|
|
963
|
+
setNodeProgress(nodeId, {
|
|
964
|
+
completed: event.completedRows,
|
|
965
|
+
failed: event.failedRows,
|
|
966
|
+
total: event.totalRows,
|
|
967
|
+
completedRows: event.completedRows,
|
|
968
|
+
artifactTableNamespace: event.artifactTableNamespace,
|
|
969
|
+
message: rowsProcessedMessage(event.completedRows, event.totalRows),
|
|
970
|
+
});
|
|
971
|
+
}
|
|
972
|
+
};
|
|
973
|
+
|
|
974
|
+
const onRunnerEvent = (event: unknown): void => {
|
|
975
|
+
if (!event || typeof event !== 'object') {
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
const type = (event as { type?: unknown }).type;
|
|
979
|
+
if (type === 'log') {
|
|
980
|
+
const logEvent = event as { line?: unknown; source?: unknown };
|
|
981
|
+
const rawLine = logEvent.line;
|
|
982
|
+
if (typeof rawLine !== 'string' || !rawLine) {
|
|
983
|
+
return;
|
|
984
|
+
}
|
|
985
|
+
if (shouldPublishDurableLogEvent(durableLogMode, logEvent)) {
|
|
986
|
+
appendLiveLog(rawLine);
|
|
987
|
+
}
|
|
988
|
+
markMapStartedFromLog(rawLine);
|
|
989
|
+
markMapStartedFromPerfLog(rawLine);
|
|
990
|
+
markToolBatchInFlightFromLog(rawLine);
|
|
991
|
+
scheduleFlush();
|
|
992
|
+
return;
|
|
993
|
+
}
|
|
994
|
+
if (type === 'row_update') {
|
|
995
|
+
// Runtime Sheet rows are owned by the context-level row writer. Progress
|
|
996
|
+
// consumes execution and dataset lifecycle facts only; it never patches
|
|
997
|
+
// the same durable rows through a second write path.
|
|
998
|
+
return;
|
|
999
|
+
}
|
|
1000
|
+
if (type === 'execution_event') {
|
|
1001
|
+
const executionEvent = (event as { event?: PlayExecutionEvent }).event;
|
|
1002
|
+
if (executionEvent && typeof executionEvent.type === 'string') {
|
|
1003
|
+
applyExecutionEvent(executionEvent);
|
|
1004
|
+
scheduleFlush();
|
|
1005
|
+
}
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1008
|
+
};
|
|
1009
|
+
|
|
1010
|
+
// ADR 0016 rule 3: fold durable docflow observations into liveNodeProgress at
|
|
1011
|
+
// terminal so a completed absurd run carries docflow node I/O even when the
|
|
1012
|
+
// live docflow.node.* events were dropped mid-run. A record only supersedes
|
|
1013
|
+
// the current node state when it is at least as recent — later attempt, or
|
|
1014
|
+
// same attempt with a >= invocation sequence — matching the event-path guard
|
|
1015
|
+
// in applyExecutionEvent so live and durable never regress each other.
|
|
1016
|
+
const applyDurableObservations = (
|
|
1017
|
+
observations: DocflowObservationRecord[],
|
|
1018
|
+
): void => {
|
|
1019
|
+
for (const observation of observations) {
|
|
1020
|
+
const nodeId = observation.nodeId.trim();
|
|
1021
|
+
if (!nodeId) continue;
|
|
1022
|
+
const current = liveNodeProgress[nodeId];
|
|
1023
|
+
const currentAttempt = current?.nodeIo?.attempt ?? -1;
|
|
1024
|
+
if (observation.attempt < currentAttempt) continue;
|
|
1025
|
+
if (
|
|
1026
|
+
observation.attempt === currentAttempt &&
|
|
1027
|
+
observation.invocationSeq <
|
|
1028
|
+
docflowInvocationSequence(current?.nodeIo?.invocationId)
|
|
1029
|
+
) {
|
|
1030
|
+
continue;
|
|
1031
|
+
}
|
|
1032
|
+
const at = observation.settledAt ?? observation.startedAt ?? Date.now();
|
|
1033
|
+
setNodeProgress(nodeId, {
|
|
1034
|
+
startedAt: current?.startedAt ?? observation.startedAt ?? at,
|
|
1035
|
+
...(observation.status === 'started' ? {} : { completedAt: at }),
|
|
1036
|
+
nodeIo: {
|
|
1037
|
+
attempt: observation.attempt,
|
|
1038
|
+
...(observation.invocationId
|
|
1039
|
+
? { invocationId: observation.invocationId }
|
|
1040
|
+
: {}),
|
|
1041
|
+
...(observation.inputs ? { inputs: observation.inputs } : {}),
|
|
1042
|
+
...(observation.inputsTruncated ? { inputsTruncated: true } : {}),
|
|
1043
|
+
...(observation.status === 'completed' && observation.outputs
|
|
1044
|
+
? { outputs: observation.outputs }
|
|
1045
|
+
: {}),
|
|
1046
|
+
...(observation.status === 'completed' && observation.outputsTruncated
|
|
1047
|
+
? { outputsTruncated: true }
|
|
1048
|
+
: {}),
|
|
1049
|
+
...(observation.status === 'failed'
|
|
1050
|
+
? { error: observation.error ?? 'Docflow node failed.' }
|
|
1051
|
+
: observation.status === 'completed'
|
|
1052
|
+
? { error: null }
|
|
1053
|
+
: {}),
|
|
1054
|
+
},
|
|
1055
|
+
});
|
|
1056
|
+
}
|
|
1057
|
+
liveNodeProgressDirty = true;
|
|
1058
|
+
};
|
|
1059
|
+
|
|
1060
|
+
// Terminal truth for map/dataset nodes is the durable per-map checkpoint
|
|
1061
|
+
// frame carried on the runner result — NOT the event-fed liveNodeProgress
|
|
1062
|
+
// counters, which can be stale or dropped (a missed map.completed frame, a
|
|
1063
|
+
// node-id resolution miss on a docflow-gated run) and then become the
|
|
1064
|
+
// terminal claim. ADR 0016 rule 3: terminal step progress is derived from the
|
|
1065
|
+
// data plane. `checkpoint.mapFrames` is the map executor's authoritative
|
|
1066
|
+
// settled account (`completedRowsCount` successes-only, `failedRowsCount`
|
|
1067
|
+
// settled-but-failed, `totalRows` the settled denominator), written after the
|
|
1068
|
+
// incremental-persistence flush barrier, so it agrees with the runtime
|
|
1069
|
+
// sheets. Reconcile each map node's terminal progress from it before the
|
|
1070
|
+
// final flush so the persisted ledger — and `summarizeRunRowOutcomes` — carry
|
|
1071
|
+
// the truth.
|
|
1072
|
+
const reconcileTerminalMapProgressFromCheckpoint = (
|
|
1073
|
+
result: PlayRunnerResult | null | undefined,
|
|
1074
|
+
): void => {
|
|
1075
|
+
const mapFrames = result?.checkpoint?.mapFrames;
|
|
1076
|
+
if (!mapFrames || typeof mapFrames !== 'object') {
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
1079
|
+
for (const frame of Object.values(mapFrames)) {
|
|
1080
|
+
if (!frame || typeof frame !== 'object') continue;
|
|
1081
|
+
if (frame.status !== 'completed' && frame.status !== 'failed') continue;
|
|
1082
|
+
const nodeId =
|
|
1083
|
+
frame.mapNodeId?.trim() ||
|
|
1084
|
+
resolveDatasetNodeRefFromTableNamespace(
|
|
1085
|
+
mapNodeLookup,
|
|
1086
|
+
frame.artifactTableNamespace || frame.logicalNamespace,
|
|
1087
|
+
)?.nodeId;
|
|
1088
|
+
if (!nodeId) continue;
|
|
1089
|
+
// `completedRowKeys`/`pendingRowKeys` are emptied at map completion, so
|
|
1090
|
+
// trust the *Count fields; fall back to the key-array length only while a
|
|
1091
|
+
// count is absent (never at a settled frame the executor fully accounts).
|
|
1092
|
+
const failed = Math.max(0, Number(frame.failedRowsCount ?? 0) || 0);
|
|
1093
|
+
const completed = Math.max(
|
|
1094
|
+
0,
|
|
1095
|
+
Number(
|
|
1096
|
+
frame.completedRowsCount ?? frame.completedRowKeys?.length ?? 0,
|
|
1097
|
+
) || 0,
|
|
1098
|
+
);
|
|
1099
|
+
const total =
|
|
1100
|
+
Number.isFinite(frame.totalRows) && frame.totalRows > 0
|
|
1101
|
+
? frame.totalRows
|
|
1102
|
+
: completed + failed;
|
|
1103
|
+
const existing = liveNodeProgress[nodeId] ?? {};
|
|
1104
|
+
// Only correct upward-or-equal on the settled denominator and never lose
|
|
1105
|
+
// a larger already-observed success count from a concurrent flush; the
|
|
1106
|
+
// checkpoint frame is authoritative for the settled split.
|
|
1107
|
+
setNodeProgress(nodeId, {
|
|
1108
|
+
completed,
|
|
1109
|
+
failed,
|
|
1110
|
+
total: total > 0 ? total : undefined,
|
|
1111
|
+
startedRows: total > 0 ? total : completed + failed,
|
|
1112
|
+
activeRows: 0,
|
|
1113
|
+
waitingRows: 0,
|
|
1114
|
+
completedRows: completed,
|
|
1115
|
+
artifactTableNamespace:
|
|
1116
|
+
frame.artifactTableNamespace ||
|
|
1117
|
+
existing.artifactTableNamespace ||
|
|
1118
|
+
undefined,
|
|
1119
|
+
completedAt: existing.completedAt ?? Date.now(),
|
|
1120
|
+
message: rowsProcessedMessage(completed, total > 0 ? total : undefined),
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
1123
|
+
liveNodeProgressDirty = true;
|
|
1124
|
+
};
|
|
1125
|
+
|
|
1126
|
+
// Sheet-table row-outcome counts recorded by the worker before finalize.
|
|
1127
|
+
// These are the reconciliation of record (ADR 0016 rule 3): the runtime
|
|
1128
|
+
// sheet rows exist regardless of runner mode, while checkpoint frames can be
|
|
1129
|
+
// omitted on the detached terminal wire (OMITTED_TERMINAL_REPLAY) and events
|
|
1130
|
+
// never stream while the worker is parked.
|
|
1131
|
+
let terminalSheetOutcomes: Array<{
|
|
1132
|
+
tableNamespace: string;
|
|
1133
|
+
completed: number;
|
|
1134
|
+
failed: number;
|
|
1135
|
+
total: number;
|
|
1136
|
+
}> = [];
|
|
1137
|
+
|
|
1138
|
+
const applyTerminalSheetOutcomes = (
|
|
1139
|
+
outcomes: Array<{
|
|
1140
|
+
tableNamespace: string;
|
|
1141
|
+
completed: number;
|
|
1142
|
+
failed: number;
|
|
1143
|
+
total: number;
|
|
1144
|
+
}>,
|
|
1145
|
+
): void => {
|
|
1146
|
+
terminalSheetOutcomes = outcomes;
|
|
1147
|
+
};
|
|
1148
|
+
|
|
1149
|
+
// Applied AFTER the checkpoint-frame reconcile so the data plane wins when
|
|
1150
|
+
// the two disagree; also the only terminal source when frames are missing
|
|
1151
|
+
// (detached push runs) and liveNodeProgress is empty (zero-event runs).
|
|
1152
|
+
const reconcileTerminalMapProgressFromSheetOutcomes = (): void => {
|
|
1153
|
+
for (const outcome of terminalSheetOutcomes) {
|
|
1154
|
+
const tableNamespace = outcome.tableNamespace.trim();
|
|
1155
|
+
if (!tableNamespace) continue;
|
|
1156
|
+
const nodeRef = resolveDatasetNodeRefFromTableNamespace(
|
|
1157
|
+
mapNodeLookup,
|
|
1158
|
+
tableNamespace,
|
|
1159
|
+
);
|
|
1160
|
+
if (!nodeRef) continue;
|
|
1161
|
+
const completed = Math.max(0, Math.floor(outcome.completed) || 0);
|
|
1162
|
+
const failed = Math.max(0, Math.floor(outcome.failed) || 0);
|
|
1163
|
+
const total =
|
|
1164
|
+
Number.isFinite(outcome.total) && outcome.total > 0
|
|
1165
|
+
? Math.floor(outcome.total)
|
|
1166
|
+
: completed + failed;
|
|
1167
|
+
if (total <= 0 && completed <= 0 && failed <= 0) continue;
|
|
1168
|
+
const existing = liveNodeProgress[nodeRef.nodeId] ?? {};
|
|
1169
|
+
const now = Date.now();
|
|
1170
|
+
setNodeProgress(nodeRef.nodeId, {
|
|
1171
|
+
completed,
|
|
1172
|
+
failed,
|
|
1173
|
+
total: total > 0 ? total : undefined,
|
|
1174
|
+
startedRows: total > 0 ? total : completed + failed,
|
|
1175
|
+
activeRows: 0,
|
|
1176
|
+
waitingRows: 0,
|
|
1177
|
+
completedRows: completed,
|
|
1178
|
+
artifactTableNamespace:
|
|
1179
|
+
existing.artifactTableNamespace ?? nodeRef.artifactTableNamespace,
|
|
1180
|
+
startedAt: existing.startedAt ?? now,
|
|
1181
|
+
completedAt: existing.completedAt ?? now,
|
|
1182
|
+
message: rowsProcessedMessage(completed, total > 0 ? total : undefined),
|
|
1183
|
+
});
|
|
1184
|
+
}
|
|
1185
|
+
liveNodeProgressDirty = true;
|
|
1186
|
+
};
|
|
1187
|
+
|
|
1188
|
+
const finalize = async (
|
|
1189
|
+
result?: PlayRunnerResult | null,
|
|
1190
|
+
options: {
|
|
1191
|
+
status?: 'running' | 'completed' | 'failed';
|
|
1192
|
+
required?: boolean;
|
|
1193
|
+
replayAllTerminalLogs?: boolean;
|
|
1194
|
+
terminalLogProducerAttempt?: number;
|
|
1195
|
+
skipTerminalLogReplay?: boolean;
|
|
1196
|
+
} = {},
|
|
1197
|
+
): Promise<void> => {
|
|
1198
|
+
// Mark started steps terminal with real timestamps. Static branches that
|
|
1199
|
+
// never started remain non-executed; suspended runs stay in-flight.
|
|
1200
|
+
if (result?.status === 'failed') {
|
|
1201
|
+
stepLifecycle.markStartedFailed();
|
|
1202
|
+
} else if (result?.status === 'completed') {
|
|
1203
|
+
stepLifecycle.markAllTerminal();
|
|
1204
|
+
}
|
|
1205
|
+
// Terminal runs derive their per-map step progress from the durable data
|
|
1206
|
+
// plane, overriding any stale/dropped event-fed counters. Checkpoint
|
|
1207
|
+
// frames first (cheap, in-result), then sheet-table counts as the
|
|
1208
|
+
// reconciliation of record. Suspended runs stay mid-flight, so leave their
|
|
1209
|
+
// live counters untouched.
|
|
1210
|
+
if (result?.status === 'completed' || result?.status === 'failed') {
|
|
1211
|
+
reconcileTerminalMapProgressFromCheckpoint(result);
|
|
1212
|
+
reconcileTerminalMapProgressFromSheetOutcomes();
|
|
1213
|
+
}
|
|
1214
|
+
const status = options.status ?? 'running';
|
|
1215
|
+
await flush({
|
|
1216
|
+
force: true,
|
|
1217
|
+
status,
|
|
1218
|
+
required:
|
|
1219
|
+
options.required === true ||
|
|
1220
|
+
status === 'completed' ||
|
|
1221
|
+
status === 'failed',
|
|
1222
|
+
terminalLogReplay:
|
|
1223
|
+
options.skipTerminalLogReplay || !Array.isArray(result?.logs)
|
|
1224
|
+
? null
|
|
1225
|
+
: terminalReplayPayloadForMode({
|
|
1226
|
+
resultLogs: result.logs,
|
|
1227
|
+
durableLogMode,
|
|
1228
|
+
liveLogs,
|
|
1229
|
+
liveLogsTotalCount,
|
|
1230
|
+
replayAllTerminalLogs: options.replayAllTerminalLogs === true,
|
|
1231
|
+
producerAttempt:
|
|
1232
|
+
options.terminalLogProducerAttempt ?? producerAttempt,
|
|
1233
|
+
}),
|
|
1234
|
+
});
|
|
1235
|
+
};
|
|
1236
|
+
|
|
1237
|
+
return {
|
|
1238
|
+
onRunnerEvent,
|
|
1239
|
+
applyDurableObservations,
|
|
1240
|
+
applyTerminalSheetOutcomes,
|
|
1241
|
+
finalize,
|
|
1242
|
+
};
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
export const createDirectWorkerProgressReporter = (input: {
|
|
1246
|
+
launch: PlaySchedulerSubmitInput;
|
|
1247
|
+
producerAttempt?: number;
|
|
1248
|
+
isCurrentAttempt?: () => boolean | Promise<boolean>;
|
|
1249
|
+
initialLiveLogTotalCount?: number;
|
|
1250
|
+
}) =>
|
|
1251
|
+
createPostgresSchedulerProgressReporter({
|
|
1252
|
+
...input,
|
|
1253
|
+
durableLogMode: 'direct_worker',
|
|
1254
|
+
});
|
|
1255
|
+
export type DirectWorkerProgressReporter = PostgresSchedulerProgressReporter;
|