deepline 0.1.152 → 0.1.154

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.
Files changed (48) hide show
  1. package/dist/bundling-sources/apps/play-runner-workers/src/coordinator-entry.ts +46 -6
  2. package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +1180 -825
  3. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/batching.ts +34 -18
  4. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/harness-receipt-store.ts +41 -0
  5. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/receipts.ts +143 -8
  6. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-receipts.ts +104 -0
  7. package/dist/bundling-sources/sdk/src/index.ts +0 -1
  8. package/dist/bundling-sources/sdk/src/play.ts +3 -48
  9. package/dist/bundling-sources/sdk/src/plays/harness-stub.ts +27 -2
  10. package/dist/bundling-sources/sdk/src/release.ts +2 -2
  11. package/dist/bundling-sources/sdk/src/worker-play-entry.ts +0 -10
  12. package/dist/bundling-sources/shared_libs/play-data-plane/index.ts +0 -1
  13. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +87 -0
  14. package/dist/bundling-sources/shared_libs/play-runtime/batch-runtime.ts +0 -59
  15. package/dist/bundling-sources/shared_libs/play-runtime/cell-staleness.ts +0 -253
  16. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +805 -1570
  17. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +47 -74
  18. package/dist/bundling-sources/shared_libs/play-runtime/default-batch-strategies.ts +36 -14
  19. package/dist/bundling-sources/shared_libs/play-runtime/durable-call-cache.ts +145 -0
  20. package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +284 -0
  21. package/dist/bundling-sources/shared_libs/play-runtime/postgres-json.ts +12 -5
  22. package/dist/bundling-sources/shared_libs/play-runtime/run-lifecycle-policy.ts +78 -0
  23. package/dist/bundling-sources/shared_libs/play-runtime/run-snapshot-stream.ts +10 -45
  24. package/dist/bundling-sources/shared_libs/play-runtime/runtime-actions.ts +1 -0
  25. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +923 -535
  26. package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver-neon-serverless.ts +58 -78
  27. package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver.ts +12 -1
  28. package/dist/bundling-sources/shared_libs/play-runtime/step-program-dataset-builder.ts +1 -14
  29. package/dist/bundling-sources/shared_libs/play-runtime/tool-execution-outcome.ts +159 -0
  30. package/dist/bundling-sources/shared_libs/play-runtime/tool-result-types.ts +4 -1
  31. package/dist/bundling-sources/shared_libs/play-runtime/work-receipts.ts +32 -0
  32. package/dist/bundling-sources/shared_libs/plays/definition.ts +4 -2
  33. package/dist/bundling-sources/shared_libs/plays/runtime-validation.ts +3 -14
  34. package/dist/bundling-sources/shared_libs/plays/static-pipeline.ts +1 -43
  35. package/dist/cli/index.js +1301 -399
  36. package/dist/cli/index.mjs +1269 -361
  37. package/dist/{compiler-manifest-BjoRENv9.d.ts → compiler-manifest-DW1flrHk.d.mts} +0 -9
  38. package/dist/{compiler-manifest-BjoRENv9.d.mts → compiler-manifest-DW1flrHk.d.ts} +0 -9
  39. package/dist/index.d.mts +9 -38
  40. package/dist/index.d.ts +9 -38
  41. package/dist/index.js +22 -11
  42. package/dist/index.mjs +22 -11
  43. package/dist/plays/bundle-play-file.d.mts +2 -2
  44. package/dist/plays/bundle-play-file.d.ts +2 -2
  45. package/package.json +1 -1
  46. package/dist/bundling-sources/shared_libs/play-data-plane/cell-policy.ts +0 -76
  47. package/dist/bundling-sources/shared_libs/play-runtime/progress-emitter.ts +0 -197
  48. package/dist/bundling-sources/shared_libs/play-runtime/waterfall-replay.ts +0 -79
@@ -46,7 +46,6 @@
46
46
 
47
47
  import {
48
48
  registerRuntimePoolFactory,
49
- registerRuntimeOneShotQueryFactory,
50
49
  type RuntimePool,
51
50
  type RuntimePoolClient,
52
51
  } from './runtime-pg-driver';
