deepline 0.1.214 → 0.1.216

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 (31) hide show
  1. package/dist/bundling-sources/apps/play-runner-workers/src/child-manifest-resolver.ts +108 -0
  2. package/dist/bundling-sources/apps/play-runner-workers/src/coordinator-entry.ts +85 -10
  3. package/dist/bundling-sources/apps/play-runner-workers/src/coordinator-runtime-proxy.ts +34 -0
  4. package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +50 -36
  5. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/harness-receipt-store.ts +12 -0
  6. package/dist/bundling-sources/apps/play-runner-workers/src/workflow-retry.ts +4 -0
  7. package/dist/bundling-sources/sdk/src/client.ts +1 -2
  8. package/dist/bundling-sources/sdk/src/release.ts +2 -2
  9. package/dist/bundling-sources/sdk/src/types.ts +2 -3
  10. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +21 -3
  11. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +95 -144
  12. package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +14 -3
  13. package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +37 -2
  14. package/dist/bundling-sources/shared_libs/play-runtime/profiles.ts +22 -0
  15. package/dist/bundling-sources/shared_libs/play-runtime/providers.ts +32 -0
  16. package/dist/bundling-sources/shared_libs/play-runtime/run-failure.ts +13 -0
  17. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +5 -2
  18. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-session-execution.ts +66 -0
  19. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +18 -55
  20. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +59 -27
  21. package/dist/bundling-sources/shared_libs/play-runtime/runtime-contract.ts +17 -1
  22. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +3 -2
  23. package/dist/bundling-sources/shared_libs/play-runtime/secret-redaction.ts +11 -1
  24. package/dist/bundling-sources/shared_libs/play-runtime/transient-service-error.ts +10 -0
  25. package/dist/cli/index.js +72 -21
  26. package/dist/cli/index.mjs +72 -21
  27. package/dist/index.d.mts +2 -3
  28. package/dist/index.d.ts +2 -3
  29. package/dist/index.js +7 -6
  30. package/dist/index.mjs +7 -6
  31. package/package.json +1 -1
@@ -0,0 +1,108 @@
1
+ import type {
2
+ PlayRuntimeManifest,
3
+ PlayRuntimeManifestMap,
4
+ } from '../../../shared_libs/plays/compiler-manifest';
5
+ import { createSingleFlight } from '../../../shared_libs/play-runtime/single-flight';
6
+
7
+ type ChildManifestResolverInput = {
8
+ preloaded?: PlayRuntimeManifestMap | null;
9
+ resolveManifest: (playRef: string) => Promise<PlayRuntimeManifest | null>;
10
+ };
11
+
12
+ type ChildManifestResolutionState = {
13
+ resolved: Map<string, PlayRuntimeManifest>;
14
+ flights: ReturnType<
15
+ typeof createSingleFlight<string, PlayRuntimeManifest | null>
16
+ >;
17
+ lastAccessedAt: number;
18
+ };
19
+
20
+ const RUN_RESOLUTION_CACHE_TTL_MS = 10 * 60_000;
21
+ const RUN_RESOLUTION_CACHE_MAX_ENTRIES = 128;
22
+ const runResolutionStates = new Map<string, ChildManifestResolutionState>();
23
+
24
+ function seedPreloadedManifests(
25
+ resolved: Map<string, PlayRuntimeManifest>,
26
+ preloaded?: PlayRuntimeManifestMap | null,
27
+ ): void {
28
+ for (const [playRef, manifest] of Object.entries(preloaded ?? {})) {
29
+ resolved.set(playRef, manifest);
30
+ }
31
+ }
32
+
33
+ function createResolutionState(
34
+ preloaded?: PlayRuntimeManifestMap | null,
35
+ ): ChildManifestResolutionState {
36
+ const resolved = new Map<string, PlayRuntimeManifest>(
37
+ Object.entries(preloaded ?? {}),
38
+ );
39
+ return {
40
+ resolved,
41
+ flights: createSingleFlight<string, PlayRuntimeManifest | null>(),
42
+ lastAccessedAt: Date.now(),
43
+ };
44
+ }
45
+
46
+ function resolveWithState(
47
+ state: ChildManifestResolutionState,
48
+ input: ChildManifestResolverInput,
49
+ playRef: string,
50
+ ): Promise<PlayRuntimeManifest | null> {
51
+ state.lastAccessedAt = Date.now();
52
+ seedPreloadedManifests(state.resolved, input.preloaded);
53
+ const cached = state.resolved.get(playRef);
54
+ if (cached) return Promise.resolve(cached);
55
+
56
+ return state.flights.run(playRef, async () => {
57
+ const cachedAfterAdmission = state.resolved.get(playRef);
58
+ if (cachedAfterAdmission) return cachedAfterAdmission;
59
+
60
+ const manifest = await input.resolveManifest(playRef);
61
+ if (manifest) state.resolved.set(playRef, manifest);
62
+ return manifest;
63
+ });
64
+ }
65
+
66
+ function pruneRunResolutionStates(now: number): void {
67
+ for (const [scopeKey, state] of runResolutionStates) {
68
+ if (
69
+ state.flights.activeCount() === 0 &&
70
+ now - state.lastAccessedAt >= RUN_RESOLUTION_CACHE_TTL_MS
71
+ ) {
72
+ runResolutionStates.delete(scopeKey);
73
+ }
74
+ }
75
+ if (runResolutionStates.size <= RUN_RESOLUTION_CACHE_MAX_ENTRIES) return;
76
+
77
+ const evictable = [...runResolutionStates.entries()]
78
+ .filter(([, state]) => state.flights.activeCount() === 0)
79
+ .sort((a, b) => a[1].lastAccessedAt - b[1].lastAccessedAt);
80
+ for (const [scopeKey] of evictable) {
81
+ if (runResolutionStates.size <= RUN_RESOLUTION_CACHE_MAX_ENTRIES) break;
82
+ runResolutionStates.delete(scopeKey);
83
+ }
84
+ }
85
+
86
+ export function createChildManifestResolver(
87
+ input: ChildManifestResolverInput,
88
+ ): (playRef: string) => Promise<PlayRuntimeManifest | null> {
89
+ const state = createResolutionState(input.preloaded);
90
+
91
+ return (playRef) => resolveWithState(state, input, playRef);
92
+ }
93
+
94
+ export function createRunScopedChildManifestResolver(
95
+ input: ChildManifestResolverInput & { scopeKey: string },
96
+ ): (playRef: string) => Promise<PlayRuntimeManifest | null> {
97
+ const now = Date.now();
98
+ pruneRunResolutionStates(now);
99
+ let state = runResolutionStates.get(input.scopeKey);
100
+ if (!state) {
101
+ state = createResolutionState(input.preloaded);
102
+ runResolutionStates.set(input.scopeKey, state);
103
+ pruneRunResolutionStates(now);
104
+ }
105
+ state.lastAccessedAt = now;
106
+
107
+ return (playRef) => resolveWithState(state, input, playRef);
108
+ }
@@ -57,9 +57,13 @@ import {
57
57
  PLAY_RUNTIME_CONTRACT_HEADER,
58
58
  } from '../../../shared_libs/play-runtime/runtime-contract';
