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
@@ -62,13 +62,6 @@ import {
62
62
  pacingPolicyFromUnknownQueueHints,
63
63
  type ResolvedPacingPolicy,
64
64
  } from '../../../shared_libs/play-runtime/pacing';
65
- import {
66
- awaitChildTerminal,
67
- type ChildPlayTerminalWaitResult,
68
- type WorkflowStepLike,
69
- } from './child-play-await';
70
- import { submitChildPlayThroughCoordinator } from './child-play-submit';
71
- import { createRunScopedChildManifestResolver } from './child-manifest-resolver';
72
65
  import { isRetryableWorkerRuntimeApiError } from './runtime-api-retry';
73
66
  import { formatCustomerConsoleValue } from './runtime/customer-console';
74
67
  import {
@@ -91,12 +84,8 @@ import {
91
84
  createToolExecuteHttpFailureAttemptTracker,
92
85
  parseToolExecuteAuthScopeChangedError,
93
86
  } from '../../../shared_libs/play-runtime/tool-execute-retry-policy';
94
- import type { PlayCallGovernanceSnapshot } from '../../../shared_libs/play-runtime/scheduler-backend';
95
87
  import type { PreloadedRuntimeDbSession } from '../../../shared_libs/play-runtime/db-session';
96
- import type {
97
- PlayRuntimeManifest,
98
- PlayRuntimeManifestMap,
99
- } from '../../../shared_libs/plays/compiler-manifest';
88
+ import type { PlayRuntimeManifest } from '../../../shared_libs/plays/compiler-manifest';
100
89
  import {
101
90
  deriveToolRequestIdentity,
102
91
  derivePlayRowIdentity,
@@ -105,10 +94,7 @@ import {
105
94
  stableStringify,
106
95
  } from '../../../shared_libs/plays/row-identity';
107
96
  import { createDeferredPlayDataset } from '../../../shared_libs/plays/dataset';
108
- import {
109
- buildDurableCtxCallCacheKey,
110
- buildDurableRunPlayInvocationScope,
111
- } from '../../../shared_libs/play-runtime/durable-call-cache';
97
+ import { buildDurableCtxCallCacheKey } from '../../../shared_libs/play-runtime/durable-call-cache';
112
98
  import {
113
99
  resolveRuntimeToolReceiptWaitMaxAttempts,
114
100
  resolveRuntimeToolReceiptWaitTimeoutMs,
@@ -210,7 +196,6 @@ import {
210
196
  runtimeMapJsonByteLength,
211
197
  } from '../../../shared_libs/play-runtime/map-memory-limits';
212
198
  import { createSerialTaskQueue } from '../../../shared_libs/play-runtime/serial-task-queue';
213
- import { resolveChildExecutionPlacement as resolveChildExecutionStrategy } from '../../../shared_libs/play-runtime/child-execution-placement';
214
199
  // The harness stub forwards leaf calls (validation, runtime-api HTTP) into
215
200
  // the long-lived Play Harness Worker via env.HARNESS. We import the
216
201
  // `setHarnessBinding` setter eagerly so it's available the moment
@@ -423,10 +408,6 @@ type RunRequest = {
423
408
  contractSnapshot?: unknown;
424
409
  /** Deepline-owned compact execution plan. Public SDK/users never see this. */
425
410
  executionPlan?: ExecutionPlan | null;
426
- /** Trusted child play launch manifests carried by the top-level Vercel submit. */
427
- childPlayManifests?: PlayRuntimeManifestMap | null;
428
- /** Internal ctx.runPlay lineage. Public SDK/users never see this. */
429
- playCallGovernance?: PlayCallGovernanceSnapshot | null;
430
411
  preloadedDbSessions?: PreloadedRuntimeDbSession[] | null;
431
412
  /** Cloudflare coordinator URL for direct Workflow control-plane signals. */
432
413
  coordinatorUrl?: string | null;
@@ -639,41 +620,8 @@ type WorkerEnv = {
639
620
  body: string;
640
621
  }>;
641
622
  };
642
- /**
643
- * Loopback RPC binding into the coordinator Worker. Used for CF-to-CF
644
- * child orchestration so nested plays do not bounce through a public
645
- * coordinator URL when both caller and callee are already inside the same
646
- * Cloudflare Worker graph.
647
- */
623
+ /** Loopback RPC binding for runtime observability and rate coordination. */
648
624
  COORDINATOR?: {
649
- submitChild(
650
- parentRunId: string,
651
- body: Record<string, unknown>,
652
- ): Promise<{
653
- workflowId?: string;
654
- runId?: string;
655
- status?: string;
656
- mode?: string;
657
- output?: unknown;
658
- result?: unknown;
659
- error?: unknown;
660
- logs?: string[];
661
- timings?: Array<{ phase: string; ms: number }>;
662
- }>;
663
- submitWorkflowChild?(
664
- parentRunId: string,
665
- body: Record<string, unknown>,
666
- ): Promise<{
667
- workflowId?: string;
668
- runId?: string;
669
- status?: string;
670
- mode?: string;
671
- output?: unknown;
672
- result?: unknown;
673
- error?: unknown;
674
- logs?: string[];
675
- timings?: Array<{ phase: string; ms: number }>;
676
- }>;
677
625
  signal(
678
626
  runId: string,
679
627
  body: Record<string, unknown>,
@@ -687,11 +635,6 @@ type WorkerEnv = {
687
635
  event: Record<string, unknown>,
688
636
  ): Promise<void>;
689
637
  readTerminalState?(runId: string): Promise<Record<string, unknown> | null>;
690
- readChildTerminalState?(
691
- parentRunId: string,
692
- eventKey: string,
693
- timeoutMs?: number,
694
- ): Promise<Record<string, unknown> | null>;
695
638
  /**
696
639
  * Distributed Rate State Backend RPC. Routes to the per-(org,provider)
697
640
  * rate-bucket Durable Object so the request window is global across
@@ -1230,29 +1173,11 @@ async function drainRunnerPerfTraces(req: RunRequest): Promise<void> {
1230
1173
 
1231
1174
  let workerRequestSequence = 0;
1232
1175
 
1233
- const workerRunPlayRowContext = new AsyncLocalStorage<{
1234
- tableNamespace: string;
1235
- rowKey: string;
1236
- fieldName: string;
1237
- }>();
1238
-
1239
1176
  function makeRequestId(): string {
1240
1177
  workerRequestSequence = (workerRequestSequence + 1) % Number.MAX_SAFE_INTEGER;
1241
1178
  return `worker-request-${workerRequestSequence}`;
1242
1179
  }
1243
1180
 
1244
- async function executeFreshChildInvocation<T>(
1245
- input: {
1246
- parentRunId: string;
1247
- key: string;
1248
- invocationScope: string;
1249
- },
1250
- execute: (invocationId: string) => Promise<T>,
1251
- ): Promise<T> {
1252
- const invocationId = `${input.parentRunId}:runPlay:${input.key}:${input.invocationScope}`;
1253
- return await execute(invocationId);
1254
- }
1255
-
1256
1181
  function makeRuntimeSheetAttempt(input: {
1257
1182
  runId: string;
1258
1183
  runAttempt?: number | null;
@@ -1483,65 +1408,14 @@ async function postRuntimeApiBestEffort(
1483
1408
  }
1484
1409
  }
1485
1410
 
1486
- async function readDurableChildRunTerminalState(input: {
1487
- baseUrl: string;
1488
- executorToken: string;
1489
- parentRunId: string;
1490
- childRunId: string;
1491
- childPlayName: string;
1492
- timeoutMs?: number;
1493
- }): Promise<{ data?: unknown } | null> {
1494
- const response = await postRuntimeApi<{
1495
- state?: {
1496
- data?: unknown;
1497
- reason?: string;
1498
- status?: string;
1499
- runId?: string;
1500
- playName?: string;
1501
- parentRunId?: string | null;
1502
- } | null;
1503
- }>(
1504
- input.baseUrl,
1505
- input.executorToken,
1506
- {
1507
- action: 'read_child_run_terminal_snapshot',
1508
- parentRunId: input.parentRunId,
1509
- childRunId: input.childRunId,
1510
- childPlayName: input.childPlayName,
1511
- },
1512
- {
1513
- timeoutMsOverride: input.timeoutMs,
1514
- timeoutErrorMessage: `[play-harness] child run terminal snapshot read timed out after ${Math.max(
1515
- 1,
1516
- Math.ceil(input.timeoutMs ?? RUNTIME_API_TIMEOUT_MS),
1517
- )}ms. childRunId=${input.childRunId}`,
1518
- },
1519
- );
1520
- return response.state ?? null;
1521
- }
1522
-
1523
- function workflowEventType(name: string): string {
1524
- const normalized = name
1525
- .trim()
1526
- .replace(/[^A-Za-z0-9_-]+/g, '_')
1527
- .replace(/^_+|_+$/g, '')
1528
- .slice(0, 100);
1529
- return normalized || 'deepline_event';
1530
- }
1531
-
1532
- function normalizeContextKey(key: unknown, operation: string): string {
1533
- if (typeof key !== 'string' || !key.trim()) {
1534
- throw new Error(`ctx.${operation}(...) requires a non-empty key.`);
1535
- }
1536
- return key
1537
- .trim()
1538
- .replace(/[^A-Za-z0-9_.:-]+/g, '_')
1539
- .slice(0, 120);
1540
- }
1541
-
1542
1411
  function resolvePlayRefName(playRef: unknown): string {
1543
- if (typeof playRef === 'string') return playRef.trim();
1544
- if (typeof playRef === 'function') {
1412
+ if (typeof playRef === 'string' && playRef.trim()) {
1413
+ return playRef.trim();
1414
+ }
1415
+ if (
1416
+ playRef &&
1417
+ (typeof playRef === 'object' || typeof playRef === 'function')
1418
+ ) {
1545
1419
  const record = playRef as unknown as Record<string | symbol, unknown>;
1546
1420
  const playName = record.playName;
1547
1421
  if (typeof playName === 'string' && playName.trim()) return playName.trim();
@@ -1564,189 +1438,11 @@ function resolvePlayRefName(playRef: unknown): string {
1564
1438
  return '';
1565
1439
  }
1566
1440
 
1567
- function extractChildPlayOutput(status: Record<string, unknown>): unknown {
1568
- const result = status.result;
1569
- if (isRecord(result) && 'output' in result) {
1570
- return result.output;
1571
- }
1572
- return result ?? null;
1573
- }
1574
-
1575
- function hydrateChildPlayOutputDatasets(input: {
1576
- req: RunRequest;
1577
- childRunId: string;
1578
- childPlayName: string;
1579
- value: unknown;
1580
- }): unknown {
1581
- return hydrateSerializedResultDatasets(input.value, (dataset) => {
1582
- const tableNamespace = dataset.tableNamespace?.trim();
1583
- if (!tableNamespace) {
1584
- return dataset;
1585
- }
1586
- const count = Math.max(0, Math.floor(dataset.count));
1587
- const previewRows = dataset.preview.filter(isRecord);
1588
- return createPersistedDatasetHandle({
1589
- playName: input.childPlayName,
1590
- name: tableNamespace,
1591
- count,
1592
- datasetKind: dataset.datasetKind,
1593
- previewRows,
1594
- cachedRows: count <= previewRows.length ? previewRows : null,
1595
- sourceLabel: dataset.sourceLabel ?? null,
1596
- readRows: async ({ limit, offset }) => {
1597
- const result = await harnessReadSheetDatasetRows({
1598
- baseUrl: input.req.baseUrl,
1599
- executorToken: input.req.executorToken,
1600
- orgId: input.req.orgId,
1601
- playName: input.childPlayName,
1602
- tableNamespace,
1603
- runId: input.childRunId,
1604
- limit,
1605
- offset,
1606
- userEmail: input.req.userEmail,
1607
- preloadedDbSessions: input.req.preloadedDbSessions ?? null,
1608
- });
1609
- return result.rows as Array<Record<string, unknown>>;
1610
- },
1611
- trace: (phase, ms, extra) =>
1612
- recordRunnerPerfTrace({
1613
- req: input.req,
1614
- phase,
1615
- ms,
1616
- extra: {
1617
- ...(extra ?? {}),
1618
- childRunId: input.childRunId,
1619
- childPlayName: input.childPlayName,
1620
- },
1621
- }),
1622
- nowMs,
1623
- workProgress: dataset._metadata?.workProgress,
1624
- });
1625
- });
1626
- }
1627
-
1628
- async function hashChildPlayEventKey(input: unknown): Promise<string> {
1629
- return (await hashJson(input)).slice(0, 32);
1630
- }
1631
-
1632
- type RuntimeResolvedPlayResponse = {
1633
- manifest?: PlayRuntimeManifest | null;
1634
- };
1635
-
1636
- async function resolveAuthorizedWorkerChildManifest(input: {
1637
- req: RunRequest;
1638
- playRef: string;
1639
- }): Promise<PlayRuntimeManifest | null> {
1640
- const response = await postRuntimeApi<RuntimeResolvedPlayResponse>(
1641
- input.req.baseUrl,
1642
- input.req.executorToken,
1643
- {
1644
- action: 'resolve_play',
1645
- playRef: input.playRef,
1646
- artifactKind: 'esm_workers',
1647
- },
1648
- {
1649
- runtimeTestFaultHeader: input.req.runtimeTestFaultHeader,
1650
- timeoutMsOverride: 30_000,
1651
- },
1652
- );
1653
- return response.manifest ?? null;
1654
- }
1655
-
1656
- async function childPlayEventKey(input: {
1657
- key: string;
1658
- workflowId: string;
1659
- }): Promise<string> {
1660
- const readableKey = workflowEventType(input.key).slice(0, 40);
1661
- const digest = await hashChildPlayEventKey({
1662
- key: input.key,
1663
- workflowId: input.workflowId,
1664
- });
1665
- return `child_play_${digest}_${readableKey}`;
1666
- }
1667
-
1668
1441
  function workflowTimeoutFromMs(timeoutMs: number): string {
1669
1442
  const seconds = Math.max(1, Math.ceil(timeoutMs / 1000));
1670
1443
  return `${seconds} second${seconds === 1 ? '' : 's'}`;
1671
1444
  }
1672
1445
 
1673
- async function signalParentPlayTerminal(input: {
1674
- req: RunRequest;
1675
- status: 'completed' | 'failed' | 'cancelled';
1676
- result?: unknown;
1677
- error?: string | null;
1678
- }): Promise<void> {
1679
- const governance = input.req.playCallGovernance;
1680
- if (!governance?.parentRunId || !governance.key) return;
1681
- const eventKey = await childPlayEventKey({
1682
- key: governance.key,
1683
- workflowId: input.req.runId,
1684
- });
1685
- const data = {
1686
- type: 'play.child.terminal',
1687
- parentRunId: governance.parentRunId,
1688
- childRunId: input.req.runId,
1689
- playName: input.req.playName,
1690
- key: governance.key,
1691
- status: input.status,
1692
- ...(input.result !== undefined ? { result: input.result } : {}),
1693
- ...(input.error
1694
- ? {
1695
- error: {
1696
- code:
1697
- input.status === 'cancelled' ? 'CHILD_CANCELLED' : 'CHILD_FAILED',
1698
- message: input.error,
1699
- phase: 'child_terminal',
1700
- runId: input.req.runId,
1701
- parentRunId: governance.parentRunId,
1702
- childRunId: input.req.runId,
1703
- },
1704
- }
1705
- : {}),
1706
- emittedAt: nowMs(),
1707
- };
1708
- const signalBody = {
1709
- signal: 'integration_event',
1710
- eventKey,
1711
- data,
1712
- };
1713
- if (cachedCoordinatorBinding) {
1714
- await cachedCoordinatorBinding.signal(governance.parentRunId, signalBody);
1715
- return;
1716
- }
1717
- const coordinatorUrl = input.req.coordinatorUrl?.trim();
1718
- if (coordinatorUrl) {
1719
- const res = await fetch(
1720
- `${coordinatorUrl.replace(/\/$/, '')}/workflow/${encodeURIComponent(
1721
- governance.parentRunId,
1722
- )}/signal`,
1723
- {
1724
- method: 'POST',
1725
- headers: {
1726
- 'x-deepline-request-id': makeRequestId(),
1727
- ...coordinatorRequestHeaders({
1728
- runId: governance.parentRunId,
1729
- contentType: 'application/json',
1730
- internalToken: input.req.coordinatorInternalToken,
1731
- }),
1732
- },
1733
- body: JSON.stringify(signalBody),
1734
- },
1735
- );
1736
- if (res.ok) {
1737
- return;
1738
- }
1739
- const text = await res.text().catch(() => '');
1740
- throw new Error(
1741
- text.slice(0, 800) ||
1742
- `Coordinator parent signal failed with ${res.status}.`,
1743
- );
1744
- }
1745
- throw new Error(
1746
- 'Child play terminal signaling requires a coordinator binding in the cf-workflows runtime.',
1747
- );
1748
- }
1749
-
1750
1446
  async function executeTool(
1751
1447
  req: RunRequest,
1752
1448
  args: {
@@ -1880,6 +1576,25 @@ function normalizeToolExecuteArgs(request: unknown): {
1880
1576
  };
1881
1577
  }
1882
1578
 
1579
+ function workflowEventType(name: string): string {
1580
+ const normalized = name
1581
+ .trim()
1582
+ .replace(/[^A-Za-z0-9_-]+/g, '_')
1583
+ .replace(/^_+|_+$/g, '')
1584
+ .slice(0, 100);
1585
+ return normalized || 'deepline_event';
1586
+ }
1587
+
1588
+ function normalizeContextKey(key: unknown, operation: string): string {
1589
+ if (typeof key !== 'string' || !key.trim()) {
1590
+ throw new Error(`ctx.${operation}(...) requires a non-empty key.`);
1591
+ }
1592
+ return key
1593
+ .trim()
1594
+ .replace(/[^A-Za-z0-9_.:-]+/g, '_')
1595
+ .slice(0, 120);
1596
+ }
1597
+
1883
1598
  function integrationEventType(eventKey: string): string {
1884
1599
  return workflowEventType(`integration_event_${eventKey}`);
1885
1600
  }
@@ -3938,34 +3653,6 @@ function formatWorkerRowFailureMessage(error: unknown): string {
3938
3653
  return message.length > 1_000 ? `${message.slice(0, 1_000)}…` : message;
3939
3654
  }
3940
3655
 
3941
- function childPipelineUsesCtxDataset(
3942
- pipeline: PlayStaticPipeline | null | undefined,
3943
- ): boolean {
3944
- if (!pipeline) return false;
3945
- if (typeof pipeline.tableNamespace === 'string' && pipeline.tableNamespace) {
3946
- return true;
3947
- }
3948
- if (pipeline.sheetContract) {
3949
- return true;
3950
- }
3951
- return flattenStaticPipeline(pipeline).some((substep) => {
3952
- if (substep.type === 'dataset') return true;
3953
- if (!isRecord(substep)) return false;
3954
- return (
3955
- ('tableNamespace' in substep &&
3956
- typeof substep.tableNamespace === 'string' &&
3957
- substep.tableNamespace.length > 0) ||
3958
- ('sheetContract' in substep && Boolean(substep.sheetContract))
3959
- );
3960
- });
3961
- }
3962
-
3963
- /**
3964
- * Build the per-(org,provider) rate port the distributed Rate State Backend
3965
- * RPCs through. When the coordinator binding (or its rate RPCs) is absent we
3966
- * fail OPEN — grant immediately — matching customer-rate-limiter semantics so a
3967
- * miswired binding degrades pacing without stalling the run.
3968
- */
3969
3656
  function createCoordinatorRatePort(req: RunRequest): CoordinatorRatePort {
3970
3657
  return {
3971
3658
  async rateAcquire(input) {
@@ -4179,46 +3866,20 @@ function createWorkerPacingResolver(req: RunRequest): WorkerPacingResolver {
4179
3866
  }
4180
3867
 
4181
3868
  /**
4182
- * Build the Governor's lineage snapshot for this worker, seeded from the
4183
- * inherited PlayCallGovernanceSnapshot (threaded via internalRunPlay) so play-
4184
- * call budgets accumulate down the dispatch tree across isolates. The current
4185
- * play id is always `req.playName` so the per-parent child-call counter keys off
4186
- * the executing play (matching the prior worker behavior). Per-run counters the
4187
- * worker lineage does not carry (tool/retry/descendant/waterfall) seed at 0 —
4188
- * these are runaway guards, not exact cross-isolate ledgers, so a per-worker
4189
- * reset is acceptable and matches the Governor contract.
3869
+ * The retired workers-edge runtime has no child-run scheduling. Its Governor
3870
+ * therefore starts from this top-level run only.
4190
3871
  */
4191
3872
  function resumeGovernanceFromRequest(req: RunRequest): GovernanceSnapshot {
4192
- const inherited = req.playCallGovernance;
4193
- const rootRunId = inherited?.rootRunId || req.runId;
4194
- const ancestryPlayIds = inherited?.ancestryPlayIds?.length
4195
- ? // Per the lineage validator the inherited tail equals the parent; ensure
4196
- // the chain ends with the currently-executing play for the cycle guard.
4197
- inherited.ancestryPlayIds[inherited.ancestryPlayIds.length - 1] ===
4198
- req.playName
4199
- ? [...inherited.ancestryPlayIds]
4200
- : [...inherited.ancestryPlayIds, req.playName]
4201
- : [req.playName];
4202
- const ancestryRunIds =
4203
- rootRunId === req.runId ? [req.runId] : [rootRunId, req.runId];
4204
3873
  return {
4205
- rootRunId,
3874
+ rootRunId: req.runId,
4206
3875
  currentRunId: req.runId,
4207
3876
  currentPlayId: req.playName,
4208
- ancestryPlayIds,
4209
- ancestryRunIds,
4210
- callDepth: inherited?.callDepth ?? 0,
4211
- // Seed every lineage-global budget counter from the inherited snapshot so
4212
- // descendant/tool/retry/waterfall budgets accumulate across isolates exactly
4213
- // as they do across the cjs forkChild lineage. Without this they would reset
4214
- // to 0 in each isolate and become per-worker — contradicting the Governor's
4215
- // lineage-global budget contract. Fail-safe to 0 for older callers.
4216
- playCallCount: inherited?.playCallCount ?? 0,
4217
- toolCallCount: inherited?.toolCallCount ?? 0,
4218
- retryCount: inherited?.retryCount ?? 0,
4219
- descendantCount: inherited?.descendantCount ?? 0,
4220
- waterfallStepExecutions: inherited?.waterfallStepExecutions ?? 0,
4221
- parentChildCalls: {},
3877
+ ancestryPlayIds: [req.playName],
3878
+ ancestryRunIds: [req.runId],
3879
+ callDepth: 0,
3880
+ toolCallCount: 0,
3881
+ retryCount: 0,
3882
+ waterfallStepExecutions: 0,
4222
3883
  };
4223
3884
  }
4224
3885
 
@@ -4231,7 +3892,7 @@ function createGovernorForRun(req: RunRequest): {
4231
3892
  adapter: 'esm_workers',
4232
3893
  scope: {
4233
3894
  orgId: req.orgId,
4234
- rootRunId: req.playCallGovernance?.rootRunId ?? req.runId,
3895
+ rootRunId: req.runId,
4235
3896
  },
4236
3897
  rateState: new CoordinatorRateStateBackend(createCoordinatorRatePort(req)),
4237
3898
  budgetState: new BlockReservingBudgetStateBackend(
@@ -4259,7 +3920,7 @@ function createGovernorForRun(req: RunRequest): {
4259
3920
  * - ctx.csv(filename | inline rows) (calls runtime API for file resolve)
4260
3921
  * - ctx.dataset(name, rows).withColumn(name, resolver).run(opts)
4261
3922
  * - ctx.tools.execute({ id, tool, input, ... })
4262
- * - ctx.runPlay(key, playRef, input, opts)
3923
+ * - ctx.runPlay(...), which rejects with CTX_RUN_PLAY_INLINE_ONLY
4263
3924
  *
4264
3925
  * Not supported (will throw):
4265
3926
  * - ctx.fetch, checkpoints, etc.
@@ -4289,16 +3950,7 @@ function createMinimalWorkerCtx(
4289
3950
  createWorkerToolActionCacheVersionResolver(req);
4290
3951
  const resolveToolAuthScopeDigest =
4291
3952
  createWorkerToolAuthScopeDigestResolver(req);
4292
- // Play-call depth/count/per-parent budgets, child-play concurrency, and the
4293
- // lineage snapshot are owned by the Governor (createGovernorForRun above).
4294
- // The worker keeps only substrate mechanism here.
4295
3953
  const stepCallCounts: Record<string, number> = {};
4296
- const resolveChildManifest = createRunScopedChildManifestResolver({
4297
- scopeKey: `${req.orgId}:${req.runId}:${req.runAttempt}`,
4298
- preloaded: req.childPlayManifests,
4299
- resolveManifest: (playRef) =>
4300
- resolveAuthorizedWorkerChildManifest({ req, playRef }),
4301
- });
4302
3954
  const secretRedactor = createSecretRedactionContext();
4303
3955
 
4304
3956
  const resolveSecretAuth = async (auth?: SecretAuth) => {
@@ -4337,8 +3989,6 @@ function createMinimalWorkerCtx(
4337
3989
  : { [auth.header.toLowerCase()]: value };
4338
3990
  };
4339
3991
 
4340
- const rootGovernance = req.playCallGovernance;
4341
- const rootRunId = rootGovernance?.rootRunId ?? req.runId;
4342
3992
  const receiptStore = createHarnessWorkerReceiptStore({
4343
3993
  executorToken: req.executorToken,
4344
3994
  orgId: req.orgId,
@@ -4515,23 +4165,6 @@ function createMinimalWorkerCtx(
4515
4165
  persistenceLatch: rootPersistenceLatch,
4516
4166
  receiptSalvage,
4517
4167
  });
4518
- // Local ancestry chain that always ENDS with the currently-executing play
4519
- // (req.playName). The /api/v2/plays/run lineage validator requires the
4520
- // submitted ancestry's tail to equal the executor token's play name (i.e.
4521
- // the caller). Normalizing here keeps both the cycle-detection check below
4522
- // and the runPlay submission honest: at root we start with [req.playName],
4523
- // and for nested calls we append req.playName onto the parent-supplied
4524
- // chain (which per contract ends with the parent that submitted us).
4525
- const ancestryPlayIds = ((): string[] => {
4526
- if (!rootGovernance?.ancestryPlayIds?.length) {
4527
- return [req.playName];
4528
- }
4529
- const inherited = rootGovernance.ancestryPlayIds;
4530
- return inherited[inherited.length - 1] === req.playName
4531
- ? inherited
4532
- : [...inherited, req.playName];
4533
- })();
4534
- const callDepth = rootGovernance?.callDepth ?? 0;
4535
4168
  const runMap = async <T extends Record<string, unknown>>(
4536
4169
  name: string,
4537
4170
  rows: WorkerDatasetInput<T>,
@@ -5595,49 +5228,37 @@ function createMinimalWorkerCtx(
5595
5228
  })
5596
5229
  : null,
5597
5230
  });
5598
- const resolved = await workerRunPlayRowContext.run(
5599
- {
5600
- tableNamespace: name,
5601
- rowKey: entry.rowKey,
5602
- fieldName: key,
5603
- },
5604
- () =>
5605
- executeWorkerStepResolver(
5606
- value,
5607
- enriched,
5608
- rowCtx,
5609
- absoluteIndex,
5610
- previousCell,
5611
- isWorkerStepProgram(value)
5612
- ? {
5613
- parentField: key,
5614
- path: [],
5615
- outputs: stepProgramOutputs,
5616
- onOutput: async (stepOutput) => {
5617
- generatedOutputFields.add(
5618
- stepOutput.columnName,
5619
- );
5620
- const status =
5621
- stepOutput.status ?? 'completed';
5622
- if (status === 'skipped')
5623
- stepCellsSkipped += 1;
5624
- else stepCellsCompleted += 1;
5625
- await enqueueLiveRowUpdate({
5626
- key: entry.rowKey,
5627
- dataPatch: {
5628
- [stepOutput.columnName]: stepOutput.value,
5629
- },
5630
- cellMetaPatch: {
5631
- [stepOutput.columnName]: {
5632
- status,
5633
- stage: stepOutput.stepId,
5634
- },
5635
- },
5636
- });
5231
+ const resolved = await executeWorkerStepResolver(
5232
+ value,
5233
+ enriched,
5234
+ rowCtx,
5235
+ absoluteIndex,
5236
+ previousCell,
5237
+ isWorkerStepProgram(value)
5238
+ ? {
5239
+ parentField: key,
5240
+ path: [],
5241
+ outputs: stepProgramOutputs,
5242
+ onOutput: async (stepOutput) => {
5243
+ generatedOutputFields.add(stepOutput.columnName);
5244
+ const status = stepOutput.status ?? 'completed';
5245
+ if (status === 'skipped') stepCellsSkipped += 1;
5246
+ else stepCellsCompleted += 1;
5247
+ await enqueueLiveRowUpdate({
5248
+ key: entry.rowKey,
5249
+ dataPatch: {
5250
+ [stepOutput.columnName]: stepOutput.value,
5251
+ },
5252
+ cellMetaPatch: {
5253
+ [stepOutput.columnName]: {
5254
+ status,
5255
+ stage: stepOutput.stepId,
5256
+ },
5637
5257
  },
5638
- }
5639
- : undefined,
5640
- ),
5258
+ });
5259
+ },
5260
+ }
5261
+ : undefined,
5641
5262
  );
5642
5263
  enriched[key] = resolved.value;
5643
5264
  fieldOutputs[key] = resolved.value;
@@ -6971,438 +6592,20 @@ function createMinimalWorkerCtx(
6971
6592
  key: string,
6972
6593
  playRef: string | { playName?: string; name?: string },
6973
6594
  input: Record<string, unknown>,
6974
- options?: {
6595
+ _options?: {
6975
6596
  description?: string;
6976
6597
  timeoutMs?: number;
6977
6598
  execution?: 'inline' | 'child-workflow';
6978
6599
  },
6979
6600
  ): Promise<unknown> {
6980
- const normalizedKey = normalizeContextKey(key, 'runPlay');
6981
- const resolvedName = resolvePlayRefName(playRef);
6601
+ normalizeContextKey(key, 'runPlay');
6982
6602
  assertNoSecretTaint(input, 'ctx.runPlay input');
6603
+ const resolvedName = resolvePlayRefName(playRef);
6983
6604
  if (!resolvedName) {
6984
6605
  throw new Error('ctx.runPlay(...) requires a resolvable play name.');
6985
6606
  }
6986
- const childManifest = await resolveChildManifest(resolvedName);
6987
- const rowScope = workerRunPlayRowContext.getStore();
6988
- const invocationScope = buildDurableRunPlayInvocationScope({
6989
- childPlayName: resolvedName,
6990
- input,
6991
- rowScope: rowScope
6992
- ? {
6993
- fieldName: rowScope.fieldName,
6994
- rowKey: rowScope.rowKey,
6995
- tableNamespace: rowScope.tableNamespace,
6996
- }
6997
- : null,
6998
- });
6999
- return await executeFreshChildInvocation(
7000
- {
7001
- parentRunId: req.runId,
7002
- key: normalizedKey,
7003
- invocationScope,
7004
- },
7005
- async (childInvocationId) => {
7006
- // The Governor owns the play-call lineage: forkChild does the cycle
7007
- // guard, depth/per-parent/playCall/descendant budget charges, and
7008
- // returns the snapshot to thread into the child so budgets accumulate
7009
- // across isolates. Every ctx.runPlay call is a fresh child invocation.
7010
- const childRunId = `${req.runId}:child:${childInvocationId}`;
7011
- // Checkpoint governance admission separately from the child result.
7012
- // Workflow replay reuses this admission and the coordinator's stable
7013
- // child launch identity, but ctx.runPlay never caches child output.
7014
- const forkChild = () =>
7015
- governor.forkChild({
7016
- childPlayName: resolvedName,
7017
- childRunId,
7018
- });
7019
- const childGovernance = workflowStep
7020
- ? await (
7021
- workflowStep.do as unknown as <T>(
7022
- name: string,
7023
- callback: () => Promise<T>,
7024
- ) => Promise<T>
7025
- )(
7026
- `runPlay-governance:${sha256Hex(childInvocationId).slice(0, 24)}`,
7027
- forkChild,
7028
- )
7029
- : await forkChild();
7030
- const nextDepth = childGovernance.callDepth;
7031
- const nextParentCalls =
7032
- governor.snapshot().parentChildCalls[req.playName] ?? 0;
7033
-
7034
- emitEvent({
7035
- type: 'log',
7036
- level: 'info',
7037
- message: `Starting child play ${resolvedName} (${normalizedKey})`,
7038
- ts: nowMs(),
7039
- });
7040
- if (!childManifest) {
7041
- throw new Error(
7042
- `ctx.runPlay(${normalizedKey}) cannot start ${resolvedName}: not callable.`,
7043
- );
7044
- }
7045
- const childIsDatasetBacked = childPipelineUsesCtxDataset(
7046
- childManifest.staticPipeline,
7047
- );
7048
- const childWaitsForEvent = (
7049
- childManifest.staticPipeline
7050
- ? flattenStaticPipeline(childManifest.staticPipeline)
7051
- : []
7052
- ).some(
7053
- (step) =>
7054
- step.type === 'tool' &&
7055
- (step.isEventWait || step.toolId === 'test_wait_for_event'),
7056
- );
7057
- const authoredWorkflow =
7058
- options?.timeoutMs != null ||
7059
- childIsDatasetBacked ||
7060
- childWaitsForEvent;
7061
- if (options?.execution === 'inline' && authoredWorkflow) {
7062
- throw new Error(
7063
- `ctx.runPlay("${resolvedName}") requested inline execution for a child that requires a workflow.`,
7064
- );
7065
- }
7066
- const childExecutionDecision = resolveChildExecutionStrategy({
7067
- requiresWorkflow: authoredWorkflow,
7068
- execution: options?.execution,
7069
- });
7070
- const childNeedsWorkflowScheduler =
7071
- childExecutionDecision.strategy === 'scheduled';
7072
- if (rowScope && childNeedsWorkflowScheduler) {
7073
- throw new Error(
7074
- `ctx.runPlay("${resolvedName}") cannot start a child workflow per dataset row.`,
7075
- );
7076
- }
7077
- recordRunnerOperationalSpan(req, {
7078
- event: 'play.runtime.span',
7079
- phase: 'child_route',
7080
- runId: req.runId,
7081
- parentRunId: req.runId,
7082
- playName: resolvedName,
7083
- graphHash: req.graphHash ?? null,
7084
- depth: nextDepth,
7085
- fanoutIndex: nextParentCalls - 1,
7086
- childIsDatasetBacked,
7087
- childNeedsWorkflowScheduler,
7088
- hasStaticPipeline: Boolean(childManifest.staticPipeline),
7089
- childTableNamespace:
7090
- typeof childManifest.staticPipeline?.tableNamespace === 'string'
7091
- ? childManifest.staticPipeline.tableNamespace
7092
- : null,
7093
- childStageCount: Array.isArray(childManifest.staticPipeline?.stages)
7094
- ? childManifest.staticPipeline.stages.length
7095
- : null,
7096
- childSubstepCount: Array.isArray(
7097
- childManifest.staticPipeline?.substeps,
7098
- )
7099
- ? childManifest.staticPipeline.substeps.length
7100
- : null,
7101
- });
7102
- let childPlaySlot: { release(): void } | null = null;
7103
- try {
7104
- childPlaySlot = await governor.acquireChildSubmitSlot({
7105
- signal: abortSignal,
7106
- });
7107
- const childSubmitStartedAt = nowMs();
7108
- let started: {
7109
- workflowId?: string;
7110
- runId?: string;
7111
- status?: string;
7112
- mode?: string;
7113
- output?: unknown;
7114
- result?: unknown;
7115
- error?: unknown;
7116
- logs?: string[];
7117
- timings?: Array<{ phase: string; ms: number }>;
7118
- };
7119
- try {
7120
- started = await submitChildPlayThroughCoordinator({
7121
- req,
7122
- coordinatorBinding: cachedCoordinatorBinding,
7123
- makeRequestId,
7124
- coordinatorRequestHeaders,
7125
- allowInline: childExecutionDecision.strategy === 'inline',
7126
- body: {
7127
- name: resolvedName,
7128
- childIdempotencyKey: childInvocationId,
7129
- input: isRecord(input) ? input : {},
7130
- orgId: req.orgId,
7131
- callbackUrl: req.callbackUrl,
7132
- baseUrl: req.baseUrl,
7133
- integrationMode: req.integrationMode ?? null,
7134
- parentExecutorToken: req.executorToken,
7135
- userEmail: req.userEmail ?? '',
7136
- profile: 'workers_edge',
7137
- manifest: childManifest,
7138
- childPlayManifests: req.childPlayManifests ?? null,
7139
- internalRunPlay: {
7140
- rootRunId,
7141
- parentRunId: req.runId,
7142
- parentPlayName: req.playName,
7143
- key: normalizedKey,
7144
- // Per the lineage validator: ancestry tail must equal the
7145
- // executor token's play name (the parent making this call).
7146
- ancestryPlayIds,
7147
- callDepth: nextDepth,
7148
- // Cumulative lineage-global budget counters (incl. this
7149
- // launch's play/descendant charges) so the child seeds its
7150
- // budgets from the lineage total instead of resetting to 0 in
7151
- // its isolate. Threading descendantCount in particular keeps
7152
- // fan-out descendant accounting lineage-global, matching cjs.
7153
- playCallCount: childGovernance.playCallCount,
7154
- toolCallCount: childGovernance.toolCallCount,
7155
- retryCount: childGovernance.retryCount,
7156
- descendantCount: childGovernance.descendantCount,
7157
- waterfallStepExecutions:
7158
- childGovernance.waterfallStepExecutions,
7159
- description:
7160
- typeof options?.description === 'string'
7161
- ? options.description
7162
- : null,
7163
- },
7164
- },
7165
- });
7166
- } catch (error) {
7167
- recordRunnerOperationalSpan(req, {
7168
- event: 'play.runtime.span',
7169
- phase: 'child_submit',
7170
- runId: req.runId,
7171
- parentRunId: req.runId,
7172
- playName: resolvedName,
7173
- graphHash: req.graphHash ?? null,
7174
- depth: nextDepth,
7175
- fanoutIndex: nextParentCalls - 1,
7176
- ms: nowMs() - childSubmitStartedAt,
7177
- status: 'failed',
7178
- errorCode: 'CHILD_SUBMIT_FAILED',
7179
- });
7180
- recordRunnerPerfTrace({
7181
- req,
7182
- phase: 'ctx_run_play.child_submit',
7183
- ms: nowMs() - childSubmitStartedAt,
7184
- extra: {
7185
- status: 'failed',
7186
- errorCode: 'CHILD_SUBMIT_FAILED',
7187
- playName: resolvedName,
7188
- key: normalizedKey,
7189
- depth: nextDepth,
7190
- fanoutIndex: nextParentCalls - 1,
7191
- childIsDatasetBacked,
7192
- childNeedsWorkflowScheduler,
7193
- },
7194
- });
7195
- throw error;
7196
- }
7197
- const workflowId = started.workflowId ?? started.runId;
7198
- if (!workflowId) {
7199
- const startedError = isRecord(started.error)
7200
- ? started.error
7201
- : { message: started.error };
7202
- const startedErrorMessage =
7203
- typeof startedError.message === 'string' &&
7204
- startedError.message.trim()
7205
- ? startedError.message.trim()
7206
- : null;
7207
- throw new Error(
7208
- startedErrorMessage ??
7209
- `ctx.runPlay(${normalizedKey}) did not receive a child workflow id.`,
7210
- );
7211
- }
7212
- recordRunnerOperationalSpan(req, {
7213
- event: 'play.runtime.span',
7214
- phase: 'child_submit',
7215
- runId: req.runId,
7216
- parentRunId: req.runId,
7217
- childRunId: workflowId,
7218
- playName: resolvedName,
7219
- graphHash: req.graphHash ?? null,
7220
- depth: nextDepth,
7221
- fanoutIndex: nextParentCalls - 1,
7222
- ms: nowMs() - childSubmitStartedAt,
7223
- status: 'ok',
7224
- });
7225
- recordRunnerPerfTrace({
7226
- req,
7227
- phase: 'ctx_run_play.child_submit',
7228
- ms: nowMs() - childSubmitStartedAt,
7229
- extra: {
7230
- status: 'ok',
7231
- childRunId: workflowId,
7232
- startedStatus: started.status ?? null,
7233
- mode: started.mode ?? null,
7234
- coordinatorTimings: Array.isArray(started.timings)
7235
- ? started.timings
7236
- : null,
7237
- playName: resolvedName,
7238
- key: normalizedKey,
7239
- depth: nextDepth,
7240
- fanoutIndex: nextParentCalls - 1,
7241
- childIsDatasetBacked,
7242
- childNeedsWorkflowScheduler,
7243
- },
7244
- });
7245
- childPlaySlot?.release();
7246
- childPlaySlot = null;
7247
- const startedStatus = String(started.status ?? '').toLowerCase();
7248
- if (startedStatus === 'completed') {
7249
- emitEvent({
7250
- type: 'log',
7251
- level: 'info',
7252
- message: `Completed child play ${resolvedName} (${normalizedKey})`,
7253
- ts: nowMs(),
7254
- });
7255
- return hydrateChildPlayOutputDatasets({
7256
- req,
7257
- childRunId: workflowId,
7258
- childPlayName: resolvedName,
7259
- value: started.output ?? extractChildPlayOutput(started),
7260
- });
7261
- }
7262
- if (startedStatus === 'failed') {
7263
- const startedError = isRecord(started.error)
7264
- ? started.error
7265
- : { message: started.error };
7266
- const startedErrorMessage =
7267
- typeof startedError.message === 'string' &&
7268
- startedError.message.trim()
7269
- ? startedError.message.trim()
7270
- : `Child play ${resolvedName} (${workflowId}) failed.`;
7271
- throw new Error(startedErrorMessage);
7272
- }
7273
- const childWaitStartedAt = nowMs();
7274
- let waitResult: ChildPlayTerminalWaitResult;
7275
- const readCachedChildTerminalState =
7276
- cachedCoordinatorBinding?.readChildTerminalState?.bind(
7277
- cachedCoordinatorBinding,
7278
- );
7279
- try {
7280
- waitResult = await awaitChildTerminal({
7281
- parentRunId: req.runId,
7282
- // CF's WorkflowStep.waitForEvent generic signature is wider than
7283
- // the small structural shape ChildPlayAwait needs; bridge it the
7284
- // same way the inline implementation did.
7285
- workflowStep: workflowStep as unknown as
7286
- | WorkflowStepLike
7287
- | undefined,
7288
- workflowId,
7289
- playName: resolvedName,
7290
- key: normalizedKey,
7291
- timeoutMs: Math.max(
7292
- 1_000,
7293
- Math.min(options?.timeoutMs ?? 5 * 60_000, 30 * 60_000),
7294
- ),
7295
- coordinator: {
7296
- readRunTerminalState: (runId, timeoutMs) =>
7297
- readDurableChildRunTerminalState({
7298
- baseUrl: req.baseUrl,
7299
- executorToken: req.executorToken,
7300
- parentRunId: req.runId,
7301
- childRunId: runId,
7302
- childPlayName: resolvedName,
7303
- timeoutMs,
7304
- }),
7305
- ...(readCachedChildTerminalState
7306
- ? {
7307
- readChildTerminalState: (
7308
- parentRunId: string,
7309
- eventKey: string,
7310
- timeoutMs?: number,
7311
- ) =>
7312
- readCachedChildTerminalState(
7313
- parentRunId,
7314
- eventKey,
7315
- timeoutMs,
7316
- ),
7317
- }
7318
- : {}),
7319
- },
7320
- now: nowMs,
7321
- hashJson,
7322
- });
7323
- } catch (error) {
7324
- recordRunnerOperationalSpan(req, {
7325
- event: 'play.runtime.span',
7326
- phase: 'child_wait',
7327
- runId: req.runId,
7328
- parentRunId: req.runId,
7329
- childRunId: workflowId,
7330
- playName: resolvedName,
7331
- graphHash: req.graphHash ?? null,
7332
- depth: nextDepth,
7333
- fanoutIndex: nextParentCalls - 1,
7334
- ms: nowMs() - childWaitStartedAt,
7335
- status: 'failed',
7336
- errorCode: 'CHILD_WAIT_FAILED',
7337
- });
7338
- recordRunnerPerfTrace({
7339
- req,
7340
- phase: 'ctx_run_play.child_wait',
7341
- ms: nowMs() - childWaitStartedAt,
7342
- extra: {
7343
- status: 'failed',
7344
- errorCode: 'CHILD_WAIT_FAILED',
7345
- childRunId: workflowId,
7346
- playName: resolvedName,
7347
- key: normalizedKey,
7348
- depth: nextDepth,
7349
- fanoutIndex: nextParentCalls - 1,
7350
- childIsDatasetBacked,
7351
- childNeedsWorkflowScheduler,
7352
- },
7353
- });
7354
- throw error;
7355
- }
7356
- recordRunnerOperationalSpan(req, {
7357
- event: 'play.runtime.span',
7358
- phase: 'child_wait',
7359
- runId: req.runId,
7360
- parentRunId: req.runId,
7361
- childRunId: workflowId,
7362
- playName: resolvedName,
7363
- graphHash: req.graphHash ?? null,
7364
- depth: nextDepth,
7365
- fanoutIndex: nextParentCalls - 1,
7366
- ms: nowMs() - childWaitStartedAt,
7367
- status: 'ok',
7368
- waitSource: waitResult.source,
7369
- waitAttempts: waitResult.attempts ?? null,
7370
- reportedWaitMs: waitResult.waitMs,
7371
- });
7372
- recordRunnerPerfTrace({
7373
- req,
7374
- phase: 'ctx_run_play.child_wait',
7375
- ms: nowMs() - childWaitStartedAt,
7376
- extra: {
7377
- status: 'ok',
7378
- childRunId: workflowId,
7379
- playName: resolvedName,
7380
- key: normalizedKey,
7381
- depth: nextDepth,
7382
- fanoutIndex: nextParentCalls - 1,
7383
- childIsDatasetBacked,
7384
- childNeedsWorkflowScheduler,
7385
- waitSource: waitResult.source,
7386
- waitAttempts: waitResult.attempts ?? null,
7387
- reportedWaitMs: waitResult.waitMs,
7388
- },
7389
- });
7390
- emitEvent({
7391
- type: 'log',
7392
- level: 'info',
7393
- message: `Completed child play ${resolvedName} (${normalizedKey})`,
7394
- ts: nowMs(),
7395
- });
7396
- return hydrateChildPlayOutputDatasets({
7397
- req,
7398
- childRunId: workflowId,
7399
- childPlayName: resolvedName,
7400
- value: waitResult.output,
7401
- });
7402
- } finally {
7403
- childPlaySlot?.release();
7404
- }
7405
- },
6607
+ throw new Error(
6608
+ `CTX_RUN_PLAY_INLINE_ONLY: ctx.runPlay("${resolvedName}") is unavailable on the retired workers_edge runtime. Run this play on the current runtime, where resolved scalar children compose inline.`,
7406
6609
  );
7407
6610
  },
7408
6611
  async fetch(
@@ -8001,9 +7204,7 @@ async function executeRunRequest(
8001
7204
  const flushTerminalLedgerEvents = async (
8002
7205
  terminalEvent: PlayRunLedgerEvent,
8003
7206
  ): Promise<void> => {
8004
- const shouldPersistTerminalLedger =
8005
- options?.persistResultDatasets === true ||
8006
- Boolean(req.playCallGovernance);
7207
+ const shouldPersistTerminalLedger = options?.persistResultDatasets === true;
8007
7208
  if (!shouldPersistTerminalLedger) return;
8008
7209
  await ledgerFlushInFlight;
8009
7210
  const now = nowMs();
@@ -8208,46 +7409,6 @@ async function executeRunRequest(
8208
7409
  ms: nowMs() - resultDatasetStartedAt,
8209
7410
  });
8210
7411
  };
8211
- let parentSignalPromise: Promise<void> | null = null;
8212
- const startParentTerminalSignal = (): Promise<void> => {
8213
- if (!parentSignalPromise) {
8214
- const parentSignalStartedAt = nowMs();
8215
- parentSignalPromise = signalParentPlayTerminal({
8216
- req,
8217
- status: 'completed',
8218
- result: req.playCallGovernance ? serializedResult : terminalResult,
8219
- })
8220
- .catch((error) => {
8221
- void runnerTelemetry
8222
- .child({
8223
- context: {
8224
- runId: req.runId,
8225
- orgId: req.orgId,
8226
- playName: req.playName,
8227
- },
8228
- })
8229
- .error(
8230
- 'runner.parent_completion_signal.failed',
8231
- error,
8232
- undefined,
8233
- {
8234
- tag: '[play-harness] non-fatal parent completion signal failed',
8235
- },
8236
- );
8237
- })
8238
- .finally(() => {
8239
- recordRunnerPerfTrace({
8240
- req,
8241
- phase: 'runner.parent_terminal_signal',
8242
- ms: nowMs() - parentSignalStartedAt,
8243
- });
8244
- });
8245
- }
8246
- return parentSignalPromise;
8247
- };
8248
- if (req.playCallGovernance && !options?.persistResultDatasets) {
8249
- await persistProjectedResultDatasets();
8250
- }
8251
7412
  await releaseRuntimeLeasesOnSettlement({
8252
7413
  req,
8253
7414
  leasedSheetNamespaces,
@@ -8290,7 +7451,6 @@ async function executeRunRequest(
8290
7451
  ms: nowMs() - terminalUpdateStartedAt,
8291
7452
  });
8292
7453
 
8293
- const parentSignal = startParentTerminalSignal();
8294
7454
  if (!capped) {
8295
7455
  const billingStartedAt = nowMs();
8296
7456
  const billingPromise = finalizeWorkerComputeBilling({
@@ -8323,23 +7483,7 @@ async function executeRunRequest(
8323
7483
  await nonBlockingBillingPromise;
8324
7484
  }
8325
7485
  }
8326
- await parentSignal;
8327
- } else if (req.playCallGovernance) {
8328
- const childTerminalStartedAt = nowMs();
8329
- await flushTerminalLedgerEvents({
8330
- type: 'run.completed',
8331
- runId: req.runId,
8332
- source: 'worker',
8333
- occurredAt: nowMs(),
8334
- result: terminalResult,
8335
- });
8336
- recordRunnerPerfTrace({
8337
- req,
8338
- phase: 'runner.child_terminal_ledger_append',
8339
- ms: nowMs() - childTerminalStartedAt,
8340
- });
8341
7486
  }
8342
- await startParentTerminalSignal();
8343
7487
  recordRunnerPerfTrace({
8344
7488
  req,
8345
7489
  phase: 'runner.execute_total',
@@ -8395,7 +7539,7 @@ async function executeRunRequest(
8395
7539
  ? `${message} ${receiptSalvageFailureSuffix(salvage)}`
8396
7540
  : message;
8397
7541
  const terminalLedgerMessage = redactSecretsFromLogString(terminalMessage);
8398
- if (options?.persistResultDatasets || req.playCallGovernance) {
7542
+ if (options?.persistResultDatasets) {
8399
7543
  appendRunLogLine(
8400
7544
  `${aborted ? '[cancelled]' : '[error]'} ${terminalLedgerMessage}`,
8401
7545
  );
@@ -8429,13 +7573,9 @@ async function executeRunRequest(
8429
7573
  });
8430
7574
  recordRunnerPerfTrace({
8431
7575
  req,
8432
- phase: req.playCallGovernance
8433
- ? aborted
8434
- ? 'runner.child_terminal_ledger_append_cancelled'
8435
- : 'runner.child_terminal_ledger_append_failed'
8436
- : aborted
8437
- ? 'runner.terminal_ledger_append_cancelled'
8438
- : 'runner.terminal_ledger_append_failed',
7576
+ phase: aborted
7577
+ ? 'runner.terminal_ledger_append_cancelled'
7578
+ : 'runner.terminal_ledger_append_failed',
8439
7579
  ms: nowMs() - terminalUpdateStartedAt,
8440
7580
  extra: {
8441
7581
  errorCode: failure.code,
@@ -8476,11 +7616,6 @@ async function executeRunRequest(
8476
7616
  });
8477
7617
  }
8478
7618
  }
8479
- await signalParentPlayTerminal({
8480
- req,
8481
- status: aborted ? 'cancelled' : 'failed',
8482
- error: terminalMessage,
8483
- }).catch(() => null);
8484
7619
  recordRunnerPerfTrace({
8485
7620
  req,
8486
7621
  phase: aborted ? 'runner.execute_cancelled' : 'runner.execute_failed',
@@ -8631,12 +7766,6 @@ function runRequestFromWorkflowParams(
8631
7766
  executionPlan: isExecutionPlan(params.executionPlan)
8632
7767
  ? (params.executionPlan as ExecutionPlan)
8633
7768
  : null,
8634
- childPlayManifests: isRecord(params.childPlayManifests)
8635
- ? (params.childPlayManifests as PlayRuntimeManifestMap)
8636
- : null,
8637
- playCallGovernance: isPlayCallGovernanceSnapshot(params.playCallGovernance)
8638
- ? params.playCallGovernance
8639
- : null,
8640
7769
  preloadedDbSessions: Array.isArray(params.preloadedDbSessions)
8641
7770
  ? (params.preloadedDbSessions as PreloadedRuntimeDbSession[])
8642
7771
  : null,
@@ -8673,22 +7802,6 @@ function isExecutionPlan(value: unknown): value is ExecutionPlan {
8673
7802
  );
8674
7803
  }
8675
7804
 
8676
- function isPlayCallGovernanceSnapshot(
8677
- value: unknown,
8678
- ): value is PlayCallGovernanceSnapshot {
8679
- return (
8680
- isRecord(value) &&
8681
- typeof value.rootRunId === 'string' &&
8682
- typeof value.parentRunId === 'string' &&
8683
- typeof value.parentPlayName === 'string' &&
8684
- typeof value.key === 'string' &&
8685
- Array.isArray(value.ancestryPlayIds) &&
8686
- value.ancestryPlayIds.every((entry) => typeof entry === 'string') &&
8687
- typeof value.callDepth === 'number' &&
8688
- Number.isFinite(value.callDepth)
8689
- );
8690
- }
8691
-
8692
7805
  async function persistResultDatasets(
8693
7806
  req: RunRequest,
8694
7807
  resultDatasets: ProjectedResultDatasetHandle[],
@@ -9014,7 +8127,7 @@ export class TenantWorkflow extends WorkflowEntrypoint<
9014
8127
  },
9015
8128
  step,
9016
8129
  {
9017
- persistResultDatasets: !req.playCallGovernance,
8130
+ persistResultDatasets: true,
9018
8131
  abortController,
9019
8132
  waitUntil: (promise) => this.ctx.waitUntil(promise),
9020
8133
  },