@@ -91,15 +90,14 @@ interface NeonPoolConfig {
91
90
 
92
91
  interface NeonModule {
93
92
  Pool: new (config: NeonPoolConfig) => NeonPoolInstance;
94
- neon: (
95
- connectionString: string,
96
- options?: { fullResults?: boolean },
97
- ) => {
98
- query<R = Record<string, unknown>>(
99
- text: string,
100
- params?: unknown[],
101
- ): Promise<{ rows: R[] }>;
102
- };
93
+ }
94
+
95
+ function assertBindParams(params: unknown[] | undefined): void {
96
+ if (params !== undefined && !Array.isArray(params)) {
97
+ throw new Error(
98
+ 'Neon runtime query bind parameters must be an array. Configure Neon client options at client construction, not on query().',
99
+ );
100
+ }
103
101
  }
104
102
 
105
103
  /**
@@ -126,13 +124,15 @@ function wrapNeonClient(client: NeonPoolClient): RuntimePoolClient {
126
124
  query: <R extends Record<string, unknown> = Record<string, unknown>>(
127
125
  text: string,
128
126
  params?: unknown[],
129
- ) =>
130
- (
127
+ ) => {
128
+ assertBindParams(params);
129
+ return (
131
130
  client.query as unknown as (
132
131
  t: string,
133
132
  p?: unknown[],
134
133
  ) => Promise<{ rows: R[] }>
135
- )(text, params),
134
+ )(text, params);
135
+ },
136
136
  release: () => {
137
137
  client.release();
138
138
  },
@@ -167,71 +167,51 @@ function wrapNeonPool(pool: NeonPoolInstance): RuntimePool {
167
167
  * until the import() resolves.
168
168
  */
169
169
  export function installNeonServerlessRuntimePoolDriver(): void {
170
- registerRuntimeOneShotQueryFactory((input) => {
171
- let sqlPromise: Promise<ReturnType<NeonModule['neon']>> | null = null;
172
- async function getSql(): Promise<ReturnType<NeonModule['neon']>> {
173
- if (!sqlPromise) {
174
- sqlPromise = loadNeonModule().then((neon) =>
175
- neon.neon(input.connectionString, { fullResults: true }),
176
- );
177
- }
178
- return sqlPromise;
179
- }
180
- return {
181
- query: async <
182
- R extends Record<string, unknown> = Record<string, unknown>,
183
- >(
184
- text: string,
185
- params?: unknown[],
186
- ) => {
187
- const sql = await getSql();
188
- return await sql.query<R>(text, params);
189
- },
190
- };
191
- });
192
-
193
- registerRuntimePoolFactory((input) => {
194
- // Captured lazily so a Pool is only constructed if the play actually
195
- // connects. Most plays that don't touch Postgres directly never even
196
- // reach this branch — the factory is registered but never invoked.
197
- let lazyPool: NeonPoolInstance | null = null;
170
+ registerRuntimePoolFactory(
171
+ (input) => {
172
+ // Captured lazily so a Pool is only constructed if the play actually
173
+ // connects. Most plays that don't touch Postgres directly never even
174
+ // reach this branch — the factory is registered but never invoked.
175
+ let lazyPool: NeonPoolInstance | null = null;
198
176
 
199
- /**
200
- * Resolve the lazy Pool, creating it on first call.
201
- *
202
- * Race safety: workerd executes within a single JS event loop, so
203
- * two concurrent `connect()` calls on the SAME wrapper run their
204
- * "lazyPool == null" checks in turn — the first creates the Pool,
205
- * the second sees it. No locking needed.
206
- *
207
- * If pool creation fails (e.g. DNS, bad connection string), the
208
- * error propagates out of connect() to the caller. We don't cache
209
- * a failed pool so retries can succeed on transient failures.
210
- */
211
- async function ensurePool(): Promise<NeonPoolInstance> {
212
- if (lazyPool) return lazyPool;
213
- const neon = await loadNeonModule();
214
- const pool = new neon.Pool({
215
- connectionString: input.connectionString,
216
- max: input.maxConnections ?? 4,
217
- idleTimeoutMillis: input.idleTimeoutMs ?? 15_000,
218
- connectionTimeoutMillis: input.connectTimeoutMs ?? 10_000,
219
- });
220
- lazyPool = pool;
221
- return pool;
222
- }
177
+ /**
178
+ * Resolve the lazy Pool, creating it on first call.
179
+ *
180
+ * Race safety: workerd executes within a single JS event loop, so
181
+ * two concurrent `connect()` calls on the SAME wrapper run their
182
+ * "lazyPool == null" checks in turn — the first creates the Pool,
183
+ * the second sees it. No locking needed.
184
+ *
185
+ * If pool creation fails (e.g. DNS, bad connection string), the
186
+ * error propagates out of connect() to the caller. We don't cache
187
+ * a failed pool so retries can succeed on transient failures.
188
+ */
189
+ async function ensurePool(): Promise<NeonPoolInstance> {
190
+ if (lazyPool) return lazyPool;
191
+ const neon = await loadNeonModule();
192
+ const pool = new neon.Pool({
193
+ connectionString: input.connectionString,
194
+ max: input.maxConnections ?? 4,
195
+ idleTimeoutMillis: input.idleTimeoutMs ?? 15_000,
196
+ connectionTimeoutMillis: input.connectTimeoutMs ?? 10_000,
197
+ });
198
+ lazyPool = pool;
199
+ return pool;
200
+ }
223
201
 
224
- return {
225
- connect: async () => {
226
- const pool = await ensurePool();
227
- return wrapNeonClient(await pool.connect());
228
- },
229
- end: async () => {
230
- if (lazyPool) {
231
- await lazyPool.end();
232
- lazyPool = null;
233
- }
234
- },
235
- };
236
- });
202
+ return {
203
+ connect: async () => {
204
+ const pool = await ensurePool();
205
+ return wrapNeonClient(await pool.connect());
206
+ },
207
+ end: async () => {
208
+ if (lazyPool) {
209
+ await lazyPool.end();
210
+ lazyPool = null;
211
+ }
212
+ },
213
+ };
214
+ },
215
+ { canReuseAcrossRequests: false },
216
+ );
237
217
  }
@@ -58,6 +58,7 @@ const runtimePgDriverRegistryKey = Symbol.for(
58
58
  type RuntimePgDriverRegistry = {
59
59
  poolFactory: RuntimePoolFactory | null;
60
60
  oneShotQueryFactory: RuntimeOneShotQueryFactory | null;
61
+ canReusePoolsAcrossRequests: boolean;
61
62
  };
62
63
 
63
64
  function getRuntimePgDriverRegistry(): RuntimePgDriverRegistry {
@@ -67,6 +68,7 @@ function getRuntimePgDriverRegistry(): RuntimePgDriverRegistry {
67
68
  globalWithRegistry[runtimePgDriverRegistryKey] ??= {
68
69
  poolFactory: null,
69
70
  oneShotQueryFactory: null,
71
+ canReusePoolsAcrossRequests: true,
70
72
  };
71
73
  return globalWithRegistry[runtimePgDriverRegistryKey];
72
74
  }
@@ -76,7 +78,10 @@ function getRuntimePgDriverRegistry(): RuntimePgDriverRegistry {
76
78
  * with different factories will throw to prevent silent driver swaps that
77
79
  * would otherwise drop in-flight pooled connections.
78
80
  */
79
- export function registerRuntimePoolFactory(factory: RuntimePoolFactory): void {
81
+ export function registerRuntimePoolFactory(
82
+ factory: RuntimePoolFactory,
83
+ options: { canReuseAcrossRequests?: boolean } = {},
84
+ ): void {
80
85
  const registry = getRuntimePgDriverRegistry();
81
86
  if (registry.poolFactory && registry.poolFactory !== factory) {
82
87
  throw new Error(
@@ -85,12 +90,17 @@ export function registerRuntimePoolFactory(factory: RuntimePoolFactory): void {
85
90
  );
86
91
  }
87
92
  registry.poolFactory = factory;
93
+ registry.canReusePoolsAcrossRequests = options.canReuseAcrossRequests ?? true;
88
94
  }
89
95
 
90
96
  export function isRuntimePoolFactoryRegistered(): boolean {
91
97
  return getRuntimePgDriverRegistry().poolFactory !== null;
92
98
  }
93
99
 
100
+ export function canReuseRuntimePostgresPoolsAcrossRequests(): boolean {
101
+ return getRuntimePgDriverRegistry().canReusePoolsAcrossRequests;
102
+ }
103
+
94
104
  export function registerRuntimeOneShotQueryFactory(
95
105
  factory: RuntimeOneShotQueryFactory,
96
106
  ): void {
@@ -146,4 +156,5 @@ export function __resetRuntimePoolFactoryForTests(): void {
146
156
  const registry = getRuntimePgDriverRegistry();
147
157
  registry.poolFactory = null;
148
158
  registry.oneShotQueryFactory = null;
159
+ registry.canReusePoolsAcrossRequests = true;
149
160
  }
@@ -1,13 +1,10 @@
1
- import type { AuthoredStaleAfterSeconds, PreviousCell } from './cell-staleness';
1
+ import type { PreviousCell } from './cell-staleness';
2
2
 
3
3
  export type StepProgramDatasetOptions = {
4
4
  runIf?: (
5
5
  row: Record<string, unknown>,
6
6
  index: number,
7
7
  ) => boolean | Promise<boolean>;
8
- recompute?: boolean;
9
- recomputeOnError?: boolean;
10
- staleAfterSeconds?: AuthoredStaleAfterSeconds;
11
8
  };
12
9
 
13
10
  export type StepProgramDatasetColumnRunInput<Value = unknown> = {
@@ -50,10 +47,7 @@ function isPreviousCell(value: unknown): value is PreviousCell {
50
47
 
51
48
  export type StepProgramDatasetStep<TResolver> = {
52
49
  name: string;
53
- recompute?: boolean;
54
- recomputeOnError?: boolean;
55
50
  resolver: TResolver;
56
- staleAfterSeconds?: AuthoredStaleAfterSeconds;
57
51
  };
58
52
 
59
53
  export type StepProgramDatasetProgram<TStep> = {
@@ -134,13 +128,6 @@ export class StepProgramDatasetBuilder<
134
128
  normalized.resolver,
135
129
  normalized.options,
136
130
  ),
137
- ...(normalized.options?.staleAfterSeconds !== undefined
138
- ? { staleAfterSeconds: normalized.options.staleAfterSeconds }
139
- : {}),
140
- ...(normalized.options?.recompute === true ? { recompute: true } : {}),
141
- ...(normalized.options?.recomputeOnError === true
142
- ? { recomputeOnError: true }
143
- : {}),
144
131
  } as TStep,
145
132
  ];
146
133
  return this;
@@ -0,0 +1,159 @@
1
+ import {
2
+ cloneToolExecuteResultWithExecution,
3
+ isToolExecuteResult,
4
+ type ToolExecuteResult,
5
+ type ToolResultExecutionMetadata,
6
+ } from './tool-result';
7
+
8
+ type OptionalKey = string | null | undefined;
9
+
10
+ type BaseToolExecutionOutcome = {
11
+ cacheKey?: OptionalKey;
12
+ };
13
+
14
+ export type ToolExecutionOutcome =
15
+ | (BaseToolExecutionOutcome & {
16
+ kind: 'live';
17
+ receiptKey?: OptionalKey;
18
+ })
19
+ | (BaseToolExecutionOutcome & {
20
+ kind: 'checkpoint';
21
+ })
22
+ | (BaseToolExecutionOutcome & {
23
+ kind: 'cache';
24
+ receiptKey: string;
25
+ attachedToReceiptKey?: OptionalKey;
26
+ })
27
+ | (BaseToolExecutionOutcome & {
28
+ kind: 'in_flight';
29
+ receiptKey: string;
30
+ attachedToReceiptKey?: OptionalKey;
31
+ });
32
+
33
+ export type DurableReceiptRecoverySource = 'cache' | 'in_flight' | 'owner';
34
+
35
+ function trimmed(value: OptionalKey): string | null {
36
+ const normalized = value?.trim();
37
+ return normalized ? normalized : null;
38
+ }
39
+
40
+ function optionalCacheKey(value: OptionalKey): Pick<
41
+ ToolResultExecutionMetadata,
42
+ 'cacheKey'
43
+ > {
44
+ const cacheKey = trimmed(value);
45
+ return cacheKey ? { cacheKey } : {};
46
+ }
47
+
48
+ function followerAttachment(input: {
49
+ receiptKey: string;
50
+ attachedToReceiptKey?: OptionalKey;
51
+ }): Pick<ToolResultExecutionMetadata, 'attachedToReceiptKey'> {
52
+ return {
53
+ attachedToReceiptKey:
54
+ trimmed(input.attachedToReceiptKey) ?? input.receiptKey,
55
+ };
56
+ }
57
+
58
+ export function toolExecutionMetadataForOutcome(
59
+ outcome: ToolExecutionOutcome,
60
+ ): ToolResultExecutionMetadata {
61
+ switch (outcome.kind) {
62
+ case 'live': {
63
+ const receiptKey = trimmed(outcome.receiptKey);
64
+ return {
65
+ idempotent: true,
66
+ cached: false,
67
+ source: 'live',
68
+ ...optionalCacheKey(outcome.cacheKey),
69
+ ...(receiptKey ? { receiptRole: 'owner' as const, receiptKey } : {}),
70
+ };
71
+ }
72
+ case 'checkpoint':
73
+ return {
74
+ idempotent: true,
75
+ cached: true,
76
+ source: 'checkpoint',
77
+ ...optionalCacheKey(outcome.cacheKey),
78
+ };
79
+ case 'cache': {
80
+ const receiptKey = trimmed(outcome.receiptKey);
81
+ if (!receiptKey) {
82
+ throw new Error('Cached durable tool results require a receipt key.');
83
+ }
84
+ return {
85
+ idempotent: true,
86
+ cached: true,
87
+ source: 'cache',
88
+ ...optionalCacheKey(outcome.cacheKey),
89
+ receiptRole: 'follower',
90
+ receiptKey,
91
+ ...followerAttachment({
92
+ receiptKey,
93
+ attachedToReceiptKey: outcome.attachedToReceiptKey,
94
+ }),
95
+ };
96
+ }
97
+ case 'in_flight': {
98
+ const receiptKey = trimmed(outcome.receiptKey);
99
+ if (!receiptKey) {
100
+ throw new Error('In-flight durable tool results require a receipt key.');
101
+ }
102
+ return {
103
+ idempotent: true,
104
+ cached: false,
105
+ source: 'in_flight',
106
+ ...optionalCacheKey(outcome.cacheKey),
107
+ receiptRole: 'follower',
108
+ receiptKey,
109
+ ...followerAttachment({
110
+ receiptKey,
111
+ attachedToReceiptKey: outcome.attachedToReceiptKey,
112
+ }),
113
+ };
114
+ }
115
+ default: {
116
+ const exhaustive: never = outcome;
117
+ return exhaustive;
118
+ }
119
+ }
120
+ }
121
+
122
+ export function toolExecutionOutcomeForDurableReceipt(input: {
123
+ source: DurableReceiptRecoverySource;
124
+ receiptKey: string;
125
+ cacheKey?: OptionalKey;
126
+ }): ToolExecutionOutcome {
127
+ return input.source === 'owner'
128
+ ? {
129
+ kind: 'live',
130
+ receiptKey: input.receiptKey,
131
+ cacheKey: input.cacheKey,
132
+ }
133
+ : {
134
+ kind: input.source,
135
+ receiptKey: input.receiptKey,
136
+ attachedToReceiptKey: input.receiptKey,
137
+ cacheKey: input.cacheKey,
138
+ };
139
+ }
140
+
141
+ export function cloneToolExecuteResultWithOutcome<TResult>(
142
+ value: ToolExecuteResult<TResult>,
143
+ outcome: ToolExecutionOutcome,
144
+ ): ToolExecuteResult<TResult> {
145
+ return cloneToolExecuteResultWithExecution(
146
+ value,
147
+ toolExecutionMetadataForOutcome(outcome),
148
+ );
149
+ }
150
+
151
+ export function markToolExecuteResultExecutionOutcome(
152
+ value: unknown,
153
+ outcome: ToolExecutionOutcome,
154
+ ): unknown {
155
+ if (!isToolExecuteResult(value)) {
156
+ return value;
157
+ }
158
+ return cloneToolExecuteResultWithOutcome(value, outcome);
159
+ }
@@ -5,8 +5,11 @@ import type { PlayDataset, SerializedPlayDataset } from '../plays/dataset';
5
5
  export type ToolResultExecutionMetadata = {
6
6
  idempotent: true;
7
7
  cached: boolean;
8
- source: 'live' | 'checkpoint' | 'cache';
8
+ source: 'live' | 'checkpoint' | 'cache' | 'in_flight';
9
9
  cacheKey?: string;
10
+ receiptRole?: 'owner' | 'follower';
11
+ receiptKey?: string;
12
+ attachedToReceiptKey?: string;
10
13
  };
11
14
 
12
15
  export type ToolResultTargetMetadata = {
@@ -18,6 +18,30 @@ export type WorkReceiptCommand = {
18
18
  runId: string;
19
19
  key: string;
20
20
  reclaimRunning?: boolean;
21
+ forceRefresh?: boolean;
22
+ };
23
+
24
+ export type WorkReceiptBatchClaimCommand = {
25
+ playName: string;
26
+ runId: string;
27
+ keys: string[];
28
+ reclaimRunning?: boolean;
29
+ forceRefresh?: boolean;
30
+ };
31
+
32
+ export type WorkReceiptBatchCompleteCommand = {
33
+ playName: string;
34
+ receipts: Array<{ runId: string; key: string; output: unknown }>;
35
+ };
36
+
37
+ export type WorkReceiptBatchFailCommand = {
38
+ playName: string;
39
+ receipts: Array<{ runId: string; key: string; error: string }>;
40
+ };
41
+
42
+ export type WorkReceiptGetCommand = {
43
+ playName: string;
44
+ key: string;
21
45
  };
22
46
 
23
47
  export type WorkReceiptClaim =
@@ -39,13 +63,21 @@ export type WorkReceiptClaim =
39
63
  };
40
64
 
41
65
  export type WorkReceiptStore = {
66
+ getReceipt?(input: WorkReceiptGetCommand): Promise<WorkReceipt | null>;
42
67
  claimReceipt(input: WorkReceiptCommand): Promise<WorkReceiptClaim>;
68
+ claimReceipts?(
69
+ input: WorkReceiptBatchClaimCommand,
70
+ ): Promise<WorkReceiptClaim[]>;
43
71
  completeReceipt(
44
72
  input: WorkReceiptCommand & { output: unknown },
45
73
  ): Promise<WorkReceipt | null>;
74
+ completeReceipts?(
75
+ input: WorkReceiptBatchCompleteCommand,
76
+ ): Promise<WorkReceipt[]>;
46
77
  failReceipt(
47
78
  input: WorkReceiptCommand & { error: string },
48
79
  ): Promise<WorkReceipt | null>;
80
+ failReceipts?(input: WorkReceiptBatchFailCommand): Promise<WorkReceipt[]>;
49
81
  };
50
82
 
51
83
  const SCOPED_WORK_RECEIPT_KEY_VERSION = 'ctxv2';
@@ -198,8 +198,10 @@ export function validatePlayStructuredDefinition(definition: unknown): {
198
198
  if (typedStep.type === 'tool' && !typedStep.toolId?.trim()) {
199
199
  errors.push(`Tool step ${typedStep.alias || index} requires toolId.`);
200
200
  }
201
- if (typedStep.type === 'waterfall' && !typedStep.tool?.trim()) {
202
- errors.push(`Waterfall step ${typedStep.alias || index} requires tool.`);
201
+ if (typedStep.type === 'waterfall') {
202
+ errors.push(
203
+ `Waterfall step ${typedStep.alias || index} is no longer supported. Use explicit tool steps or a steps(...) program.`,
204
+ );
203
205
  }
204
206
  if (typedStep.type === 'run_javascript') {
205
207
  if (!typedStep.execute?.source?.trim()) {
@@ -111,20 +111,9 @@ function validatePlayMapStructure(code: string): string[] {
111
111
  callExpression.callee.property.type === 'Identifier' &&
112
112
  callExpression.callee.property.name === 'waterfall'
113
113
  ) {
114
- const firstArgument = callExpression.arguments[0];
115
- if (firstArgument?.type === 'ObjectExpression') {
116
- const minResultsProperty = firstArgument.properties.find(
117
- (prop) =>
118
- prop.type === 'Property' &&
119
- prop.key.type === 'Identifier' &&
120
- prop.key.name === 'minResults',
121
- );
122
- if (!minResultsProperty) {
123
- errors.push(
124
- 'Inline ctx.waterfall({...}) calls must declare minResults.',
125
- );
126
- }
127
- }
114
+ errors.push(
115
+ 'ctx.waterfall(...) has been removed. Use explicit ctx.tools.execute(...) calls with steps(...) or ordinary TypeScript fallback logic.',
116
+ );
128
117
  }
129
118
  return;
130
119
  }
@@ -131,9 +131,6 @@ export interface PlayStaticColumnProducer {
131
131
  toolId?: string;
132
132
  playId?: string;
133
133
  dependsOnFields?: string[];
134
- recompute?: boolean;
135
- recomputeOnError?: boolean;
136
- staleAfterSeconds?: number;
137
134
  conditional?: boolean;
138
135
  sourceRange?: PlayStaticSourceRange;
139
136
  steps?: PlayStaticColumnProducer[];
@@ -144,9 +141,6 @@ export interface PlayStaticDatasetColumn {
144
141
  id: string;
145
142
  source: PlaySheetColumnSource;
146
143
  sqlName?: string;
147
- recompute?: boolean;
148
- recomputeOnError?: boolean;
149
- staleAfterSeconds?: number;
150
144
  producers: PlayStaticColumnProducer[];
151
145
  }
152
146
 
@@ -337,9 +331,6 @@ export interface PlayStaticSourceRange {
337
331
  type PlayStaticSubstepMetadata = {
338
332
  conditional?: boolean;
339
333
  dependsOnFields?: string[];
340
- recompute?: boolean;
341
- recomputeOnError?: boolean;
342
- staleAfterSeconds?: number;
343
334
  };
344
335
 
345
336
  export type PlayStaticSubstep = PlayStaticSubstepMetadata &
@@ -663,39 +654,11 @@ function compileDatasetColumns(
663
654
  sqlSafePlayColumnName(field),
664
655
  );
665
656
  if (!column) continue;
666
- const pipelineSubstep =
667
- substep.staleAfterSeconds === undefined &&
668
- substep.recompute !== true &&
669
- substep.recomputeOnError !== true
670
- ? pipelineSubsteps.find(
671
- (candidate) => fieldForColumnProducer(candidate) === field,
672
- )
673
- : undefined;
674
657
  const producer = columnProducerFromSubstep(
675
- pipelineSubstep &&
676
- (pipelineSubstep.staleAfterSeconds !== undefined ||
677
- pipelineSubstep.recompute === true ||
678
- pipelineSubstep.recomputeOnError === true)
679
- ? pipelineSubstep
680
- : substep,
658
+ substep,
681
659
  field,
682
660
  );
683
661
  column.producers.push(producer);
684
- if (
685
- column.staleAfterSeconds === undefined &&
686
- producer.staleAfterSeconds !== undefined
687
- ) {
688
- column.staleAfterSeconds = producer.staleAfterSeconds;
689
- }
690
- if (column.recompute !== true && producer.recompute === true) {
691
- column.recompute = true;
692
- }
693
- if (
694
- column.recomputeOnError !== true &&
695
- producer.recomputeOnError === true
696
- ) {
697
- column.recomputeOnError = true;
698
- }
699
662
  }
700
663
 
701
664
  return [...columnsById.values()];
@@ -745,11 +708,6 @@ function columnProducerFromSubstep(
745
708
  ...(substep.dependsOnFields?.length
746
709
  ? { dependsOnFields: [...substep.dependsOnFields] }
747
710
  : {}),
748
- ...(substep.recompute === true ? { recompute: true } : {}),
749
- ...(substep.recomputeOnError === true ? { recomputeOnError: true } : {}),
750
- ...(substep.staleAfterSeconds !== undefined
751
- ? { staleAfterSeconds: substep.staleAfterSeconds }
752
- : {}),
753
711
  ...(substep.conditional ? { conditional: true } : {}),
754
712
  ...(substep.sourceRange ? { sourceRange: substep.sourceRange } : {}),
755
713
  ...(steps && steps.length > 0 ? { steps } : {}),