59
59
  import {
60
- PLAY_RUNTIME_API_COMPAT_PATH,
61
- PLAY_RUNTIME_TAIL_LOG_COMPAT_PATH,
60
+ PLAY_RUNTIME_API_CURRENT_PATH,
61
+ PLAY_RUNTIME_TAIL_LOG_CURRENT_PATH,
62
62
  } from '../../../shared_libs/play-runtime/runtime-api-paths';
63
+ import {
64
+ executorTokenFromAuthorizationHeader,
65
+ isCoordinatorRuntimeProxyPath,
66
+ } from './coordinator-runtime-proxy';
63
67
  import {
64
68
  decideWorkflowPlatformRetry,
65
69
  PLATFORM_DEPLOY_WORKFLOW_RETRY_LIMIT,
@@ -1331,7 +1335,7 @@ async function markWorkflowRuntimeFailure(input: {
1331
1335
  } satisfies PlayRunLedgerEvent,
1332
1336
  ],
1333
1337
  });
1334
- const url = `${baseUrl.replace(/\/$/, '')}${PLAY_RUNTIME_API_COMPAT_PATH}`;
1338
+ const url = `${baseUrl.replace(/\/$/, '')}${PLAY_RUNTIME_API_CURRENT_PATH}`;
1335
1339
  const backoffMs = [200, 500, 1500];
1336
1340
  let lastError: unknown = null;
1337
1341
  for (let attempt = 0; attempt <= backoffMs.length; attempt += 1) {
@@ -1420,7 +1424,7 @@ async function appendWorkflowChildCompletedRunEvent(input: {
1420
1424
  } satisfies PlayRunLedgerEvent,
1421
1425
  ],
1422
1426
  });
1423
- const url = `${baseUrl.replace(/\/$/, '')}${PLAY_RUNTIME_API_COMPAT_PATH}`;
1427
+ const url = `${baseUrl.replace(/\/$/, '')}${PLAY_RUNTIME_API_CURRENT_PATH}`;
1424
1428
  const response = await fetch(url, { method: 'POST', headers, body });
