deepline 0.1.228 → 0.1.229

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 (39) hide show
  1. package/dist/bundling-sources/apps/play-runner-workers/src/coordinator-entry.ts +76 -1842
  2. package/dist/bundling-sources/apps/play-runner-workers/src/dedup-do.ts +0 -113
  3. package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +81 -968
  4. package/dist/bundling-sources/apps/play-runner-workers/src/workflow-retry-state.ts +1 -50
  5. package/dist/bundling-sources/sdk/src/release.ts +2 -2
  6. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +67 -15
  7. package/dist/bundling-sources/shared_libs/play-runtime/child-execution-strategy.ts +84 -79
  8. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +152 -688
  9. package/dist/bundling-sources/shared_libs/play-runtime/coordinator-headers.ts +3 -10
  10. package/dist/bundling-sources/shared_libs/play-runtime/ctx-contract.ts +2 -2
  11. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +12 -47
  12. package/dist/bundling-sources/shared_libs/play-runtime/governor/block-reserving-budget-state-backend.ts +0 -2
  13. package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +12 -200
  14. package/dist/bundling-sources/shared_libs/play-runtime/governor/policy.ts +2 -17
  15. package/dist/bundling-sources/shared_libs/play-runtime/play-call-execution.ts +6 -1
  16. package/dist/bundling-sources/shared_libs/play-runtime/play-latency-trace.ts +28 -0
  17. package/dist/bundling-sources/shared_libs/play-runtime/run-execution-scope.ts +16 -64
  18. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api-paths.ts +0 -4
  19. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +37 -9
  20. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +0 -36
  21. package/dist/bundling-sources/shared_libs/play-runtime/suspension.ts +3 -21
  22. package/dist/bundling-sources/shared_libs/play-runtime/test-runtime-seams.ts +9 -1
  23. package/dist/bundling-sources/shared_libs/plays/static-pipeline.ts +2 -0
  24. package/dist/cli/index.js +2 -2
  25. package/dist/cli/index.mjs +2 -2
  26. package/dist/{compiler-manifest-BhgZ23A4.d.ts → compiler-manifest-CYcwzSOJ.d.mts} +2 -0
  27. package/dist/{compiler-manifest-BhgZ23A4.d.mts → compiler-manifest-CYcwzSOJ.d.ts} +2 -0
  28. package/dist/index.d.mts +1 -1
  29. package/dist/index.d.ts +1 -1
  30. package/dist/index.js +2 -2
  31. package/dist/index.mjs +2 -2
  32. package/dist/plays/bundle-play-file.d.mts +2 -2
  33. package/dist/plays/bundle-play-file.d.ts +2 -2
  34. package/package.json +1 -1
  35. package/dist/bundling-sources/apps/play-runner-workers/src/child-manifest-resolver.ts +0 -108
  36. package/dist/bundling-sources/apps/play-runner-workers/src/child-play-await.ts +0 -374
  37. package/dist/bundling-sources/apps/play-runner-workers/src/child-play-submit.ts +0 -203
  38. package/dist/bundling-sources/shared_libs/play-runtime/child-execution-placement.ts +0 -14
  39. package/dist/bundling-sources/shared_libs/play-runtime/child-run-id.ts +0 -121
@@ -1,13 +1,6 @@
1
1
  import type { ExecutionPlan } from '../../../shared_libs/play-runtime/execution-plan';
2
- import type {
3
- PlayCallGovernanceSnapshot,
4
- PlayRunInputPayload,
5
- } from '../../../shared_libs/play-runtime/scheduler-backend';
2
+ import type { PlayRunInputPayload } from '../../../shared_libs/play-runtime/scheduler-backend';
6
3
  import type { PreloadedRuntimeDbSession } from '../../../shared_libs/play-runtime/db-session';
7
- import type {
8
- PlayRuntimeManifest,
9
- PlayRuntimeManifestMap,
10
- } from '../../../shared_libs/plays/compiler-manifest';
11
4
 
