deepline 0.1.119 → 0.1.121
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/README.md +4 -0
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/README.md +21 -0
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/batching.ts +185 -0
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-batch.ts +107 -0
- package/dist/{repo → bundling-sources}/sdk/src/client.ts +116 -12
- package/dist/bundling-sources/sdk/src/compat.ts +191 -0
- package/dist/bundling-sources/sdk/src/gtm.ts +146 -0
- package/dist/bundling-sources/sdk/src/helpers.ts +12 -0
- package/dist/{repo → bundling-sources}/sdk/src/index.ts +2 -1
- package/dist/{repo → bundling-sources}/sdk/src/play.ts +3 -1
- package/dist/{repo → bundling-sources}/sdk/src/plays/bundle-play-file.ts +17 -5
- package/dist/{repo → bundling-sources}/sdk/src/release.ts +2 -2
- package/dist/{repo → bundling-sources}/sdk/src/runs/observe-transport.ts +2 -3
- package/dist/bundling-sources/shared_libs/play-data-plane/index.ts +3 -0
- package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +838 -0
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +5510 -0
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-contract.ts +261 -0
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +828 -0
- package/dist/bundling-sources/shared_libs/play-runtime/dataset-id.ts +10 -0
- package/dist/bundling-sources/shared_libs/play-runtime/daytona-runtime-config.ts +50 -0
- package/dist/bundling-sources/shared_libs/play-runtime/durability-store.ts +20 -0
- package/dist/bundling-sources/shared_libs/play-runtime/event-wait-tools.ts +9 -0
- package/dist/bundling-sources/shared_libs/play-runtime/governor/in-memory-rate-state-backend.ts +171 -0
- package/dist/bundling-sources/shared_libs/play-runtime/hatchet-cold-execution-diagnosis.ts +321 -0
- package/dist/bundling-sources/shared_libs/play-runtime/hatchet-cold-execution-target.ts +158 -0
- package/dist/bundling-sources/shared_libs/play-runtime/internal-step-ids.ts +34 -0
- package/dist/bundling-sources/shared_libs/play-runtime/ledger-safe-payload.ts +34 -0
- package/dist/bundling-sources/shared_libs/play-runtime/live-state-contract.ts +50 -0
- package/dist/bundling-sources/shared_libs/play-runtime/map-execution-frame.ts +119 -0
- package/dist/{repo → bundling-sources}/shared_libs/play-runtime/map-row-identity.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/play-latency-trace.ts +636 -0
- package/dist/bundling-sources/shared_libs/play-runtime/postgres-json.ts +9 -0
- package/dist/bundling-sources/shared_libs/play-runtime/progress-emitter.ts +197 -0
- package/dist/bundling-sources/shared_libs/play-runtime/projection.ts +262 -0
- package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +143 -0
- package/dist/bundling-sources/shared_libs/play-runtime/public-play-contract.ts +42 -0
- package/dist/bundling-sources/shared_libs/play-runtime/receipt-status.ts +40 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-actions.ts +178 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +4015 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-constraints.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver-neon-serverless.ts +238 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver-pg.ts +53 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver.ts +149 -0
- package/dist/bundling-sources/shared_libs/play-runtime/suspension.ts +68 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-batch-executor.ts +149 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-result-types.ts +159 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tracing.ts +33 -0
- package/dist/bundling-sources/shared_libs/play-runtime/waterfall-replay.ts +79 -0
- package/dist/bundling-sources/shared_libs/play-runtime/worker-api-types.ts +139 -0
- package/dist/bundling-sources/shared_libs/plays/artifact-transport.ts +14 -0
- package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +49 -0
- package/dist/bundling-sources/shared_libs/plays/compiler-manifest.ts +41 -0
- package/dist/bundling-sources/shared_libs/plays/dataset-summary.ts +163 -0
- package/dist/bundling-sources/shared_libs/plays/definition.ts +267 -0
- package/dist/bundling-sources/shared_libs/plays/file-refs.ts +11 -0
- package/dist/bundling-sources/shared_libs/plays/input-contract.ts +146 -0
- package/dist/bundling-sources/shared_libs/plays/resolve-static-pipeline.ts +190 -0
- package/dist/bundling-sources/shared_libs/plays/runtime-validation.ts +417 -0
- package/dist/bundling-sources/shared_libs/plays/tool-codegen.ts +142 -0
- package/dist/bundling-sources/shared_libs/security/safe-outbound-fetch.ts +274 -0
- package/dist/bundling-sources/shared_libs/temporal/preview-config.ts +150 -0
- package/dist/cli/index.js +811 -2207
- package/dist/cli/index.mjs +847 -2258
- package/dist/compiler-manifest-BjoRENv9.d.mts +227 -0
- package/dist/compiler-manifest-BjoRENv9.d.ts +227 -0
- package/dist/index.d.mts +8 -231
- package/dist/index.d.ts +8 -231
- package/dist/index.js +101 -15
- package/dist/index.mjs +101 -15
- package/dist/plays/bundle-play-file.d.mts +120 -0
- package/dist/plays/bundle-play-file.d.ts +120 -0
- package/dist/plays/bundle-play-file.mjs +1830 -0
- package/package.json +4 -9
- /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/child-play-await.ts +0 -0
- /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/child-play-submit.ts +0 -0
- /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/coordinator-entry.ts +0 -0
- /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/dedup-do.ts +0 -0
- /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/entry.ts +0 -0
- /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/runtime/csv-rows.ts +0 -0
- /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/runtime/dataset-handles.ts +0 -0
- /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/runtime/harness-receipt-store.ts +0 -0
- /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/runtime/live-progress.ts +0 -0
- /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/runtime/map-chunk-plan.ts +0 -0
- /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/runtime/receipts.ts +0 -0
- /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/runtime/row-isolation.ts +0 -0
- /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/runtime/tool-http-errors.ts +0 -0
- /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/workflow-instance-create.ts +0 -0
- /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/workflow-retry-state.ts +0 -0
- /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/workflow-retry.ts +0 -0
- /package/dist/{repo → bundling-sources}/sdk/src/agent-runtime.ts +0 -0
- /package/dist/{repo → bundling-sources}/sdk/src/config.ts +0 -0
- /package/dist/{repo → bundling-sources}/sdk/src/errors.ts +0 -0
- /package/dist/{repo → bundling-sources}/sdk/src/http.ts +0 -0
- /package/dist/{repo → bundling-sources}/sdk/src/plays/harness-stub.ts +0 -0
- /package/dist/{repo → bundling-sources}/sdk/src/plays/local-file-discovery.ts +0 -0
- /package/dist/{repo → bundling-sources}/sdk/src/stream-reconnect.ts +0 -0
- /package/dist/{repo → bundling-sources}/sdk/src/tool-output.ts +0 -0
- /package/dist/{repo → bundling-sources}/sdk/src/types.ts +0 -0
- /package/dist/{repo → bundling-sources}/sdk/src/version.ts +0 -0
- /package/dist/{repo → bundling-sources}/sdk/src/worker-play-entry.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-data-plane/cell-policy.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-data-plane/column-names.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-data-plane/sheet-contract.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/backend.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/batch-runtime.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/batching-types.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/cell-staleness.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/coordinator-headers.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/csv-rename.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/db-session-crypto.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/db-session-plan.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/db-session.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/dedup-backend.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/default-batch-strategies.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/email-status.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/execution-plan.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/extractor-targets.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/fullenrich-batching.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/governor/coordinator-rate-state-backend.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/governor/governor.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/governor/policy.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/governor/rate-state-backend.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/live-events.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/play-runtime-batching-registry.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/profiles.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/providers.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/run-failure.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/run-ledger.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/run-snapshot-stream.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/scheduler-backend.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/secret-capability.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/secret-redaction.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/step-lifecycle-tracker.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/step-program-dataset-builder.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/submit-limits.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/tool-result.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/work-receipts.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/plays/bootstrap-routes.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/plays/bundling/index.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/plays/bundling/limits.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/plays/contracts.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/plays/dataset.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/plays/row-identity.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/plays/secret-guardrails.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/plays/static-pipeline.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/security/outbound-url-policy.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/security/safe-fetch.ts +0 -0
- /package/dist/{repo → bundling-sources}/shared_libs/temporal/constants.ts +0 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import type { EmailStatusExtractorConfig } from './email-status';
|
|
2
|
+
import type { DeeplineGetterValueMap } from './extractor-targets';
|
|
3
|
+
|
|
4
|
+
export type ToolResultExecutionMetadata = {
|
|
5
|
+
idempotent: true;
|
|
6
|
+
cached: boolean;
|
|
7
|
+
source: 'live' | 'checkpoint' | 'cache';
|
|
8
|
+
cacheKey?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type ToolResultTargetMetadata = {
|
|
12
|
+
value: unknown;
|
|
13
|
+
path: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type ToolResultListMetadata = {
|
|
17
|
+
path: string;
|
|
18
|
+
count: number | null;
|
|
19
|
+
keys: Record<string, string>;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type ToolResultExtractorDescriptor = {
|
|
23
|
+
paths: readonly string[];
|
|
24
|
+
transforms?: readonly string[];
|
|
25
|
+
enum?: readonly string[];
|
|
26
|
+
overrides?: readonly ToolResultExtractorOverride[];
|
|
27
|
+
emailStatus?: EmailStatusExtractorConfig;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type ToolResultExtractorOverride = {
|
|
31
|
+
paths: readonly string[];
|
|
32
|
+
equals?: string | number | boolean | null;
|
|
33
|
+
value: string | number | boolean | null;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type ToolResultMetadata = {
|
|
37
|
+
toolId: string;
|
|
38
|
+
execution: ToolResultExecutionMetadata;
|
|
39
|
+
targets: Record<string, ToolResultTargetMetadata>;
|
|
40
|
+
lists: Record<string, ToolResultListMetadata>;
|
|
41
|
+
extractors?: Record<string, ToolResultExtractorDescriptor>;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export type ToolResultTargetAccessor<T = unknown> = ToolResultTargetMetadata & {
|
|
45
|
+
get(): T | null;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export type ToolResultListAccessor<
|
|
49
|
+
T = Record<string, unknown>,
|
|
50
|
+
TKey extends string = string,
|
|
51
|
+
> = Omit<ToolResultListMetadata, 'keys'> & {
|
|
52
|
+
keys: Partial<Record<TKey, string>> & Record<string, string>;
|
|
53
|
+
get(): T[];
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export type ToolResultMetadataInput = {
|
|
57
|
+
toolId: string;
|
|
58
|
+
extractors?: Record<string, ToolResultExtractorDescriptor>;
|
|
59
|
+
targetGetters?: Record<string, readonly string[]>;
|
|
60
|
+
listExtractorPaths?: readonly string[];
|
|
61
|
+
listIdentityGetters?: Record<string, readonly string[]>;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export type ToolResultEnvelope<
|
|
65
|
+
TData = unknown,
|
|
66
|
+
TMeta = Record<string, unknown>,
|
|
67
|
+
> = {
|
|
68
|
+
data: TData;
|
|
69
|
+
meta?: TMeta;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export type SerializedToolExecuteResult = {
|
|
73
|
+
__kind: 'deepline.tool_execute_result.v1';
|
|
74
|
+
status: string;
|
|
75
|
+
toolResponse: {
|
|
76
|
+
raw: unknown;
|
|
77
|
+
meta?: Record<string, unknown>;
|
|
78
|
+
};
|
|
79
|
+
metadata: ToolResultMetadataInput;
|
|
80
|
+
execution: ToolResultExecutionMetadata;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export type ToolResponseEnvelope<
|
|
84
|
+
TData = unknown,
|
|
85
|
+
TMeta = Record<string, unknown>,
|
|
86
|
+
> = {
|
|
87
|
+
raw: TData;
|
|
88
|
+
meta?: TMeta;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export type ToolExecuteResultBase<
|
|
92
|
+
TResult = unknown,
|
|
93
|
+
TMeta = Record<string, unknown>,
|
|
94
|
+
> = {
|
|
95
|
+
status: string;
|
|
96
|
+
job_id?: string;
|
|
97
|
+
/** Deepline-owned execution/result metadata. */
|
|
98
|
+
meta?: Record<string, unknown>;
|
|
99
|
+
toolResponse: ToolResponseEnvelope<TResult, TMeta>;
|
|
100
|
+
extractedValues: Record<string, ToolResultTargetAccessor>;
|
|
101
|
+
extractedLists: Record<string, ToolResultListAccessor>;
|
|
102
|
+
/** Convenience alias for play code. Serialized output uses toolResponse. */
|
|
103
|
+
toolOutput: ToolResponseEnvelope<TResult, TMeta>;
|
|
104
|
+
_metadata: {
|
|
105
|
+
toolId: string;
|
|
106
|
+
execution: ToolResultExecutionMetadata;
|
|
107
|
+
targets: Record<string, { value: unknown; path: string }>;
|
|
108
|
+
extractors?: Record<string, ToolResultExtractorDescriptor>;
|
|
109
|
+
lists: Record<
|
|
110
|
+
string,
|
|
111
|
+
{
|
|
112
|
+
path: string;
|
|
113
|
+
count: number | null;
|
|
114
|
+
keys: Record<string, string>;
|
|
115
|
+
}
|
|
116
|
+
>;
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
export type ToolExecuteResultAccessors<
|
|
121
|
+
TExtracted extends Record<string, unknown> = Partial<DeeplineGetterValueMap>,
|
|
122
|
+
TLists extends Record<string, Record<string, unknown>> = Record<
|
|
123
|
+
string,
|
|
124
|
+
Record<string, unknown>
|
|
125
|
+
>,
|
|
126
|
+
> = {
|
|
127
|
+
extractedValues: {
|
|
128
|
+
[K in keyof TExtracted]: ToolResultTargetAccessor<TExtracted[K]>;
|
|
129
|
+
};
|
|
130
|
+
extractedLists: {
|
|
131
|
+
[K in keyof TLists]: ToolResultListAccessor<TLists[K]>;
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Canonical result returned by Deepline tool execution.
|
|
137
|
+
*
|
|
138
|
+
* The top-level object is Deepline-owned execution metadata and semantic
|
|
139
|
+
* extraction state. Raw tool/provider data lives under `toolResponse.raw`;
|
|
140
|
+
* response metadata lives under `toolResponse.meta`. Semantic single-value
|
|
141
|
+
* getters live under `extractedValues.<name>.get()`, and list getters live
|
|
142
|
+
* under `extractedLists.<name>.get()`.
|
|
143
|
+
*
|
|
144
|
+
* Use extractors first when a tool contract exposes them. Drop to
|
|
145
|
+
* `toolResponse.raw` when you need provider-specific fields or when debugging
|
|
146
|
+
* from persisted run rows.
|
|
147
|
+
*
|
|
148
|
+
* @sdkReference runtime 200
|
|
149
|
+
*/
|
|
150
|
+
export type ToolExecuteResult<
|
|
151
|
+
TResult = unknown,
|
|
152
|
+
TMeta = Record<string, unknown>,
|
|
153
|
+
TExtracted extends Record<string, unknown> = Partial<DeeplineGetterValueMap>,
|
|
154
|
+
TLists extends Record<string, Record<string, unknown>> = Record<
|
|
155
|
+
string,
|
|
156
|
+
Record<string, unknown>
|
|
157
|
+
>,
|
|
158
|
+
> = ToolExecuteResultBase<TResult, TMeta> &
|
|
159
|
+
ToolExecuteResultAccessors<TExtracted, TLists>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
type SpanLike = {
|
|
2
|
+
setAttribute: (key: string, value: unknown) => void;
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
type SpanOptions = {
|
|
6
|
+
tracer?: string;
|
|
7
|
+
attributes?: Record<string, unknown>;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export function setSpanAttributes(
|
|
11
|
+
span: SpanLike | null | undefined,
|
|
12
|
+
attributes: Record<string, unknown>,
|
|
13
|
+
): void {
|
|
14
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
15
|
+
span?.setAttribute?.(key, value);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function withActiveSpan<T>(
|
|
20
|
+
_name: string,
|
|
21
|
+
options: SpanOptions,
|
|
22
|
+
fn: (span: SpanLike) => Promise<T>,
|
|
23
|
+
): Promise<T> {
|
|
24
|
+
const attributes = new Map<string, unknown>(
|
|
25
|
+
Object.entries(options.attributes ?? {}),
|
|
26
|
+
);
|
|
27
|
+
const span: SpanLike = {
|
|
28
|
+
setAttribute(key, value) {
|
|
29
|
+
attributes.set(key, value);
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
return await fn(span);
|
|
33
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BatchResult,
|
|
3
|
+
PlayCheckpoint,
|
|
4
|
+
WaterfallRequest,
|
|
5
|
+
} from './ctx-types';
|
|
6
|
+
|
|
7
|
+
export class WaterfallReplayStore {
|
|
8
|
+
constructor(private readonly checkpoint: PlayCheckpoint) {}
|
|
9
|
+
|
|
10
|
+
checkpointKey(input: { rowId: number; rowKey?: string | null }): string {
|
|
11
|
+
return input.rowKey?.trim() || String(input.rowId);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
getResolved(
|
|
15
|
+
queueKey: string,
|
|
16
|
+
input: {
|
|
17
|
+
rowId: number;
|
|
18
|
+
rowKey?: string | null;
|
|
19
|
+
},
|
|
20
|
+
): { found: boolean; value: unknown } {
|
|
21
|
+
const resolved = this.checkpoint.resolvedWaterfalls[queueKey];
|
|
22
|
+
if (!resolved) {
|
|
23
|
+
return { found: false, value: undefined };
|
|
24
|
+
}
|
|
25
|
+
const durableKey = this.checkpointKey(input);
|
|
26
|
+
if (Object.prototype.hasOwnProperty.call(resolved, durableKey)) {
|
|
27
|
+
return { found: true, value: resolved[durableKey] };
|
|
28
|
+
}
|
|
29
|
+
return { found: false, value: undefined };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
setResolved(
|
|
33
|
+
queueKey: string,
|
|
34
|
+
input: {
|
|
35
|
+
rowId: number;
|
|
36
|
+
rowKey?: string | null;
|
|
37
|
+
},
|
|
38
|
+
value: unknown,
|
|
39
|
+
): void {
|
|
40
|
+
this.checkpoint.resolvedWaterfalls[queueKey] ??= {};
|
|
41
|
+
this.checkpoint.resolvedWaterfalls[queueKey]![this.checkpointKey(input)] =
|
|
42
|
+
value;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
readProviderBatch(input: {
|
|
46
|
+
batchKey: string;
|
|
47
|
+
requests: readonly WaterfallRequest[];
|
|
48
|
+
}): Array<{ request: WaterfallRequest; result: unknown | null }> | null {
|
|
49
|
+
const cached = this.checkpoint.completedBatches[input.batchKey];
|
|
50
|
+
if (!cached) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
const recovered = cached.flatMap((entry) => {
|
|
54
|
+
const request = input.requests.find((candidate) =>
|
|
55
|
+
entry.rowKey
|
|
56
|
+
? candidate.rowKey === entry.rowKey
|
|
57
|
+
: candidate.rowId === entry.rowId,
|
|
58
|
+
);
|
|
59
|
+
return request ? [{ request, result: entry.result }] : [];
|
|
60
|
+
});
|
|
61
|
+
return recovered.length > 0 ? recovered : null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
writeProviderBatch(
|
|
65
|
+
batchKey: string,
|
|
66
|
+
results: ReadonlyArray<{
|
|
67
|
+
request: WaterfallRequest;
|
|
68
|
+
result: unknown | null;
|
|
69
|
+
}>,
|
|
70
|
+
): void {
|
|
71
|
+
this.checkpoint.completedBatches[batchKey] = results.map(
|
|
72
|
+
(entry): BatchResult => ({
|
|
73
|
+
rowId: entry.request.rowId,
|
|
74
|
+
rowKey: entry.request.rowKey ?? null,
|
|
75
|
+
result: entry.result,
|
|
76
|
+
}),
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
export type PlayStagedFileRef = {
|
|
2
|
+
storageKind: 'r2';
|
|
3
|
+
storageKey: string;
|
|
4
|
+
logicalPath: string;
|
|
5
|
+
fileName: string;
|
|
6
|
+
contentHash: string;
|
|
7
|
+
contentType: string;
|
|
8
|
+
bytes: number;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type PlayVisualNodeProgress = {
|
|
12
|
+
completed?: number;
|
|
13
|
+
total?: number;
|
|
14
|
+
failed?: number;
|
|
15
|
+
message?: string;
|
|
16
|
+
updatedAt?: number;
|
|
17
|
+
startedAt?: number;
|
|
18
|
+
completedAt?: number;
|
|
19
|
+
artifactTableNamespace?: string | null;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type PlayVisualNodeProgressMap = Record<string, PlayVisualNodeProgress>;
|
|
23
|
+
|
|
24
|
+
export type ComputeBillingItem = {
|
|
25
|
+
itemId: string;
|
|
26
|
+
source: string;
|
|
27
|
+
unit: string;
|
|
28
|
+
units: number;
|
|
29
|
+
providerCostUsd: number;
|
|
30
|
+
metadata?: unknown;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const DAYTONA_COMPUTE_PRICING_USD = {
|
|
34
|
+
vcpuSecond: 0.000014,
|
|
35
|
+
memoryGiBSecond: 0.0000045,
|
|
36
|
+
storageGiBSecond: 0.00000003,
|
|
37
|
+
includedStorageGiB: 5,
|
|
38
|
+
} as const;
|
|
39
|
+
|
|
40
|
+
const TEMPORAL_COMPUTE_PRICING_USD = {
|
|
41
|
+
action: 50 / 1_000_000,
|
|
42
|
+
} as const;
|
|
43
|
+
|
|
44
|
+
const NEON_COMPUTE_PRICING_USD = {
|
|
45
|
+
cuHour: 0.106,
|
|
46
|
+
defaultCu: 1,
|
|
47
|
+
} as const;
|
|
48
|
+
|
|
49
|
+
function roundUsd(amount: number): number {
|
|
50
|
+
return Number(Math.max(0, amount).toFixed(12));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function resolveDaytonaSandboxComputeItem(input: {
|
|
54
|
+
itemId: string;
|
|
55
|
+
source?: string;
|
|
56
|
+
wallTimeSeconds: number;
|
|
57
|
+
cpu: number;
|
|
58
|
+
memoryGiB: number;
|
|
59
|
+
diskGiB: number;
|
|
60
|
+
sandboxId?: string | null;
|
|
61
|
+
startedAt?: number;
|
|
62
|
+
endedAt?: number;
|
|
63
|
+
}): ComputeBillingItem {
|
|
64
|
+
const billableSeconds = Math.max(1, Math.ceil(input.wallTimeSeconds));
|
|
65
|
+
const cpu = Math.max(0, input.cpu);
|
|
66
|
+
const memoryGiB = Math.max(0, input.memoryGiB);
|
|
67
|
+
const billableDiskGiB = Math.max(
|
|
68
|
+
0,
|
|
69
|
+
input.diskGiB - DAYTONA_COMPUTE_PRICING_USD.includedStorageGiB,
|
|
70
|
+
);
|
|
71
|
+
const providerCostUsd = roundUsd(
|
|
72
|
+
billableSeconds *
|
|
73
|
+
(cpu * DAYTONA_COMPUTE_PRICING_USD.vcpuSecond +
|
|
74
|
+
memoryGiB * DAYTONA_COMPUTE_PRICING_USD.memoryGiBSecond +
|
|
75
|
+
billableDiskGiB * DAYTONA_COMPUTE_PRICING_USD.storageGiBSecond),
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
itemId: input.itemId,
|
|
80
|
+
source: input.source ?? 'daytona',
|
|
81
|
+
unit: 'sandbox_second',
|
|
82
|
+
units: billableSeconds,
|
|
83
|
+
providerCostUsd,
|
|
84
|
+
metadata: {
|
|
85
|
+
sandboxId: input.sandboxId ?? null,
|
|
86
|
+
cpu,
|
|
87
|
+
memoryGiB,
|
|
88
|
+
diskGiB: Math.max(0, input.diskGiB),
|
|
89
|
+
billableDiskGiB,
|
|
90
|
+
startedAt: input.startedAt,
|
|
91
|
+
endedAt: input.endedAt,
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function resolveTemporalComputeItem(input: {
|
|
97
|
+
itemId: string;
|
|
98
|
+
actions: number;
|
|
99
|
+
metadata?: unknown;
|
|
100
|
+
}): ComputeBillingItem {
|
|
101
|
+
const actions = Math.max(0, Math.ceil(input.actions));
|
|
102
|
+
return {
|
|
103
|
+
itemId: input.itemId,
|
|
104
|
+
source: 'temporal',
|
|
105
|
+
unit: 'action',
|
|
106
|
+
units: actions,
|
|
107
|
+
providerCostUsd: roundUsd(actions * TEMPORAL_COMPUTE_PRICING_USD.action),
|
|
108
|
+
metadata: input.metadata,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function resolveNeonComputeItem(input: {
|
|
113
|
+
itemId: string;
|
|
114
|
+
activeSeconds: number;
|
|
115
|
+
cu?: number;
|
|
116
|
+
metadata?: unknown;
|
|
117
|
+
}): ComputeBillingItem {
|
|
118
|
+
const billableSeconds = Math.max(0, Math.ceil(input.activeSeconds));
|
|
119
|
+
const cu = Math.max(0, input.cu ?? NEON_COMPUTE_PRICING_USD.defaultCu);
|
|
120
|
+
return {
|
|
121
|
+
itemId: input.itemId,
|
|
122
|
+
source: 'neon',
|
|
123
|
+
unit: 'cu_second',
|
|
124
|
+
units: billableSeconds * cu,
|
|
125
|
+
providerCostUsd: roundUsd(
|
|
126
|
+
billableSeconds * cu * (NEON_COMPUTE_PRICING_USD.cuHour / 3600),
|
|
127
|
+
),
|
|
128
|
+
metadata: {
|
|
129
|
+
activeSeconds: billableSeconds,
|
|
130
|
+
cu,
|
|
131
|
+
cuHourUsd: NEON_COMPUTE_PRICING_USD.cuHour,
|
|
132
|
+
...(input.metadata && typeof input.metadata === 'object'
|
|
133
|
+
? (input.metadata as Record<string, unknown>)
|
|
134
|
+
: input.metadata !== undefined
|
|
135
|
+
? { inputMetadata: input.metadata }
|
|
136
|
+
: {}),
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { PlayBundleArtifact } from './artifact-types';
|
|
2
|
+
|
|
3
|
+
const INLINE_SOURCE_MAP_PATTERN =
|
|
4
|
+
/\r?\n?\/\/# sourceMappingURL=data:application\/json;base64,[A-Za-z0-9+/=]+\s*$/;
|
|
5
|
+
|
|
6
|
+
export function compactPlayArtifactForRuntimeTransport(
|
|
7
|
+
artifact: PlayBundleArtifact,
|
|
8
|
+
): PlayBundleArtifact {
|
|
9
|
+
return {
|
|
10
|
+
...artifact,
|
|
11
|
+
bundledCode: artifact.bundledCode.replace(INLINE_SOURCE_MAP_PATTERN, ''),
|
|
12
|
+
sourceMap: '',
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export type PlayPackageImport = {
|
|
2
|
+
name: string;
|
|
3
|
+
version: string | null;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
export type PlayImportPolicy = {
|
|
7
|
+
localFiles: string[];
|
|
8
|
+
nodeBuiltins: string[];
|
|
9
|
+
packages: PlayPackageImport[];
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type PlayRuntimeFeature =
|
|
13
|
+
| 'artifact_storage'
|
|
14
|
+
| 'checkpoint_resume'
|
|
15
|
+
| 'durable_sleep'
|
|
16
|
+
| 'packaged_files';
|
|
17
|
+
|
|
18
|
+
export type PlayArtifactCompatibility = {
|
|
19
|
+
apiVersion: number;
|
|
20
|
+
artifactVersion: number;
|
|
21
|
+
minRunnerVersion: number;
|
|
22
|
+
runtimeFeatures: PlayRuntimeFeature[];
|
|
23
|
+
runtimeBackend?: string | null;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Identifies which runtime can consume this artifact:
|
|
28
|
+
* - cjs_node20: Daytona / local-process (Node.js)
|
|
29
|
+
* - esm_workers: Cloudflare Workers (V8 isolate)
|
|
30
|
+
*/
|
|
31
|
+
export type PlayArtifactKind = 'cjs_node20' | 'esm_workers';
|
|
32
|
+
|
|
33
|
+
export type PlayBundleArtifact = {
|
|
34
|
+
codeFormat: 'cjs_module' | 'esm_module';
|
|
35
|
+
/** Defaults to cjs_node20 when not present (legacy artifacts). */
|
|
36
|
+
artifactKind?: PlayArtifactKind;
|
|
37
|
+
entryFile: string;
|
|
38
|
+
virtualFilename: string;
|
|
39
|
+
sourceHash: string;
|
|
40
|
+
graphHash: string;
|
|
41
|
+
artifactHash: string;
|
|
42
|
+
sourceMapHash: string;
|
|
43
|
+
bundledCode: string;
|
|
44
|
+
sourceMap: string;
|
|
45
|
+
importPolicy: PlayImportPolicy;
|
|
46
|
+
compatibility: PlayArtifactCompatibility;
|
|
47
|
+
generatedAt: number;
|
|
48
|
+
cacheHit: boolean;
|
|
49
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { PlayArtifactKind } from '../play-runtime/backend';
|
|
2
|
+
import type { PlayStaticPipeline } from './static-pipeline';
|
|
3
|
+
|
|
4
|
+
export const PLAY_COMPILER_MANIFEST_VERSION = 1;
|
|
5
|
+
|
|
6
|
+
export type PlayCompilerDependencyManifest = {
|
|
7
|
+
playName: string;
|
|
8
|
+
/** Original source path for direct imported definePlay dependencies. */
|
|
9
|
+
filePath?: string;
|
|
10
|
+
sourceHash: string;
|
|
11
|
+
graphHash: string;
|
|
12
|
+
artifactHash: string;
|
|
13
|
+
staticPipeline: PlayStaticPipeline;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type PlayCompilerManifest = {
|
|
17
|
+
compilerVersion: number;
|
|
18
|
+
playName: string;
|
|
19
|
+
sourceHash: string;
|
|
20
|
+
graphHash: string;
|
|
21
|
+
artifactHash: string;
|
|
22
|
+
artifactKind?: PlayArtifactKind;
|
|
23
|
+
staticPipeline: PlayStaticPipeline;
|
|
24
|
+
importedPlayDependencies: PlayCompilerDependencyManifest[];
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type PlayRuntimeManifest = {
|
|
28
|
+
playName?: string;
|
|
29
|
+
graphHash: string;
|
|
30
|
+
artifactHash: string;
|
|
31
|
+
artifactStorageKey: string;
|
|
32
|
+
staticPipelineHash: string;
|
|
33
|
+
staticPipeline: PlayStaticPipeline;
|
|
34
|
+
compiledAt: number;
|
|
35
|
+
compilerVersion: string;
|
|
36
|
+
sourceCode?: string | null;
|
|
37
|
+
bundledCode?: string | null;
|
|
38
|
+
maxCreditsPerRun?: number | null;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type PlayRuntimeManifestMap = Record<string, PlayRuntimeManifest>;
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
export type DatasetColumnExecutionBucket =
|
|
2
|
+
| 'queued'
|
|
3
|
+
| 'running'
|
|
4
|
+
| 'completed:executed'
|
|
5
|
+
| 'completed:reused'
|
|
6
|
+
| 'skipped:condition'
|
|
7
|
+
| 'skipped:missed'
|
|
8
|
+
| 'failed';
|
|
9
|
+
|
|
10
|
+
export type DatasetColumnExecutionStats = Record<
|
|
11
|
+
DatasetColumnExecutionBucket,
|
|
12
|
+
string
|
|
13
|
+
>;
|
|
14
|
+
|
|
15
|
+
export type DatasetColumnSummary = {
|
|
16
|
+
non_empty?: string;
|
|
17
|
+
unique?: number;
|
|
18
|
+
execution?: DatasetColumnExecutionStats;
|
|
19
|
+
sample_value?: unknown;
|
|
20
|
+
sample_type?: string;
|
|
21
|
+
top_values?: Record<string, string>;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Persisted-row accounting for a dataset, sourced from the sheet summary's
|
|
26
|
+
* row-level stats (the single source of truth). `persisted` is every durable
|
|
27
|
+
* row (the count `runs export` returns); `succeeded`/`failed` partition it.
|
|
28
|
+
* `runs get --full` renders these so its row count matches what export emits.
|
|
29
|
+
*/
|
|
30
|
+
export type DatasetRowCounts = {
|
|
31
|
+
persisted: number;
|
|
32
|
+
succeeded: number;
|
|
33
|
+
failed: number;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type DatasetSummary = {
|
|
37
|
+
total_rows: number;
|
|
38
|
+
/** Persisted/succeeded/failed breakdown when the sheet summary is available. */
|
|
39
|
+
rowCounts?: DatasetRowCounts;
|
|
40
|
+
columnStats: Record<string, DatasetColumnSummary>;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* `rows: 12 persisted (9 succeeded, 3 failed)` — the canonical row-count line.
|
|
45
|
+
* Falls back to `rows: N persisted` when nothing failed/the breakdown is the
|
|
46
|
+
* full total, so the parenthetical only appears when it adds information.
|
|
47
|
+
*/
|
|
48
|
+
export function formatDatasetRowCountsLine(counts: DatasetRowCounts): string {
|
|
49
|
+
const { persisted, succeeded, failed } = counts;
|
|
50
|
+
if (succeeded === persisted && failed === 0) {
|
|
51
|
+
return `${persisted} persisted`;
|
|
52
|
+
}
|
|
53
|
+
return `${persisted} persisted (${succeeded} succeeded, ${failed} failed)`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export type DatasetExecutionStatsInput = {
|
|
57
|
+
tableNamespace?: string;
|
|
58
|
+
columnStats: Record<
|
|
59
|
+
string,
|
|
60
|
+
{
|
|
61
|
+
queued?: number;
|
|
62
|
+
running?: number;
|
|
63
|
+
completed?: number;
|
|
64
|
+
cached?: number;
|
|
65
|
+
skipped?: number;
|
|
66
|
+
missed?: number;
|
|
67
|
+
failed?: number;
|
|
68
|
+
}
|
|
69
|
+
>;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export function datasetSummaryPercentText(
|
|
73
|
+
numerator: number,
|
|
74
|
+
denominator: number,
|
|
75
|
+
): string {
|
|
76
|
+
return denominator > 0
|
|
77
|
+
? `${numerator}/${denominator} (${Math.round((100 * numerator) / denominator)}%)`
|
|
78
|
+
: '0/0 (0%)';
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function readCount(value: unknown): number {
|
|
82
|
+
return typeof value === 'number' && Number.isFinite(value) && value >= 0
|
|
83
|
+
? Math.trunc(value)
|
|
84
|
+
: 0;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Sum of every per-cell execution bucket for a column. Each bucket is a
|
|
89
|
+
* terminal (or in-flight) state count for one cell of one row, so the sum is
|
|
90
|
+
* the number of cell attempts the column actually has — never less than any
|
|
91
|
+
* single bucket. We use this as the percentage denominator so no displayed
|
|
92
|
+
* execution stat can exceed 100%.
|
|
93
|
+
*
|
|
94
|
+
* Why not the persisted-row total: the persisted total counts distinct rows,
|
|
95
|
+
* but the column buckets can be sourced from a maintained transition-delta
|
|
96
|
+
* table that double-counts retried cells (e.g. a cell that fails then succeeds
|
|
97
|
+
* lands in both `failed` and `completed`). Dividing those numerators by the
|
|
98
|
+
* persisted-row total produced impossible figures like `executed=12/9 (133%)`.
|
|
99
|
+
* Summing the buckets is the semantically honest denominator: each percent is
|
|
100
|
+
* the share of this column's attempts that ended in that bucket.
|
|
101
|
+
*/
|
|
102
|
+
function executionAttemptTotal(
|
|
103
|
+
raw: DatasetExecutionStatsInput['columnStats'][string],
|
|
104
|
+
): number {
|
|
105
|
+
return (
|
|
106
|
+
readCount(raw.queued) +
|
|
107
|
+
readCount(raw.running) +
|
|
108
|
+
readCount(raw.completed) +
|
|
109
|
+
readCount(raw.cached) +
|
|
110
|
+
readCount(raw.skipped) +
|
|
111
|
+
readCount(raw.missed) +
|
|
112
|
+
readCount(raw.failed)
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function formatDatasetExecutionStats(
|
|
117
|
+
raw: DatasetExecutionStatsInput['columnStats'][string],
|
|
118
|
+
// `persistedRowTotal` is kept for callers that pass the run's persisted row
|
|
119
|
+
// count, but it is intentionally NOT the denominator (see
|
|
120
|
+
// `executionAttemptTotal`). The denominator is the per-column attempt total,
|
|
121
|
+
// which guarantees every bucket is <=100%.
|
|
122
|
+
_persistedRowTotal: number,
|
|
123
|
+
): DatasetColumnExecutionStats {
|
|
124
|
+
const denominator = executionAttemptTotal(raw);
|
|
125
|
+
const stats: DatasetColumnExecutionStats = {
|
|
126
|
+
queued: datasetSummaryPercentText(readCount(raw.queued), denominator),
|
|
127
|
+
running: datasetSummaryPercentText(readCount(raw.running), denominator),
|
|
128
|
+
'completed:executed': datasetSummaryPercentText(
|
|
129
|
+
readCount(raw.completed),
|
|
130
|
+
denominator,
|
|
131
|
+
),
|
|
132
|
+
'completed:reused': datasetSummaryPercentText(
|
|
133
|
+
readCount(raw.cached),
|
|
134
|
+
denominator,
|
|
135
|
+
),
|
|
136
|
+
'skipped:condition': datasetSummaryPercentText(
|
|
137
|
+
readCount(raw.skipped),
|
|
138
|
+
denominator,
|
|
139
|
+
),
|
|
140
|
+
'skipped:missed': datasetSummaryPercentText(
|
|
141
|
+
readCount(raw.missed),
|
|
142
|
+
denominator,
|
|
143
|
+
),
|
|
144
|
+
failed: datasetSummaryPercentText(readCount(raw.failed), denominator),
|
|
145
|
+
};
|
|
146
|
+
// Invariant guard: with an attempt-sum denominator no single bucket can
|
|
147
|
+
// exceed the denominator. If it ever does, the upstream summary is corrupt
|
|
148
|
+
// (a bucket count larger than the sum of all buckets is impossible) — flag it
|
|
149
|
+
// loudly as a data bug rather than silently capping.
|
|
150
|
+
if (
|
|
151
|
+
Object.values(stats).some((text) => {
|
|
152
|
+
const match = /\((\d+)%\)/.exec(text);
|
|
153
|
+
return match ? Number(match[1]) > 100 : false;
|
|
154
|
+
})
|
|
155
|
+
) {
|
|
156
|
+
throw new Error(
|
|
157
|
+
`formatDatasetExecutionStats produced a >100% execution stat; column counts are corrupt: ${JSON.stringify(
|
|
158
|
+
raw,
|
|
159
|
+
)}`,
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
return stats;
|
|
163
|
+
}
|