1425
1429
  if (!response.ok) {
1426
1430
  throw new Error(
@@ -1840,7 +1844,7 @@ async function markRegisteredChildRunFailed(input: {
1840
1844
  contract: PLAY_RUNTIME_CONTRACT,
1841
1845
  executorToken: input.childExecutorToken,
1842
1846
  baseUrl: input.baseUrl,
1843
- path: PLAY_RUNTIME_API_COMPAT_PATH,
1847
+ path: PLAY_RUNTIME_API_CURRENT_PATH,
1844
1848
  headers: {
1845
1849
  'x-deepline-request-id': crypto.randomUUID(),
1846
1850
  [PLAY_RUNTIME_CONTRACT_HEADER]: String(PLAY_RUNTIME_CONTRACT),
@@ -1897,7 +1901,7 @@ async function appendRegisteredChildRunTerminal(input: {
1897
1901
  contract: PLAY_RUNTIME_CONTRACT,
1898
1902
  executorToken: input.childExecutorToken,
1899
1903
  baseUrl: input.baseUrl,
1900
- path: PLAY_RUNTIME_API_COMPAT_PATH,
1904
+ path: PLAY_RUNTIME_API_CURRENT_PATH,
1901
1905
  headers: {
1902
1906
  'x-deepline-request-id': crypto.randomUUID(),
1903
1907
  [PLAY_RUNTIME_CONTRACT_HEADER]: String(PLAY_RUNTIME_CONTRACT),
@@ -1979,7 +1983,7 @@ async function callRuntimeApiFromCoordinator(input: {
1979
1983
  contract: PLAY_RUNTIME_CONTRACT,
1980
1984
  executorToken: input.executorToken,
1981
1985
  baseUrl: input.baseUrl,
1982
- path: PLAY_RUNTIME_API_COMPAT_PATH,
1986
+ path: PLAY_RUNTIME_API_CURRENT_PATH,
1983
1987
  body,
1984
1988
  headers: {
1985
1989
  'x-deepline-request-id': requestId,
@@ -3118,7 +3122,8 @@ async function submitChildWorkflowThroughCoordinator(input: {
3118
3122
  * Workflows serializes the dynamic Worker's `env` map when it persists
3119
3123
  * workflow state. WorkerEntrypoint stubs ARE cloneable.
3120
3124
  *
3121
- * Path allowlist: only `/api/v2/plays/*` and `/api/v2/integrations/*`.
3125
+ * Path allowlist: the current runtime endpoint plus `/api/v2/plays/*` and
3126
+ * `/api/v2/integrations/*`.
3122
3127
  * Anything else is a sandbox-escape attempt and gets a loud 403 — the
3123
3128
  * coordinator must NOT proxy a play's request to internal admin routes
3124
3129
  * even if the play tries to construct such a URL.
@@ -3127,6 +3132,7 @@ export class RuntimeApi extends WorkerEntrypoint<CoordinatorEnv, undefined> {
3127
3132
  async fetch(request: Request): Promise<Response> {
3128
3133
  const incoming = new URL(request.url);
3129
3134
  const allowed =
3135
+ incoming.pathname === PLAY_RUNTIME_API_CURRENT_PATH ||
3130
3136
  incoming.pathname.startsWith('/api/v2/plays/') ||
3131
3137
  incoming.pathname.startsWith('/api/v2/integrations/');
3132
3138
  if (!allowed) {
@@ -3759,6 +3765,62 @@ const coordinatorEntrypoint = {
3759
3765
 
3760
3766
  export default coordinatorEntrypoint;
3761
3767
 
3768
+ const COORDINATOR_RUNTIME_PROXY_MAX_BODY_BYTES = 16 * 1024 * 1024;
3769
+
3770
+ async function proxyCoordinatorRuntimeApiRequest(input: {
3771
+ request: Request;
3772
+ env: CoordinatorEnv;
3773
+ url: URL;
3774
+ }): Promise<Response> {
3775
+ const { request, env, url } = input;
3776
+ if (request.method !== 'GET' && request.method !== 'POST') {
3777
+ return new Response('method not allowed', { status: 405 });
3778
+ }
3779
+ const executorToken = executorTokenFromAuthorizationHeader(
3780
+ request.headers.get('authorization'),
3781
+ );
3782
+ if (!executorToken) {
3783
+ return Response.json(
3784
+ { error: 'Runtime gateway requires a bearer executor token.' },
3785
+ { status: 401 },
3786
+ );
3787
+ }
3788
+ const contentLength = Number(request.headers.get('content-length') ?? '0');
3789
+ if (
3790
+ Number.isFinite(contentLength) &&
3791
+ contentLength > COORDINATOR_RUNTIME_PROXY_MAX_BODY_BYTES
3792
+ ) {
3793
+ return Response.json(
3794
+ { error: 'Runtime gateway request body exceeds the 16 MiB limit.' },
3795
+ { status: 413 },
3796
+ );
3797
+ }
3798
+ let body: unknown = {};
3799
+ if (request.method === 'POST') {
3800
+ try {
3801
+ body = await request.json();
3802
+ } catch {
3803
+ return Response.json(
3804
+ { error: 'Runtime gateway requires a JSON request body.' },
3805
+ { status: 400 },
3806
+ );
3807
+ }
3808
+ }
3809
+ const upstream = await env.HARNESS.runtimeApiCall({
3810
+ contract: PLAY_RUNTIME_CONTRACT,
3811
+ executorToken,
3812
+ method: request.method,
3813
+ path: `${url.pathname}${url.search}`,
3814
+ body,
3815
+ headers: Object.fromEntries(request.headers.entries()),
3816
+ });
3817
+ const headers = new Headers(upstream.headers);
3818
+ // The harness materializes the upstream response body as a string. Let this
3819
+ // Response calculate its own byte length instead of forwarding a stale one.
3820
+ headers.delete('content-length');
3821
+ return new Response(upstream.body, { status: upstream.status, headers });
3822
+ }
3823
+
3762
3824
  /**
3763
3825
  * Route dispatcher for the coordinator fetch handler. Extracted as a standalone
3764
3826
  * function so the outer {@link coordinatorEntrypoint.fetch} try/catch backstop
@@ -3787,6 +3849,19 @@ async function coordinatorRouteFetch(
3787
3849
  }
3788
3850
  return new Response('ok', { status: 200, headers });
3789
3851
  }
3852
+ if (isCoordinatorRuntimeProxyPath(url.pathname)) {
3853
+ try {
3854
+ return await proxyCoordinatorRuntimeApiRequest({ request, env, url });
3855
+ } catch (error) {
3856
+ return coordinatorRouteErrorResponse({
3857
+ logTag: '[coordinator.runtime_proxy.error]',
3858
+ code: 'COORDINATOR_RUNTIME_PROXY_FAILED',
3859
+ phase: 'coordinator.runtime_proxy',
3860
+ runId: null,
3861
+ error,
3862
+ });
3863
+ }
3864
+ }
3790
3865
  if (url.pathname === '/internal-token/probe') {
3791
3866
  const authError = authorizeCoordinatorControlRequest({ request, env });
3792
3867
  if (authError) return authError;
@@ -4035,7 +4110,7 @@ async function flushTailRunLogs(
4035
4110
  return;
4036
4111
  }
4037
4112
  await fetch(
4038
- `${env.DEEPLINE_API_BASE_URL}${PLAY_RUNTIME_TAIL_LOG_COMPAT_PATH}`,
4113
+ `${env.DEEPLINE_API_BASE_URL}${PLAY_RUNTIME_TAIL_LOG_CURRENT_PATH}`,
4039
4114
  {
4040
4115
  method: 'POST',
4041
4116
  headers: {
@@ -5455,7 +5530,7 @@ export class TenantWorkflow extends WorkflowEntrypoint {
5455
5530
  const runId = payload && typeof payload.runId === "string" ? payload.runId : "warmup";
5456
5531
  const startedAt = Date.now();
5457
5532
  if (this.env.RUNTIME_API) {
5458
- await this.env.RUNTIME_API.fetch(new Request("https://deepline.runtime.internal${PLAY_RUNTIME_API_COMPAT_PATH}", {
5533
+ await this.env.RUNTIME_API.fetch(new Request("https://deepline.runtime.internal${PLAY_RUNTIME_API_CURRENT_PATH}", {
5459
5534
  method: "POST",
5460
5535
  headers: { "content-type": "application/json" },
5461
5536
  body: "{}"
@@ -0,0 +1,34 @@
1
+ import {
2
+ PLAY_RUNTIME_API_CURRENT_PATH,
3
+ PLAY_RUNTIME_CHILD_EXECUTOR_TOKEN_CURRENT_PATH,
4
+ PLAY_RUNTIME_EGRESS_FETCH_CURRENT_PATH,
5
+ } from '../../../shared_libs/play-runtime/runtime-api-paths';
6
+
7
+ /**
8
+ * Paths a credential-isolated Daytona sandbox may send through the
9
+ * coordinator. The sandbox receives the coordinator as its runtime origin so
10
+ * it never holds the Vercel protection-bypass credential; the harness owns the
11
+ * protected upstream hop. Keep this deliberately narrower than the harness
12
+ * allowlist: a coordinator URL is public, while the harness is a service
13
+ * binding.
14
+ */
15
+ export function isCoordinatorRuntimeProxyPath(pathname: string): boolean {
16
+ return (
17
+ pathname === PLAY_RUNTIME_API_CURRENT_PATH ||
18
+ pathname === PLAY_RUNTIME_CHILD_EXECUTOR_TOKEN_CURRENT_PATH ||
19
+ pathname === PLAY_RUNTIME_EGRESS_FETCH_CURRENT_PATH ||
20
+ pathname === '/api/v2/plays/run' ||
21
+ /^\/api\/v2\/plays\/runtime-tools\/[^/]+(?:\/(?:auth-scope|event-wait))?$/.test(
22
+ pathname,
23
+ ) ||
24
+ /^\/api\/v2\/integrations\/[^/]+\/(?:execute|stream)$/.test(pathname)
25
+ );
26
+ }
27
+
28
+ export function executorTokenFromAuthorizationHeader(
29
+ authorization: string | null,
30
+ ): string | null {
31
+ const match = /^Bearer\s+(.+)$/i.exec(authorization?.trim() ?? '');
32
+ const token = match?.[1]?.trim();
33
+ return token || null;
34
+ }
@@ -67,6 +67,7 @@ import {
67
67
  type WorkflowStepLike,
68
68
  } from './child-play-await';
69
69
  import { submitChildPlayThroughCoordinator } from './child-play-submit';
70
+ import { createRunScopedChildManifestResolver } from './child-manifest-resolver';
70
71
  import { isRetryableWorkerRuntimeApiError } from './runtime-api-retry';
71
72
  import { formatCustomerConsoleValue } from './runtime/customer-console';
72
73
  import {
@@ -184,8 +185,8 @@ import {
184
185
  PLAY_RUNTIME_CONTRACT_HEADER,
185
186
  } from '../../../shared_libs/play-runtime/runtime-contract';
186
187
  import {
187
- PLAY_RUNTIME_API_COMPAT_PATH,
188
- PLAY_RUNTIME_EGRESS_FETCH_COMPAT_PATH,
188
+ PLAY_RUNTIME_API_CURRENT_PATH,
189
+ PLAY_RUNTIME_EGRESS_FETCH_CURRENT_PATH,
189
190
  } from '../../../shared_libs/play-runtime/runtime-api-paths';
190
191
  import { DYNAMIC_PLAY_WORKER_ARTIFACT_VERSION } from '../../../shared_libs/play-runtime/dynamic-worker-version';
191
192
  import {
@@ -859,7 +860,7 @@ async function fetchRuntimeApi(
859
860
  ? Math.max(1, Math.ceil(options.timeoutMsOverride))
860
861
  : path === '/api/v2/plays/run'
861
862
  ? RUNTIME_API_PLAY_RUN_TIMEOUT_MS
862
- : path === PLAY_RUNTIME_EGRESS_FETCH_COMPAT_PATH
863
+ : path === PLAY_RUNTIME_EGRESS_FETCH_CURRENT_PATH
863
864
  ? RUNTIME_API_EGRESS_FETCH_TIMEOUT_MS
864
865
  : /^\/api\/v2\/integrations\/[^/]+\/execute$/.test(path)
865
866
  ? RUNTIME_API_INTEGRATION_EXECUTE_TIMEOUT_MS
@@ -1315,7 +1316,7 @@ async function postRuntimeApi<T>(
1315
1316
  try {
1316
1317
  res = await fetchRuntimeApi(
1317
1318
  baseUrl,
1318
- PLAY_RUNTIME_API_COMPAT_PATH,
1319
+ PLAY_RUNTIME_API_CURRENT_PATH,
1319
1320
  {
1320
1321
  method: 'POST',
1321
1322
  headers: {
@@ -1619,15 +1620,7 @@ type RuntimeResolvedPlayResponse = {
1619
1620
  async function resolveAuthorizedWorkerChildManifest(input: {
1620
1621
  req: RunRequest;
1621
1622
  playRef: string;
1622
- cache: Map<string, PlayRuntimeManifest>;
1623
1623
  }): Promise<PlayRuntimeManifest | null> {
1624
- const cached = input.cache.get(input.playRef);
1625
- if (cached) return cached;
1626
- const preloaded = input.req.childPlayManifests?.[input.playRef];
1627
- if (preloaded) {
1628
- input.cache.set(input.playRef, preloaded);
1629
- return preloaded;
1630
- }
1631
1624
  const response = await postRuntimeApi<RuntimeResolvedPlayResponse>(
1632
1625
  input.req.baseUrl,
1633
1626
  input.req.executorToken,
@@ -1641,11 +1634,7 @@ async function resolveAuthorizedWorkerChildManifest(input: {
1641
1634
  timeoutMsOverride: 30_000,
1642
1635
  },
1643
1636
  );
1644
- const manifest = response.manifest ?? null;
1645
- if (manifest) {
1646
- input.cache.set(input.playRef, manifest);
1647
- }
1648
- return manifest;
1637
+ return response.manifest ?? null;
1649
1638
  }
1650
1639
 
1651
1640
  async function childPlayEventKey(input: {
@@ -2497,6 +2486,10 @@ function deserializeDurableStepValue<T>(value: T, depth = 0): T {
2497
2486
  ) as T;
2498
2487
  }
2499
2488
 
2489
+ function decodeLegacyWorkflowStepCheckpoint<T>(checkpoint: unknown): T {
2490
+ return deserializeDurableStepValue(checkpoint) as T;
2491
+ }
2492
+
2500
2493
  type WorkerStepResolver = (
2501
2494
  row: Record<string, unknown>,
2502
2495
  ctx: unknown,
@@ -2897,7 +2890,7 @@ async function postRuntimeEgressFetch(
2897
2890
  ) {
2898
2891
  const response = await fetchRuntimeApi(
2899
2892
  req.baseUrl,
2900
- PLAY_RUNTIME_EGRESS_FETCH_COMPAT_PATH,
2893
+ PLAY_RUNTIME_EGRESS_FETCH_CURRENT_PATH,
2901
2894
  {
2902
2895
  method: 'POST',
2903
2896
  headers: {
@@ -4258,14 +4251,19 @@ function createMinimalWorkerCtx(
4258
4251
  // lineage snapshot are owned by the Governor (createGovernorForRun above).
4259
4252
  // The worker keeps only substrate mechanism here.
4260
4253
  const stepCallCounts: Record<string, number> = {};
4261
- const childManifestCache = new Map<string, PlayRuntimeManifest>();
4254
+ const resolveChildManifest = createRunScopedChildManifestResolver({
4255
+ scopeKey: `${req.orgId}:${req.runId}:${req.runAttempt}`,
4256
+ preloaded: req.childPlayManifests,
4257
+ resolveManifest: (playRef) =>
4258
+ resolveAuthorizedWorkerChildManifest({ req, playRef }),
4259
+ });
4262
4260
  const secretRedactor = createSecretRedactionContext();
4263
4261
 
4264
4262
  const resolveSecretAuth = async (auth?: SecretAuth) => {
4265
4263
  if (!auth) return {};
4266
4264
  const response = await fetchRuntimeApi(
4267
4265
  req.baseUrl,
4268
- PLAY_RUNTIME_API_COMPAT_PATH,
4266
+ PLAY_RUNTIME_API_CURRENT_PATH,
4269
4267
  {
4270
4268
  method: 'POST',
4271
4269
  headers: {
@@ -4375,22 +4373,42 @@ function createMinimalWorkerCtx(
4375
4373
  });
4376
4374
  return deserializeDurableStepValue(serialized) as T;
4377
4375
  };
4378
- const executeWithWorkflowStep = async <T>(
4376
+ const executeWithDurableStepReceipt = async <T>(
4379
4377
  name: string,
4380
4378
  execute: () => Promise<T> | T,
4381
4379
  ): Promise<T> => {
4382
4380
  if (!workflowStep) {
4383
4381
  return await executeWithRuntimeReceipt(name, execute);
4384
4382
  }
4385
- return await executeWithRuntimeReceipt(name, async () => {
4386
- const serialized = await (
4387
- workflowStep.do as unknown as (
4388
- name: string,
4389
- callback: () => Promise<unknown>,
4390
- ) => Promise<unknown>
4391
- )(name, async () => serializeDurableStepValue(await execute()));
4392
- return deserializeDurableStepValue(serialized) as T;
4383
+ let liveValue: T | undefined;
4384
+ let executedLive = false;
4385
+ const checkpoint = await (
4386
+ workflowStep.do as unknown as (
4387
+ name: string,
4388
+ callback: () => Promise<{ receiptCompleted: true }>,
4389
+ ) => Promise<unknown>
4390
+ )(name, async () => {
4391
+ liveValue = await executeWithRuntimeReceipt(name, execute);
4392
+ executedLive = true;
4393
+ return { receiptCompleted: true };
4393
4394
  });
4395
+ if (executedLive) return liveValue as T;
4396
+ if (
4397
+ checkpoint !== null &&
4398
+ typeof checkpoint === 'object' &&
4399
+ !Array.isArray(checkpoint) &&
4400
+ (checkpoint as { receiptCompleted?: unknown }).receiptCompleted === true
4401
+ ) {
4402
+ return await executeWithRuntimeReceipt(name, () => {
4403
+ throw new Error(
4404
+ `Workflow step ${name} replayed without its completed runtime receipt.`,
4405
+ );
4406
+ });
4407
+ }
4408
+ // Runs started before runtime contract 3 checkpointed the full serialized
4409
+ // value in Cloudflare Workflow. Accept that legacy value only on replay;
4410
+ // new executions above always persist the compact receipt marker.
4411
+ return decodeLegacyWorkflowStepCheckpoint<T>(checkpoint);
4394
4412
  };
4395
4413
  const nextCtxStepReceiptKey = (
4396
4414
  name: string,
@@ -6694,7 +6712,7 @@ function createMinimalWorkerCtx(
6694
6712
  if (!normalizedName) {
6695
6713
  throw new Error('ctx.step(name, callback) requires a name.');
6696
6714
  }
6697
- return await executeWithWorkflowStep(
6715
+ return await executeWithDurableStepReceipt(
6698
6716
  nextCtxStepReceiptKey(normalizedName, options?.staleAfterSeconds),
6699
6717
  callback,
6700
6718
  );
@@ -6914,11 +6932,7 @@ function createMinimalWorkerCtx(
6914
6932
  if (!resolvedName) {
6915
6933
  throw new Error('ctx.runPlay(...) requires a resolvable play name.');
6916
6934
  }
6917
- const childManifest = await resolveAuthorizedWorkerChildManifest({
6918
- req,
6919
- playRef: resolvedName,
6920
- cache: childManifestCache,
6921
- });
6935
+ const childManifest = await resolveChildManifest(resolvedName);
6922
6936
  const rowScope = workerRunPlayRowContext.getStore();
6923
6937
  const invocationScope = buildDurableRunPlayInvocationScope({
6924
6938
  childPlayName: resolvedName,
@@ -8928,7 +8942,7 @@ export class TenantWorkflow extends WorkflowEntrypoint<
8928
8942
  try {
8929
8943
  const response = await fetchRuntimeApi(
8930
8944
  req.baseUrl,
8931
- PLAY_RUNTIME_API_COMPAT_PATH,
8945
+ PLAY_RUNTIME_API_CURRENT_PATH,
8932
8946
  {
8933
8947
  method: 'POST',
8934
8948
  headers: {
@@ -11,6 +11,7 @@ import {
11
11
  harnessReleaseRuntimeReceipt,
12
12
  } from '../../../../sdk/src/plays/harness-stub';
13
13
  import type { PreloadedRuntimeDbSessionInput } from '../../../play-harness-worker/src/rpc-types';
14
+ import { PLAY_RUNTIME_CONTRACT } from '../../../../shared_libs/play-runtime/runtime-contract';
14
15
  import type { WorkerRuntimeReceiptStore } from './receipts';
15
16
 
16
17
  const RUNTIME_TEST_FAULT_NAMES = new Set([
@@ -79,6 +80,7 @@ export function createHarnessWorkerReceiptStore(input: {
79
80
  ? Math.max(0, Math.floor(input.runAttempt))
80
81
  : null;
81
82
  const runAttemptField = runAttempt == null ? {} : { runAttempt };
83
+ const runtimeContractField = { contract: PLAY_RUNTIME_CONTRACT };
82
84
  const leaseTtlField =
83
85
  typeof input.receiptLeaseTtlMs === 'number' &&
84
86
  Number.isFinite(input.receiptLeaseTtlMs) &&
@@ -92,6 +94,7 @@ export function createHarnessWorkerReceiptStore(input: {
92
94
  getReceipt(command) {
93
95
  return harnessGetRuntimeReceipt({
94
96
  executorToken: input.executorToken,
97
+ ...runtimeContractField,
95
98
  orgId: input.orgId,
96
99
  preloadedDbSessions: input.preloadedDbSessions ?? null,
97
100
  userEmail: input.userEmail ?? null,
@@ -104,6 +107,7 @@ export function createHarnessWorkerReceiptStore(input: {
104
107
  claimReceipt(command) {
105
108
  return harnessClaimRuntimeReceipt({
106
109
  executorToken: input.executorToken,
110
+ ...runtimeContractField,
107
111
  orgId: input.orgId,
108
112
  preloadedDbSessions: input.preloadedDbSessions ?? null,
109
113
  userEmail: input.userEmail ?? null,
@@ -116,6 +120,7 @@ export function createHarnessWorkerReceiptStore(input: {
116
120
  claimReceipts(command) {
117
121
  return harnessClaimRuntimeReceipts({
118
122
  executorToken: input.executorToken,
123
+ ...runtimeContractField,
119
124
  orgId: input.orgId,
120
125
  preloadedDbSessions: input.preloadedDbSessions ?? null,
121
126
  userEmail: input.userEmail ?? null,
@@ -128,6 +133,7 @@ export function createHarnessWorkerReceiptStore(input: {
128
133
  markReceiptsRunning(command) {
129
134
  return harnessMarkRuntimeReceiptsRunning({
130
135
  executorToken: input.executorToken,
136
+ ...runtimeContractField,
131
137
  orgId: input.orgId,
132
138
  preloadedDbSessions: input.preloadedDbSessions ?? null,
133
139
  userEmail: input.userEmail ?? null,
@@ -143,6 +149,7 @@ export function createHarnessWorkerReceiptStore(input: {
143
149
  completeReceipt(command) {
144
150
  return harnessCompleteRuntimeReceipt({
145
151
  executorToken: input.executorToken,
152
+ ...runtimeContractField,
146
153
  orgId: input.orgId,
147
154
  preloadedDbSessions: input.preloadedDbSessions ?? null,
148
155
  userEmail: input.userEmail ?? null,
@@ -154,6 +161,7 @@ export function createHarnessWorkerReceiptStore(input: {
154
161
  completeReceipts(command) {
155
162
  return harnessCompleteRuntimeReceipts({
156
163
  executorToken: input.executorToken,
164
+ ...runtimeContractField,
157
165
  orgId: input.orgId,
158
166
  preloadedDbSessions: input.preloadedDbSessions ?? null,
159
167
  userEmail: input.userEmail ?? null,
@@ -168,6 +176,7 @@ export function createHarnessWorkerReceiptStore(input: {
168
176
  failReceipt(command) {
169
177
  return harnessFailRuntimeReceipt({
170
178
  executorToken: input.executorToken,
179
+ ...runtimeContractField,
171
180
  orgId: input.orgId,
172
181
  preloadedDbSessions: input.preloadedDbSessions ?? null,
173
182
  userEmail: input.userEmail ?? null,
@@ -179,6 +188,7 @@ export function createHarnessWorkerReceiptStore(input: {
179
188
  releaseReceipt(command) {
180
189
  return harnessReleaseRuntimeReceipt({
181
190
  executorToken: input.executorToken,
191
+ ...runtimeContractField,
182
192
  orgId: input.orgId,
183
193
  preloadedDbSessions: input.preloadedDbSessions ?? null,
184
194
  userEmail: input.userEmail ?? null,
@@ -190,6 +200,7 @@ export function createHarnessWorkerReceiptStore(input: {
190
200
  failReceipts(command) {
191
201
  return harnessFailRuntimeReceipts({
192
202
  executorToken: input.executorToken,
203
+ ...runtimeContractField,
193
204
  orgId: input.orgId,
194
205
  preloadedDbSessions: input.preloadedDbSessions ?? null,
195
206
  userEmail: input.userEmail ?? null,
@@ -204,6 +215,7 @@ export function createHarnessWorkerReceiptStore(input: {
204
215
  heartbeatReceipts(command) {
205
216
  return harnessHeartbeatRuntimeReceipts({
206
217
  executorToken: input.executorToken,
218
+ ...runtimeContractField,
207
219
  orgId: input.orgId,
208
220
  preloadedDbSessions: input.preloadedDbSessions ?? null,
209
221
  userEmail: input.userEmail ?? null,
@@ -19,6 +19,9 @@ function workflowRetryReasonForFailure(failure: {
19
19
  code: string;
20
20
  cause?: string;
21
21
  }): string {
22
+ if (failure.code === 'PLATFORM_WORKFLOW_ENDPOINT_INTERRUPTED') {
23
+ return 'cloudflare_workflow_endpoint_unavailable';
24
+ }
22
25
  if (failure.code === 'PLATFORM_WORKER_SUBREQUEST_INTERRUPTED') {
23
26
  return 'cloudflare_worker_subrequest_limit';
24
27
  }
@@ -51,6 +54,7 @@ export function decideWorkflowPlatformRetry(input: {
51
54
  const failure = normalizePlayRunFailure(input.error);
52
55
  const retryablePlatformReset =
53
56
  failure.code === 'PLATFORM_DEPLOY_INTERRUPTED' ||
57
+ failure.code === 'PLATFORM_WORKFLOW_ENDPOINT_INTERRUPTED' ||
54
58
  failure.code === 'PLATFORM_WORKER_SUBREQUEST_INTERRUPTED';
55
59
  if (
56
60
  retryablePlatformReset &&
@@ -1563,8 +1563,7 @@ export class DeeplineClient {
1563
1563
  ? { waitForCompletionMs: request.waitForCompletionMs }
1564
1564
  : {}),
1565
1565
  // Profile selection is the API's job, not the CLI's. The server
1566
- // defaults to absurd; callers that need workers_edge pass
1567
- // `request.profile` explicitly.
1566
+ // defaults to absurd; callers normally omit this field.
1568
1567
  ...(request.profile ? { profile: request.profile } : {}),
1569
1568
  ...(integrationMode ? { integrationMode } : {}),
1570
1569
  ...(testPolicyOverrides ? { testPolicyOverrides } : {}),
@@ -106,10 +106,10 @@ export const SDK_RELEASE = {
106
106
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
107
107
  // fields shipped in 0.1.153.
108
108
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
109
- version: '0.1.214',
109
+ version: '0.1.216',
110
110
  apiContract: '2026-06-dataset-handle-results-hard-cutover',
111
111
  supportPolicy: {
112
- latest: '0.1.214',
112
+ latest: '0.1.216',
113
113
  minimumSupported: '0.1.53',
114
114
  deprecatedBelow: '0.1.53',
115
115
  commandMinimumSupported: [
@@ -1138,9 +1138,8 @@ export interface StartPlayRunRequest {
1138
1138
  /** Optionally let the start request wait briefly and return a terminal result. */
1139
1139
  waitForCompletionMs?: number;
1140
1140
  /**
1141
- * Per-run execution profile override. The server defaults to absurd;
1142
- * callers that need workers_edge can pass it here. Most callers should leave
1143
- * this unset.
1141
+ * Per-run execution profile override. The server defaults to absurd. The
1142
+ * workers_edge profile is disabled; most callers should leave this unset.
1144
1143
  */
1145
1144
  profile?: string;
1146
1145
  /** Optional per-run provider execution mode for eval/smoke runs. */