12
5
  import {
13
6
  PLAY_SUBMIT_INPUT_INLINE_MAX_BYTES,
@@ -57,8 +50,6 @@ export type WorkflowRetryPlayParams = {
57
50
  }> | null;
58
51
  contractSnapshot?: unknown;
59
52
  executionPlan?: ExecutionPlan | null;
60
- childPlayManifests?: PlayRuntimeManifestMap | null;
61
- playCallGovernance?: PlayCallGovernanceSnapshot | null;
62
53
  preloadedDbSessions?: PreloadedRuntimeDbSession[] | null;
63
54
  preloadedDbSessionRef?: {
64
55
  runId: string;
@@ -100,7 +91,6 @@ export function buildWorkflowRetryParams<
100
91
  ...params,
101
92
  dynamicWorkerCode: null,
102
93
  contractSnapshot: stripRetrySourceSnapshot(params.contractSnapshot),
103
- childPlayManifests: stripRetryChildManifestCode(params.childPlayManifests),
104
94
  packagedFiles: stripRetryPackagedFiles(params.packagedFiles),
105
95
  } satisfies WorkflowRetryPlayParams as TParams;
106
96
  if (jsonByteLength(retryParams) <= WORKFLOW_RETRY_STATE_TARGET_BYTES) {
@@ -112,9 +102,6 @@ export function buildWorkflowRetryParams<
112
102
  retryParams.contractSnapshot,
113
103
  params,
114
104
  ),
115
- childPlayManifests: stripRetryChildManifestToArtifact(
116
- retryParams.childPlayManifests,
117
- ),
118
105
  } satisfies WorkflowRetryPlayParams as TParams;
119
106
  }
120
107
 
@@ -175,42 +162,6 @@ function stripRetryContractSnapshotToArtifact(
175
162
  };
176
163
  }
177
164
 
178
- function stripRetryChildManifestCode(
179
- manifests: PlayRuntimeManifestMap | null | undefined,
180
- ): PlayRuntimeManifestMap | null {
181
- if (!manifests) return null;
182
- const stripped: PlayRuntimeManifestMap = {};
183
- for (const [key, manifest] of Object.entries(manifests)) {
184
- const rest = { ...manifest };
185
- delete rest.bundledCode;
186
- delete rest.sourceCode;
187
- delete (rest as Record<string, unknown>).sourceMap;
188
- stripped[key] = rest;
189
- }
190
- return stripped;
191
- }
192
-
193
- function stripRetryChildManifestToArtifact(
194
- manifests: PlayRuntimeManifestMap | null | undefined,
195
- ): PlayRuntimeManifestMap | null {
196
- if (!manifests) return null;
197
- const stripped: PlayRuntimeManifestMap = {};
198
- for (const [key, manifest] of Object.entries(manifests)) {
199
- stripped[key] = {
200
- playName: manifest.playName,
201
- graphHash: manifest.graphHash,
202
- artifactStorageKey: manifest.artifactStorageKey,
203
- artifactHash: manifest.artifactHash,
204
- staticPipelineHash: manifest.staticPipelineHash,
205
- staticPipeline: manifest.staticPipeline,
206
- compiledAt: manifest.compiledAt,
207
- compilerVersion: manifest.compilerVersion,
208
- maxCreditsPerRun: manifest.maxCreditsPerRun,
209
- };
210
- }
211
- return stripped;
212
- }
213
-
214
165
  function isRecord(value: unknown): value is Record<string, unknown> {
215
166
  return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
216
167
  }
@@ -108,10 +108,10 @@ export const SDK_RELEASE = {
108
108
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
109
109
  // 0.1.220 deprecates SDK CLI versions below 0.1.219 and updates them
110
110
  // automatically without blocking their current command.
111
- version: '0.1.228',
111
+ version: '0.1.229',
112
112
  apiContract: '2026-06-dataset-handle-results-hard-cutover',
113
113
  supportPolicy: {
114
- latest: '0.1.228',
114
+ latest: '0.1.229',
115
115
  minimumSupported: '0.1.53',
116
116
  deprecatedBelow: '0.1.219',
117
117
  commandMinimumSupported: [
@@ -129,13 +129,10 @@ type RuntimeApiRequest =
129
129
  idempotencyKey?: string;
130
130
  }
131
131
  | {
132
- action: 'start_inline_child_run';
132
+ action: 'start_run';
133
133
  idempotencyKey?: string;
134
134
  playName: string;
135
135
  runId: string;
136
- parentRunId?: string | null;
137
- rootRunId?: string | null;
138
- workflowFamilyKey?: string | null;
139
136
  artifactStorageKey?: string | null;
140
137
  artifactHash?: string | null;
141
138
  graphHash?: string | null;
@@ -506,6 +503,20 @@ function isRetryableAppRuntimeResponse(input: {
506
503
  if (!isRetryableAppRuntimeAction(input.action)) {
507
504
  return false;
508
505
  }
506
+ // The app runtime may explicitly classify an otherwise-client-error status
507
+ // as transient. Keep the structured delivery contract authoritative rather
508
+ // than reducing every 4xx to permanent at the worker boundary.
509
+ try {
510
+ const parsed = JSON.parse(input.body) as unknown;
511
+ if (
512
+ parsed &&
513
+ typeof parsed === 'object' &&
514
+ !Array.isArray(parsed) &&
515
+ (parsed as { retryable?: unknown }).retryable === true
516
+ ) {
517
+ return true;
518
+ }
519
+ } catch {}
509
520
  if (
510
521
  input.action === 'append_run_events' &&
511
522
  input.status === 500 &&
@@ -659,7 +670,7 @@ function isRetryableAppRuntimeAction(
659
670
  action === 'release_runtime_step_receipt' ||
660
671
  action === 'save_results' ||
661
672
  action === 'skip_runtime_step_receipt' ||
662
- action === 'start_inline_child_run'
673
+ action === 'start_run'
663
674
  );
664
675
  }
665
676
 
@@ -943,6 +954,40 @@ export class AppRuntimeApiTransportError extends Error {
943
954
  }
944
955
  }
945
956
 
957
+ /**
958
+ * A non-2xx response from the app runtime boundary.
959
+ *
960
+ * Keep the response contract structured here so durable callers can decide
961
+ * whether to retry or block a delivery without parsing an error message.
962
+ */
963
+ export class AppRuntimeApiResponseError extends Error {
964
+ readonly status: number;
965
+ readonly code: string | null;
966
+ readonly requestId: string | null;
967
+ readonly retryable: boolean;
968
+
969
+ constructor(input: {
970
+ action: RuntimeApiRequest['action'];
971
+ status: number;
972
+ code?: string | null;
973
+ requestId?: string | null;
974
+ retryable: boolean;
975
+ detail: string;
976
+ }) {
977
+ super(
978
+ `App runtime API ${input.action} failed with status ${input.status}` +
979
+ `${input.code ? ` code=${input.code}` : ''}` +
980
+ `${input.requestId ? ` request_id=${input.requestId}` : ''}: ` +
981
+ input.detail,
982
+ );
983
+ this.name = 'AppRuntimeApiResponseError';
984
+ this.status = input.status;
985
+ this.code = input.code?.trim() || null;
986
+ this.requestId = input.requestId?.trim() || null;
987
+ this.retryable = input.retryable;
988
+ }
989
+ }
990
+
946
991
  function resolveAppRuntimeApiUrl(context: WorkerRuntimeApiContext): string {
947
992
  const baseUrl = context.baseUrl.trim().replace(/\/$/, '');
948
993
  return `${baseUrl}${PLAY_RUNTIME_API_COMPAT_PATH}`;
@@ -1155,12 +1200,22 @@ async function postAppRuntimeApi<TResponse>(
1155
1200
  });
1156
1201
  const code = appRuntimeErrorCode(response, responseText);
1157
1202
  const requestId = response.headers.get('x-deepline-request-id')?.trim();
1158
- throw new Error(
1159
- `App runtime API ${body.action} failed with status ${response.status}` +
1160
- `${code ? ` code=${code}` : ''}` +
1161
- `${requestId ? ` request_id=${requestId}` : ''}: ` +
1162
- summarizeAppRuntimeErrorBody(responseText),
1163
- );
1203
+ throw new AppRuntimeApiResponseError({
1204
+ action: body.action,
1205
+ status: response.status,
1206
+ code,
1207
+ requestId,
1208
+ // Immediate request retries are intentionally selective, but durable
1209
+ // delivery must never classify an unrecognized upstream 5xx as poison.
1210
+ retryable:
1211
+ response.status >= 500 ||
1212
+ isRetryableAppRuntimeResponse({
1213
+ action: body.action,
1214
+ status: response.status,
1215
+ body: responseText,
1216
+ }),
1217
+ detail: summarizeAppRuntimeErrorBody(responseText),
1218
+ });
1164
1219
  }
1165
1220
 
1166
1221
  throw new Error(`App runtime API ${body.action} failed after retries.`);
@@ -1557,9 +1612,6 @@ export async function startRunViaAppRuntime(
1557
1612
  input: {
1558
1613
  playName: string;
1559
1614
  runId: string;
1560
- parentRunId?: string | null;
1561
- rootRunId?: string | null;
1562
- workflowFamilyKey?: string | null;
1563
1615
  artifactStorageKey?: string | null;
1564
1616
  artifactHash?: string | null;
1565
1617
  graphHash?: string | null;
@@ -1574,7 +1626,7 @@ export async function startRunViaAppRuntime(
1574
1626
  },
1575
1627
  ): Promise<void> {
1576
1628
  await postAppRuntimeApi<{ ok: true }>(context, {
1577
- action: 'start_inline_child_run',
1629
+ action: 'start_run',
1578
1630
  ...input,
1579
1631
  });
1580
1632
  }
@@ -3,101 +3,106 @@ import {
3
3
  type PlayStaticPipeline,
4
4
  } from '../plays/static-pipeline';
5
5
  import type { PlayCallExecution } from './play-call-execution';
6
- import { resolveChildExecutionPlacement } from './child-execution-placement';
7
6
 
8
- export type ChildExecutionStrategy = 'inline' | 'scheduled';
7
+ /**
8
+ * `ctx.runPlay` is function composition. It has exactly one execution
9
+ * placement: inline in the caller's run. Do not add a scheduler fallback
10
+ * here: children that need their own run lifecycle must be top-level plays.
11
+ */
12
+ export type ChildExecutionStrategy = 'inline';
9
13
 
10
14
  export type ChildExecutionDecision = {
11
15
  strategy: ChildExecutionStrategy;
12
- reason:
13
- | 'scalar_child'
14
- | 'missing_static_contract'
15
- | 'dataset_child'
16
- | 'event_wait_child'
17
- | 'explicit_timeout'
18
- | 'explicit_inline'
19
- | 'explicit_child_workflow';
16
+ reason: 'scalar_child' | 'explicit_inline';
20
17
  };
21
18
 
19
+ export type CtxRunPlayInlineOnlyReason =
20
+ | 'missing_static_contract'
21
+ | 'dataset_child'
22
+ | 'event_wait_child'
23
+ | 'suspending_child'
24
+ | 'explicit_timeout'
25
+ | 'explicit_child_workflow';
26
+
27
+ /** Stable machine-readable prefix for every rejected ctx.runPlay shape. */
28
+ export const CTX_RUN_PLAY_INLINE_ONLY = 'CTX_RUN_PLAY_INLINE_ONLY';
29
+
30
+ /**
31
+ * One public error for every unsupported child contract. The checker and
32
+ * runtime deliberately call this same helper so a dynamic child fails with
33
+ * the same actionable error as a statically known child.
34
+ */
35
+ export function ctxRunPlayInlineOnlyMessage(
36
+ childPlayName: string,
37
+ reason: CtxRunPlayInlineOnlyReason,
38
+ ): string {
39
+ const detail: Record<CtxRunPlayInlineOnlyReason, string> = {
40
+ missing_static_contract: 'its static contract could not be resolved',
41
+ dataset_child: 'it uses ctx.dataset(), ctx.csv(), or a Runtime Sheet',
42
+ event_wait_child: 'it waits for an event',
43
+ suspending_child: 'it attempted to suspend the parent execution',
44
+ explicit_timeout: 'it sets an explicit timeout',
45
+ explicit_child_workflow: 'it requests execution: "child-workflow"',
46
+ };
47
+ return (
48
+ `${CTX_RUN_PLAY_INLINE_ONLY}: ctx.runPlay("${childPlayName}") only composes a resolved scalar child; ` +
49
+ `${detail[reason]}. Move that work to a top-level play and compose only the scalar result.`
50
+ );
51
+ }
52
+
22
53
  /**
23
- * Choose execution placement from the child's authored contract. Scalar child
24
- * plays are ordinary function composition. Dataset and event-wait children own
25
- * independent durable state, so they remain scheduler jobs.
54
+ * Resolve an authored child contract. Any shape that would need a second run,
55
+ * durable scheduler state, or a suspension is rejected before invocation.
26
56
  */
27
57
  export function resolveChildExecutionStrategy(input: {
28
58
  pipeline: PlayStaticPipeline | null | undefined;
29
59
  timeoutMs?: number | null;
30
- execution?: PlayCallExecution | null;
60
+ hasExplicitTimeout?: boolean;
61
+ /** `child-workflow` remains accepted as parsed legacy source solely to emit
62
+ * the canonical migration error rather than silently scheduling it. */
63
+ execution?: PlayCallExecution | 'child-workflow' | null;
31
64
  childPlayName?: string | null;
32
65
  }): ChildExecutionDecision {
66
+ const childPlayName = input.childPlayName?.trim() || 'child';
33
67
  if (input.execution === 'child-workflow') {
34
- return { strategy: 'scheduled', reason: 'explicit_child_workflow' };
68
+ throw new Error(
69
+ ctxRunPlayInlineOnlyMessage(childPlayName, 'explicit_child_workflow'),
70
+ );
35
71
  }
36
- const steps = input.pipeline ? flattenStaticPipeline(input.pipeline) : [];
37
- const authoredDecision: ChildExecutionDecision =
38
- input.timeoutMs != null
39
- ? { strategy: 'scheduled', reason: 'explicit_timeout' }
40
- : !input.pipeline
41
- ? { strategy: 'scheduled', reason: 'missing_static_contract' }
42
- : input.pipeline.tableNamespace ||
43
- input.pipeline.sheetContract ||
44
- steps.some((step) => step.type === 'dataset' || step.type === 'csv')
45
- ? { strategy: 'scheduled', reason: 'dataset_child' }
46
- : steps.some(
47
- (step) =>
48
- step.type === 'tool' &&
49
- (step.isEventWait || step.toolId === 'test_wait_for_event'),
50
- )
51
- ? { strategy: 'scheduled', reason: 'event_wait_child' }
52
- : { strategy: 'inline', reason: 'scalar_child' };
53
- if (input.execution === 'inline') {
54
- if (
55
- authoredDecision.strategy === 'scheduled' &&
56
- authoredDecision.reason !== 'missing_static_contract'
57
- ) {
58
- throw new Error(
59
- inlineExecutionRequiresScalarChildMessage(
60
- input.childPlayName?.trim() || 'child',
61
- authoredDecision.reason,
62
- ),
63
- );
64
- }
65
- return { strategy: 'inline', reason: 'explicit_inline' };
72
+ if (!input.pipeline) {
73
+ throw new Error(
74
+ ctxRunPlayInlineOnlyMessage(childPlayName, 'missing_static_contract'),
75
+ );
66
76
  }
67
- const placement = resolveChildExecutionPlacement({
68
- requiresWorkflow: authoredDecision.strategy === 'scheduled',
69
- execution: input.execution,
70
- });
71
- if (placement.strategy === 'inline') {
72
- return { strategy: 'inline', reason: 'scalar_child' };
77
+ if (input.hasExplicitTimeout === true || input.timeoutMs != null) {
78
+ throw new Error(
79
+ ctxRunPlayInlineOnlyMessage(childPlayName, 'explicit_timeout'),
80
+ );
73
81
  }
74
- return authoredDecision;
75
- }
76
82
 
77
- export function inlineExecutionRequiresScalarChildMessage(
78
- childPlayName: string,
79
- reason: ChildExecutionDecision['reason'],
80
- ): string {
81
- return (
82
- `ctx.runPlay("${childPlayName}") requested execution: "inline", but the child requires a child workflow ` +
83
- `(${reason}). Remove the explicit execution option or use execution: "child-workflow".`
84
- );
85
- }
86
-
87
- /**
88
- * Verbatim rejection message for a scheduling-required child invoked per row.
89
- * Shared by the static preflight (`plays check`/publish gate) and the runtime
90
- * launch guard so a dynamically-named child fails with the EXACT same text as a
91
- * statically-provable one. See ADR 0013.
92
- */
93
- export function inlineChildScheduledInRowMessage(
94
- childPlayName: string,
95
- rowContextField: string,
96
- ): string {
97
- return (
98
- `ctx.runPlay("${childPlayName}") runs per row in the "${rowContextField}" batch, ` +
99
- 'but it is a scheduling-required child (it uses ctx.dataset()/ctx.csv(), waits on an ' +
100
- 'event, sets an explicit timeout, or explicitly requests a child workflow). Row-scoped children must be scalar. ' +
101
- 'Give the batch ONE dataset child at play level instead of fanning a scheduled run out per row.'
102
- );
83
+ const steps = flattenStaticPipeline(input.pipeline);
84
+ if (
85
+ input.pipeline.tableNamespace ||
86
+ input.pipeline.sheetContract ||
87
+ steps.some((step) => step.type === 'dataset' || step.type === 'csv')
88
+ ) {
89
+ throw new Error(
90
+ ctxRunPlayInlineOnlyMessage(childPlayName, 'dataset_child'),
91
+ );
92
+ }
93
+ if (
94
+ steps.some(
95
+ (step) =>
96
+ step.type === 'tool' &&
97
+ (step.isEventWait || step.toolId === 'test_wait_for_event'),
98
+ )
99
+ ) {
100
+ throw new Error(
101
+ ctxRunPlayInlineOnlyMessage(childPlayName, 'event_wait_child'),
102
+ );
103
+ }
104
+ return {
105
+ strategy: 'inline',
106
+ reason: input.execution === 'inline' ? 'explicit_inline' : 'scalar_child',
107
+ };
103
108
  }