deepline 0.1.207 → 0.1.209

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 (33) hide show
  1. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/receipts.ts +2 -12
  2. package/dist/bundling-sources/sdk/src/client.ts +10 -0
  3. package/dist/bundling-sources/sdk/src/http.ts +10 -1
  4. package/dist/bundling-sources/sdk/src/release.ts +2 -2
  5. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +16 -31
  6. package/dist/bundling-sources/shared_libs/play-runtime/child-execution-strategy.ts +18 -0
  7. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +312 -207
  8. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +15 -0
  9. package/dist/bundling-sources/shared_libs/play-runtime/daytona-runtime-config.ts +0 -5
  10. package/dist/bundling-sources/shared_libs/play-runtime/execution-capabilities.ts +1 -0
  11. package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-rate-state-backend.ts +429 -102
  12. package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +27 -5
  13. package/dist/bundling-sources/shared_libs/play-runtime/governor/rate-state-backend.ts +18 -0
  14. package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +31 -12
  15. package/dist/bundling-sources/shared_libs/play-runtime/run-failure.ts +103 -0
  16. package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +105 -10
  17. package/dist/bundling-sources/shared_libs/play-runtime/run-snapshot-stream.ts +21 -1
  18. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +32 -86
  19. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +141 -2
  20. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-session-execution.ts +45 -0
  21. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +180 -447
  22. package/dist/bundling-sources/shared_libs/play-runtime/runtime-constants.ts +12 -0
  23. package/dist/bundling-sources/shared_libs/play-runtime/suspension.ts +33 -1
  24. package/dist/bundling-sources/shared_libs/play-runtime/tool-http-errors.ts +11 -0
  25. package/dist/bundling-sources/shared_libs/plays/artifact-kind-guard.ts +112 -0
  26. package/dist/cli/index.js +38 -5
  27. package/dist/cli/index.mjs +38 -5
  28. package/dist/index.d.mts +10 -0
  29. package/dist/index.d.ts +10 -0
  30. package/dist/index.js +32 -5
  31. package/dist/index.mjs +32 -5
  32. package/package.json +1 -1
  33. package/dist/bundling-sources/shared_libs/play-runtime/child-run-lifecycle.ts +0 -70
@@ -10,3 +10,15 @@ export const PLAY_RUNNER_TIMEOUT_SECONDS = 30 * 60;
10
10
 
11
11
  /** TTL for workflow executor tokens, in seconds. */
12
12
  export const WORKFLOW_EXECUTOR_TOKEN_TTL_SECONDS = PLAY_RUNNER_TIMEOUT_SECONDS;
13
+
14
+ /**
15
+ * Absurd run-claim lease window, in seconds. The scheduler expires a claim whose
16
+ * `claim_expires_at` falls this far behind, so whoever owns execution must renew
17
+ * within this window. Shared between the worker's own lease heartbeat and the
18
+ * Daytona push-execution runner (which heartbeats the receipt gateway on a
19
+ * `RUNTIME_CLAIM_LEASE_SECONDS / 3` cadence) so both agree on the deadline.
20
+ */
21
+ export const RUNTIME_CLAIM_LEASE_SECONDS = 120;
22
+
23
+ /** Heartbeat cadence divisor: renew the claim this many times per lease window. */
24
+ export const RUNTIME_CLAIM_HEARTBEAT_DIVISOR = 3;
@@ -31,8 +31,38 @@ export type PlayExecutionSuspension =
31
31
  childRunId: string;
32
32
  childPlayName: string;
33
33
  }>;
34
+ }
35
+ | {
36
+ /**
37
+ * Push-execution park (B2-final): the Daytona runner command was started
38
+ * DETACHED and the worker parks instead of holding anything. The parked
39
+ * attempt wakes on the runner's pushed terminal (the gateway emits the
40
+ * absurd wake event) or on the ceiling timeout, then finalizes from
41
+ * persisted state.
42
+ */
43
+ kind: 'detached_runner';
44
+ boundaryId: string;
45
+ /** Attempt generation whose executor token the detached runner holds —
46
+ * the key under which its pushed terminal is recorded and its wake event
47
+ * is named. */
48
+ runnerAttempt: number;
49
+ sandboxId: string;
50
+ sessionId: string;
51
+ cmdId: string;
52
+ /** Captured output/exit-code file paths inside the sandbox, used by the
53
+ * timeout-wake salvage verification. */
54
+ outputPath: string;
55
+ exitCodePath: string;
56
+ startedAtMs: number;
57
+ /** Overall run ceiling; the park timeout. */
58
+ ceilingMs: number;
34
59
  };
35
60
 
61
+ export type DetachedRunnerSuspension = Extract<
62
+ PlayExecutionSuspension,
63
+ { kind: 'detached_runner' }
64
+ >;
65
+
36
66
  export class PlayExecutionSuspendedError extends Error {
37
67
  readonly suspension: PlayExecutionSuspension;
38
68
 
@@ -46,7 +76,9 @@ export class PlayExecutionSuspendedError extends Error {
46
76
  ? `Play execution suspended waiting for ${suspension.boundaries.length} child plays.`
47
77
  : suspension.kind === 'child_play'
48
78
  ? `Play execution suspended waiting for child play ${JSON.stringify(suspension.childPlayName)}.`
49
- : `Play execution suspended waiting for integration event ${JSON.stringify(suspension.eventKey)}.`,
79
+ : suspension.kind === 'detached_runner'
80
+ ? `Play execution parked on detached runner ${suspension.cmdId} (sandbox ${suspension.sandboxId}).`
81
+ : `Play execution suspended waiting for integration event ${JSON.stringify(suspension.eventKey)}.`,
50
82
  );
51
83
  this.name = 'PlayExecutionSuspendedError';
52
84
  this.suspension = suspension;
@@ -97,6 +97,16 @@ function normalizeHardBillingPayload(
97
97
  };
98
98
  }
99
99
 
100
+ function receiptFailureKindForToolErrorPayload(
101
+ payload: Record<string, unknown> | null,
102
+ ): WorkReceiptFailureKind {
103
+ const code = getStringField(payload, 'code')?.toUpperCase();
104
+ // A credential connection can be added or replaced between play runs. Keep
105
+ // the failure terminal within its owning run, but let a later run reclaim
106
+ // the durable receipt instead of replaying stale authorization state.
107
+ return code === 'INTEGRATION_CREDENTIALS_MISSING' ? 'repairable' : 'terminal';
108
+ }
109
+
100
110
  function formatHardBillingFailureMessage(input: {
101
111
  billing: Record<string, unknown>;
102
112
  toolId: string;
@@ -226,6 +236,7 @@ export function normalizeToolHttpErrorMessage(input: {
226
236
  )}`,
227
237
  billing,
228
238
  input.status,
239
+ receiptFailureKindForToolErrorPayload(parsed),
229
240
  );
230
241
  }
231
242
 
@@ -0,0 +1,112 @@
1
+ import type { PlayArtifactKind, PlayBundleArtifact } from './artifact-types';
2
+
3
+ /**
4
+ * Loud, directional guard that stops a Cloudflare-Workers (`esm_workers`)
5
+ * bundle from reaching a Node/Daytona (`cjs_node20`) runner.
6
+ *
7
+ * The Node runner loads play code with `Module._compile`, which cannot resolve
8
+ * `cloudflare:workers` scheme imports and dies with the opaque
9
+ * `ERR_UNSUPPORTED_ESM_URL_SCHEME: Received protocol 'cloudflare:'`. Those
10
+ * imports only exist in the Cloudflare Workers harness apps
11
+ * (`apps/play-runner-workers/`, `apps/play-harness-worker/`) baked into
12
+ * `esm_workers` artifacts. When the wrong artifact kind is targeted for a node
13
+ * profile (e.g. the absurd/Daytona scheduler falling back to a verbatim stored
14
+ * `esm_workers` bundle), this guard fires at the targeting/load seam with a
15
+ * message that names the mismatch instead of surfacing the ESM scheme error.
16
+ */
17
+
18
+ /**
19
+ * Legacy artifacts predate the `artifactKind` field; they are always
20
+ * `cjs_node20` (the only kind that existed before the workers split). Mirror the
21
+ * default documented on `PlayBundleArtifact.artifactKind`.
22
+ */
23
+ export function artifactKindOf(artifact: PlayBundleArtifact): PlayArtifactKind {
24
+ return artifact.artifactKind ?? 'cjs_node20';
25
+ }
26
+
27
+ /**
28
+ * Detect `cloudflare:` scheme imports in bundled code. Matches both static
29
+ * `import ... from 'cloudflare:workers'` and `require('cloudflare:...')` forms,
30
+ * with single or double quotes. This is the exact shape the Node runner cannot
31
+ * load.
32
+ */
33
+ const CLOUDFLARE_SCHEME_IMPORT =
34
+ /(?:\bfrom\s*|\bimport\s*|\brequire\s*\(\s*)['"]cloudflare:[^'"]*['"]/;
35
+
36
+ export function bundledCodeHasCloudflareSchemeImport(
37
+ bundledCode: string,
38
+ ): boolean {
39
+ return CLOUDFLARE_SCHEME_IMPORT.test(bundledCode);
40
+ }
41
+
42
+ export class PlayArtifactKindMismatchError extends Error {
43
+ readonly expectedKind: PlayArtifactKind;
44
+ readonly actualKind: PlayArtifactKind;
45
+ readonly reason: 'kind_mismatch' | 'cloudflare_scheme_import';
46
+
47
+ constructor(input: {
48
+ expectedKind: PlayArtifactKind;
49
+ actualKind: PlayArtifactKind;
50
+ reason: 'kind_mismatch' | 'cloudflare_scheme_import';
51
+ message: string;
52
+ }) {
53
+ super(input.message);
54
+ this.name = 'PlayArtifactKindMismatchError';
55
+ this.expectedKind = input.expectedKind;
56
+ this.actualKind = input.actualKind;
57
+ this.reason = input.reason;
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Assert an artifact is loadable by the Node (`cjs_node20`) runner. Throws a
63
+ * `PlayArtifactKindMismatchError` naming the run/profile and expected vs actual
64
+ * kind if the artifact is an `esm_workers` bundle or carries `cloudflare:`
65
+ * scheme imports.
66
+ *
67
+ * `context` is a short human-readable locator (run id, play name, submit path)
68
+ * woven into the error so the failure points at the wrong targeting decision,
69
+ * not the downstream ESM scheme error.
70
+ */
71
+ export function assertNodeRunnableArtifact(input: {
72
+ artifact: PlayBundleArtifact;
73
+ expectedKind: PlayArtifactKind;
74
+ context: string;
75
+ }): void {
76
+ const { artifact, expectedKind, context } = input;
77
+ if (expectedKind !== 'cjs_node20') {
78
+ // This helper only guards the node runner. A workers-edge target never
79
+ // reaches the Node/Daytona load path, so there is nothing to assert.
80
+ return;
81
+ }
82
+
83
+ const actualKind = artifactKindOf(artifact);
84
+ if (actualKind !== 'cjs_node20') {
85
+ throw new PlayArtifactKindMismatchError({
86
+ expectedKind,
87
+ actualKind,
88
+ reason: 'kind_mismatch',
89
+ message:
90
+ `Node runner (${context}) received a "${actualKind}" play artifact but ` +
91
+ `requires "cjs_node20". An "esm_workers" bundle embeds the Cloudflare ` +
92
+ `Workers harness (cloudflare:workers imports) and cannot load under ` +
93
+ `Module._compile. Rebundle/republish the play for the node runner ` +
94
+ `(profile=absurd / backend=daytona|local_process) instead of serving ` +
95
+ `the stored workers artifact verbatim.`,
96
+ });
97
+ }
98
+
99
+ if (bundledCodeHasCloudflareSchemeImport(artifact.bundledCode)) {
100
+ throw new PlayArtifactKindMismatchError({
101
+ expectedKind,
102
+ actualKind,
103
+ reason: 'cloudflare_scheme_import',
104
+ message:
105
+ `Node runner (${context}) received a play artifact tagged ` +
106
+ `"cjs_node20" whose bundledCode still contains a cloudflare: scheme ` +
107
+ `import. This bundle would die with ERR_UNSUPPORTED_ESM_URL_SCHEME ` +
108
+ `under Module._compile. The artifact was mis-tagged or mis-targeted; ` +
109
+ `rebundle for the node runner.`,
110
+ });
111
+ }
112
+ }
package/dist/cli/index.js CHANGED
@@ -623,10 +623,10 @@ var SDK_RELEASE = {
623
623
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
624
624
  // fields shipped in 0.1.153.
625
625
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
626
- version: "0.1.207",
626
+ version: "0.1.209",
627
627
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
628
628
  supportPolicy: {
629
- latest: "0.1.207",
629
+ latest: "0.1.209",
630
630
  minimumSupported: "0.1.53",
631
631
  deprecatedBelow: "0.1.53",
632
632
  commandMinimumSupported: [
@@ -782,6 +782,7 @@ var COORDINATOR_INTERNAL_TOKEN_HEADER = "x-deepline-internal-token";
782
782
  var COORDINATOR_URL_OVERRIDE_HEADER = "x-deepline-coordinator-url";
783
783
  var WORKER_CALLBACK_URL_OVERRIDE_HEADER = "x-deepline-worker-callback-url";
784
784
  var RUNTIME_SCHEDULER_SCHEMA_OVERRIDE_HEADER = "x-deepline-runtime-scheduler-schema";
785
+ var ABSURD_RELEASE_OVERRIDE_HEADER = "x-deepline-absurd-release";
785
786
  var SYNTHETIC_RUN_HEADER = "x-deepline-synthetic-run";
786
787
 
787
788
  // ../shared_libs/play-runtime/test-runtime-seams.ts
@@ -903,6 +904,7 @@ var HttpClient = class {
903
904
  }
904
905
  const coordinatorUrl = typeof process !== "undefined" ? process.env?.DEEPLINE_COORDINATOR_URL : void 0;
905
906
  const coordinatorInternalToken = typeof process !== "undefined" ? process.env?.DEEPLINE_INTERNAL_TOKEN : void 0;
907
+ const absurdReleaseOverride = typeof process !== "undefined" ? process.env?.DEEPLINE_ABSURD_RELEASE : void 0;
906
908
  if (coordinatorUrl?.trim()) {
907
909
  headers[COORDINATOR_URL_OVERRIDE_HEADER] = coordinatorUrl.trim();
908
910
  }
@@ -922,7 +924,10 @@ var HttpClient = class {
922
924
  if (runtimeTestFault?.trim()) {
923
925
  headers[PLAY_RUNTIME_TEST_FAULT_HEADER] = runtimeTestFault.trim();
924
926
  }
925
- if (coordinatorInternalToken?.trim() && (coordinatorUrl?.trim() || workerCallbackUrl?.trim() || runtimeTestFault?.trim())) {
927
+ if (absurdReleaseOverride?.trim() && coordinatorInternalToken?.trim()) {
928
+ headers[ABSURD_RELEASE_OVERRIDE_HEADER] = absurdReleaseOverride.trim();
929
+ }
930
+ if (coordinatorInternalToken?.trim() && (coordinatorUrl?.trim() || workerCallbackUrl?.trim() || runtimeTestFault?.trim() || absurdReleaseOverride?.trim())) {
926
931
  headers[COORDINATOR_INTERNAL_TOKEN_HEADER] = coordinatorInternalToken.trim();
927
932
  }
928
933
  return headers;
@@ -1403,6 +1408,25 @@ function normalizePlayRunLedgerStatus(value) {
1403
1408
  return "unknown";
1404
1409
  }
1405
1410
  }
1411
+ function summarizeRunRowOutcomes(snapshot) {
1412
+ let completedRows = 0;
1413
+ let failedRows = 0;
1414
+ let totalRows = 0;
1415
+ for (const step of Object.values(snapshot.stepsById)) {
1416
+ const progress = step.progress;
1417
+ if (!progress) continue;
1418
+ completedRows += Math.max(0, finiteNumber(progress.completed) ?? 0);
1419
+ failedRows += Math.max(0, finiteNumber(progress.failed) ?? 0);
1420
+ const stepTotal = finiteNumber(progress.total);
1421
+ totalRows += stepTotal !== null && stepTotal >= 0 ? stepTotal : Math.max(0, finiteNumber(progress.completed) ?? 0) + Math.max(0, finiteNumber(progress.failed) ?? 0);
1422
+ }
1423
+ return {
1424
+ completedRows,
1425
+ failedRows,
1426
+ totalRows,
1427
+ hasRowFailures: failedRows > 0
1428
+ };
1429
+ }
1406
1430
  function createEmptyPlayRunLedgerSnapshot(input2) {
1407
1431
  const status = normalizePlayRunLedgerStatus(input2.status ?? "unknown");
1408
1432
  const startedAt = finiteNumber(input2.startedAt) ?? null;
@@ -1622,9 +1646,11 @@ function buildSnapshotFromLedger(snapshot) {
1622
1646
  completedAt: step.completedAt ?? null,
1623
1647
  updatedAt: step.updatedAt ?? null
1624
1648
  }));
1649
+ const liveStatus = normalizePlayRunLiveStatus(snapshot.status);
1650
+ const rowOutcomes = isTerminalPlayRunLiveStatus(liveStatus) && Object.keys(snapshot.stepsById).length > 0 ? summarizeRunRowOutcomes(snapshot) : null;
1625
1651
  return {
1626
1652
  runId: snapshot.runId,
1627
- status: normalizePlayRunLiveStatus(snapshot.status),
1653
+ status: liveStatus,
1628
1654
  createdAt: snapshot.createdAt ?? null,
1629
1655
  startedAt: snapshot.startedAt ?? null,
1630
1656
  finishedAt: snapshot.finishedAt ?? null,
@@ -1636,7 +1662,8 @@ function buildSnapshotFromLedger(snapshot) {
1636
1662
  activeArtifactTableNamespace: snapshot.activeArtifactTableNamespace ?? null,
1637
1663
  resultTableNamespace: snapshot.resultTableNamespace ?? null,
1638
1664
  nodeStates,
1639
- activeNodeId: snapshot.activeStepId ?? null
1665
+ activeNodeId: snapshot.activeStepId ?? null,
1666
+ ...rowOutcomes ? { rowOutcomes } : {}
1640
1667
  };
1641
1668
  }
1642
1669
  function buildPlayRunStatusSnapshot(input2) {
@@ -14594,12 +14621,18 @@ async function handlePlayCheck(args) {
14594
14621
  }
14595
14622
  const client2 = new DeeplineClient();
14596
14623
  const integrationMode = resolveEvalIntegrationMode();
14624
+ const importedPlays = [...graph.nodes.values()].filter((node) => node.filePath !== graph.root.filePath).map((node) => ({
14625
+ playName: node.playName,
14626
+ sourceCode: node.sourceCode,
14627
+ sourcePath: node.filePath
14628
+ }));
14597
14629
  const result = await client2.checkPlayArtifact({
14598
14630
  name: playName,
14599
14631
  sourceCode: graph.root.sourceCode,
14600
14632
  sourceFiles: graph.root.sourceFiles,
14601
14633
  description: graph.root.playDescription ?? void 0,
14602
14634
  artifact: graph.root.artifact,
14635
+ ...importedPlays.length > 0 ? { importedPlays } : {},
14603
14636
  ...integrationMode ? { integrationMode } : {}
14604
14637
  });
14605
14638
  const enrichedResult = {
@@ -608,10 +608,10 @@ var SDK_RELEASE = {
608
608
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
609
609
  // fields shipped in 0.1.153.
610
610
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
611
- version: "0.1.207",
611
+ version: "0.1.209",
612
612
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
613
613
  supportPolicy: {
614
- latest: "0.1.207",
614
+ latest: "0.1.209",
615
615
  minimumSupported: "0.1.53",
616
616
  deprecatedBelow: "0.1.53",
617
617
  commandMinimumSupported: [
@@ -767,6 +767,7 @@ var COORDINATOR_INTERNAL_TOKEN_HEADER = "x-deepline-internal-token";
767
767
  var COORDINATOR_URL_OVERRIDE_HEADER = "x-deepline-coordinator-url";
768
768
  var WORKER_CALLBACK_URL_OVERRIDE_HEADER = "x-deepline-worker-callback-url";
769
769
  var RUNTIME_SCHEDULER_SCHEMA_OVERRIDE_HEADER = "x-deepline-runtime-scheduler-schema";
770
+ var ABSURD_RELEASE_OVERRIDE_HEADER = "x-deepline-absurd-release";
770
771
  var SYNTHETIC_RUN_HEADER = "x-deepline-synthetic-run";
771
772
 
772
773
  // ../shared_libs/play-runtime/test-runtime-seams.ts
@@ -888,6 +889,7 @@ var HttpClient = class {
888
889
  }
889
890
  const coordinatorUrl = typeof process !== "undefined" ? process.env?.DEEPLINE_COORDINATOR_URL : void 0;
890
891
  const coordinatorInternalToken = typeof process !== "undefined" ? process.env?.DEEPLINE_INTERNAL_TOKEN : void 0;
892
+ const absurdReleaseOverride = typeof process !== "undefined" ? process.env?.DEEPLINE_ABSURD_RELEASE : void 0;
891
893
  if (coordinatorUrl?.trim()) {
892
894
  headers[COORDINATOR_URL_OVERRIDE_HEADER] = coordinatorUrl.trim();
893
895
  }
@@ -907,7 +909,10 @@ var HttpClient = class {
907
909
  if (runtimeTestFault?.trim()) {
908
910
  headers[PLAY_RUNTIME_TEST_FAULT_HEADER] = runtimeTestFault.trim();
909
911
  }
910
- if (coordinatorInternalToken?.trim() && (coordinatorUrl?.trim() || workerCallbackUrl?.trim() || runtimeTestFault?.trim())) {
912
+ if (absurdReleaseOverride?.trim() && coordinatorInternalToken?.trim()) {
913
+ headers[ABSURD_RELEASE_OVERRIDE_HEADER] = absurdReleaseOverride.trim();
914
+ }
915
+ if (coordinatorInternalToken?.trim() && (coordinatorUrl?.trim() || workerCallbackUrl?.trim() || runtimeTestFault?.trim() || absurdReleaseOverride?.trim())) {
911
916
  headers[COORDINATOR_INTERNAL_TOKEN_HEADER] = coordinatorInternalToken.trim();
912
917
  }
913
918
  return headers;
@@ -1388,6 +1393,25 @@ function normalizePlayRunLedgerStatus(value) {
1388
1393
  return "unknown";
1389
1394
  }
1390
1395
  }
1396
+ function summarizeRunRowOutcomes(snapshot) {
1397
+ let completedRows = 0;
1398
+ let failedRows = 0;
1399
+ let totalRows = 0;
1400
+ for (const step of Object.values(snapshot.stepsById)) {
1401
+ const progress = step.progress;
1402
+ if (!progress) continue;
1403
+ completedRows += Math.max(0, finiteNumber(progress.completed) ?? 0);
1404
+ failedRows += Math.max(0, finiteNumber(progress.failed) ?? 0);
1405
+ const stepTotal = finiteNumber(progress.total);
1406
+ totalRows += stepTotal !== null && stepTotal >= 0 ? stepTotal : Math.max(0, finiteNumber(progress.completed) ?? 0) + Math.max(0, finiteNumber(progress.failed) ?? 0);
1407
+ }
1408
+ return {
1409
+ completedRows,
1410
+ failedRows,
1411
+ totalRows,
1412
+ hasRowFailures: failedRows > 0
1413
+ };
1414
+ }
1391
1415
  function createEmptyPlayRunLedgerSnapshot(input2) {
1392
1416
  const status = normalizePlayRunLedgerStatus(input2.status ?? "unknown");
1393
1417
  const startedAt = finiteNumber(input2.startedAt) ?? null;
@@ -1607,9 +1631,11 @@ function buildSnapshotFromLedger(snapshot) {
1607
1631
  completedAt: step.completedAt ?? null,
1608
1632
  updatedAt: step.updatedAt ?? null
1609
1633
  }));
1634
+ const liveStatus = normalizePlayRunLiveStatus(snapshot.status);
1635
+ const rowOutcomes = isTerminalPlayRunLiveStatus(liveStatus) && Object.keys(snapshot.stepsById).length > 0 ? summarizeRunRowOutcomes(snapshot) : null;
1610
1636
  return {
1611
1637
  runId: snapshot.runId,
1612
- status: normalizePlayRunLiveStatus(snapshot.status),
1638
+ status: liveStatus,
1613
1639
  createdAt: snapshot.createdAt ?? null,
1614
1640
  startedAt: snapshot.startedAt ?? null,
1615
1641
  finishedAt: snapshot.finishedAt ?? null,
@@ -1621,7 +1647,8 @@ function buildSnapshotFromLedger(snapshot) {
1621
1647
  activeArtifactTableNamespace: snapshot.activeArtifactTableNamespace ?? null,
1622
1648
  resultTableNamespace: snapshot.resultTableNamespace ?? null,
1623
1649
  nodeStates,
1624
- activeNodeId: snapshot.activeStepId ?? null
1650
+ activeNodeId: snapshot.activeStepId ?? null,
1651
+ ...rowOutcomes ? { rowOutcomes } : {}
1625
1652
  };
1626
1653
  }
1627
1654
  function buildPlayRunStatusSnapshot(input2) {
@@ -14623,12 +14650,18 @@ async function handlePlayCheck(args) {
14623
14650
  }
14624
14651
  const client2 = new DeeplineClient();
14625
14652
  const integrationMode = resolveEvalIntegrationMode();
14653
+ const importedPlays = [...graph.nodes.values()].filter((node) => node.filePath !== graph.root.filePath).map((node) => ({
14654
+ playName: node.playName,
14655
+ sourceCode: node.sourceCode,
14656
+ sourcePath: node.filePath
14657
+ }));
14626
14658
  const result = await client2.checkPlayArtifact({
14627
14659
  name: playName,
14628
14660
  sourceCode: graph.root.sourceCode,
14629
14661
  sourceFiles: graph.root.sourceFiles,
14630
14662
  description: graph.root.playDescription ?? void 0,
14631
14663
  artifact: graph.root.artifact,
14664
+ ...importedPlays.length > 0 ? { importedPlays } : {},
14632
14665
  ...integrationMode ? { integrationMode } : {}
14633
14666
  });
14634
14667
  const enrichedResult = {
package/dist/index.d.mts CHANGED
@@ -1811,6 +1811,16 @@ declare class DeeplineClient {
1811
1811
  description?: string;
1812
1812
  artifact: Record<string, unknown>;
1813
1813
  integrationMode?: 'live' | 'eval_stub' | 'fixture';
1814
+ /**
1815
+ * Sibling plays from the same local bundle graph. Lets the server splice
1816
+ * unpublished local children into the checked plan and enforce the
1817
+ * row-scoped batch rule (ADR 0013).
1818
+ */
1819
+ importedPlays?: Array<{
1820
+ playName?: string | null;
1821
+ sourceCode: string;
1822
+ sourcePath?: string | null;
1823
+ }>;
1814
1824
  }): Promise<PlayCheckResult>;
1815
1825
  /**
1816
1826
  * Compile legacy enrich command arguments into a runtime plan.
package/dist/index.d.ts CHANGED
@@ -1811,6 +1811,16 @@ declare class DeeplineClient {
1811
1811
  description?: string;
1812
1812
  artifact: Record<string, unknown>;
1813
1813
  integrationMode?: 'live' | 'eval_stub' | 'fixture';
1814
+ /**
1815
+ * Sibling plays from the same local bundle graph. Lets the server splice
1816
+ * unpublished local children into the checked plan and enforce the
1817
+ * row-scoped batch rule (ADR 0013).
1818
+ */
1819
+ importedPlays?: Array<{
1820
+ playName?: string | null;
1821
+ sourceCode: string;
1822
+ sourcePath?: string | null;
1823
+ }>;
1814
1824
  }): Promise<PlayCheckResult>;
1815
1825
  /**
1816
1826
  * Compile legacy enrich command arguments into a runtime plan.
package/dist/index.js CHANGED
@@ -422,10 +422,10 @@ var SDK_RELEASE = {
422
422
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
423
423
  // fields shipped in 0.1.153.
424
424
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
425
- version: "0.1.207",
425
+ version: "0.1.209",
426
426
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
427
427
  supportPolicy: {
428
- latest: "0.1.207",
428
+ latest: "0.1.209",
429
429
  minimumSupported: "0.1.53",
430
430
  deprecatedBelow: "0.1.53",
431
431
  commandMinimumSupported: [
@@ -581,6 +581,7 @@ var COORDINATOR_INTERNAL_TOKEN_HEADER = "x-deepline-internal-token";
581
581
  var COORDINATOR_URL_OVERRIDE_HEADER = "x-deepline-coordinator-url";
582
582
  var WORKER_CALLBACK_URL_OVERRIDE_HEADER = "x-deepline-worker-callback-url";
583
583
  var RUNTIME_SCHEDULER_SCHEMA_OVERRIDE_HEADER = "x-deepline-runtime-scheduler-schema";
584
+ var ABSURD_RELEASE_OVERRIDE_HEADER = "x-deepline-absurd-release";
584
585
  var SYNTHETIC_RUN_HEADER = "x-deepline-synthetic-run";
585
586
 
586
587
  // ../shared_libs/play-runtime/test-runtime-seams.ts
@@ -702,6 +703,7 @@ var HttpClient = class {
702
703
  }
703
704
  const coordinatorUrl = typeof process !== "undefined" ? process.env?.DEEPLINE_COORDINATOR_URL : void 0;
704
705
  const coordinatorInternalToken = typeof process !== "undefined" ? process.env?.DEEPLINE_INTERNAL_TOKEN : void 0;
706
+ const absurdReleaseOverride = typeof process !== "undefined" ? process.env?.DEEPLINE_ABSURD_RELEASE : void 0;
705
707
  if (coordinatorUrl?.trim()) {
706
708
  headers[COORDINATOR_URL_OVERRIDE_HEADER] = coordinatorUrl.trim();
707
709
  }
@@ -721,7 +723,10 @@ var HttpClient = class {
721
723
  if (runtimeTestFault?.trim()) {
722
724
  headers[PLAY_RUNTIME_TEST_FAULT_HEADER] = runtimeTestFault.trim();
723
725
  }
724
- if (coordinatorInternalToken?.trim() && (coordinatorUrl?.trim() || workerCallbackUrl?.trim() || runtimeTestFault?.trim())) {
726
+ if (absurdReleaseOverride?.trim() && coordinatorInternalToken?.trim()) {
727
+ headers[ABSURD_RELEASE_OVERRIDE_HEADER] = absurdReleaseOverride.trim();
728
+ }
729
+ if (coordinatorInternalToken?.trim() && (coordinatorUrl?.trim() || workerCallbackUrl?.trim() || runtimeTestFault?.trim() || absurdReleaseOverride?.trim())) {
725
730
  headers[COORDINATOR_INTERNAL_TOKEN_HEADER] = coordinatorInternalToken.trim();
726
731
  }
727
732
  return headers;
@@ -1202,6 +1207,25 @@ function normalizePlayRunLedgerStatus(value) {
1202
1207
  return "unknown";
1203
1208
  }
1204
1209
  }
1210
+ function summarizeRunRowOutcomes(snapshot) {
1211
+ let completedRows = 0;
1212
+ let failedRows = 0;
1213
+ let totalRows = 0;
1214
+ for (const step of Object.values(snapshot.stepsById)) {
1215
+ const progress = step.progress;
1216
+ if (!progress) continue;
1217
+ completedRows += Math.max(0, finiteNumber(progress.completed) ?? 0);
1218
+ failedRows += Math.max(0, finiteNumber(progress.failed) ?? 0);
1219
+ const stepTotal = finiteNumber(progress.total);
1220
+ totalRows += stepTotal !== null && stepTotal >= 0 ? stepTotal : Math.max(0, finiteNumber(progress.completed) ?? 0) + Math.max(0, finiteNumber(progress.failed) ?? 0);
1221
+ }
1222
+ return {
1223
+ completedRows,
1224
+ failedRows,
1225
+ totalRows,
1226
+ hasRowFailures: failedRows > 0
1227
+ };
1228
+ }
1205
1229
  function createEmptyPlayRunLedgerSnapshot(input) {
1206
1230
  const status = normalizePlayRunLedgerStatus(input.status ?? "unknown");
1207
1231
  const startedAt = finiteNumber(input.startedAt) ?? null;
@@ -1421,9 +1445,11 @@ function buildSnapshotFromLedger(snapshot) {
1421
1445
  completedAt: step.completedAt ?? null,
1422
1446
  updatedAt: step.updatedAt ?? null
1423
1447
  }));
1448
+ const liveStatus = normalizePlayRunLiveStatus(snapshot.status);
1449
+ const rowOutcomes = isTerminalPlayRunLiveStatus(liveStatus) && Object.keys(snapshot.stepsById).length > 0 ? summarizeRunRowOutcomes(snapshot) : null;
1424
1450
  return {
1425
1451
  runId: snapshot.runId,
1426
- status: normalizePlayRunLiveStatus(snapshot.status),
1452
+ status: liveStatus,
1427
1453
  createdAt: snapshot.createdAt ?? null,
1428
1454
  startedAt: snapshot.startedAt ?? null,
1429
1455
  finishedAt: snapshot.finishedAt ?? null,
@@ -1435,7 +1461,8 @@ function buildSnapshotFromLedger(snapshot) {
1435
1461
  activeArtifactTableNamespace: snapshot.activeArtifactTableNamespace ?? null,
1436
1462
  resultTableNamespace: snapshot.resultTableNamespace ?? null,
1437
1463
  nodeStates,
1438
- activeNodeId: snapshot.activeStepId ?? null
1464
+ activeNodeId: snapshot.activeStepId ?? null,
1465
+ ...rowOutcomes ? { rowOutcomes } : {}
1439
1466
  };
1440
1467
  }
1441
1468
  function buildPlayRunStatusSnapshot(input) {
package/dist/index.mjs CHANGED
@@ -352,10 +352,10 @@ var SDK_RELEASE = {
352
352
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
353
353
  // fields shipped in 0.1.153.
354
354
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
355
- version: "0.1.207",
355
+ version: "0.1.209",
356
356
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
357
357
  supportPolicy: {
358
- latest: "0.1.207",
358
+ latest: "0.1.209",
359
359
  minimumSupported: "0.1.53",
360
360
  deprecatedBelow: "0.1.53",
361
361
  commandMinimumSupported: [
@@ -511,6 +511,7 @@ var COORDINATOR_INTERNAL_TOKEN_HEADER = "x-deepline-internal-token";
511
511
  var COORDINATOR_URL_OVERRIDE_HEADER = "x-deepline-coordinator-url";
512
512
  var WORKER_CALLBACK_URL_OVERRIDE_HEADER = "x-deepline-worker-callback-url";
513
513
  var RUNTIME_SCHEDULER_SCHEMA_OVERRIDE_HEADER = "x-deepline-runtime-scheduler-schema";
514
+ var ABSURD_RELEASE_OVERRIDE_HEADER = "x-deepline-absurd-release";
514
515
  var SYNTHETIC_RUN_HEADER = "x-deepline-synthetic-run";
515
516
 
516
517
  // ../shared_libs/play-runtime/test-runtime-seams.ts
@@ -632,6 +633,7 @@ var HttpClient = class {
632
633
  }
633
634
  const coordinatorUrl = typeof process !== "undefined" ? process.env?.DEEPLINE_COORDINATOR_URL : void 0;
634
635
  const coordinatorInternalToken = typeof process !== "undefined" ? process.env?.DEEPLINE_INTERNAL_TOKEN : void 0;
636
+ const absurdReleaseOverride = typeof process !== "undefined" ? process.env?.DEEPLINE_ABSURD_RELEASE : void 0;
635
637
  if (coordinatorUrl?.trim()) {
636
638
  headers[COORDINATOR_URL_OVERRIDE_HEADER] = coordinatorUrl.trim();
637
639
  }
@@ -651,7 +653,10 @@ var HttpClient = class {
651
653
  if (runtimeTestFault?.trim()) {
652
654
  headers[PLAY_RUNTIME_TEST_FAULT_HEADER] = runtimeTestFault.trim();
653
655
  }
654
- if (coordinatorInternalToken?.trim() && (coordinatorUrl?.trim() || workerCallbackUrl?.trim() || runtimeTestFault?.trim())) {
656
+ if (absurdReleaseOverride?.trim() && coordinatorInternalToken?.trim()) {
657
+ headers[ABSURD_RELEASE_OVERRIDE_HEADER] = absurdReleaseOverride.trim();
658
+ }
659
+ if (coordinatorInternalToken?.trim() && (coordinatorUrl?.trim() || workerCallbackUrl?.trim() || runtimeTestFault?.trim() || absurdReleaseOverride?.trim())) {
655
660
  headers[COORDINATOR_INTERNAL_TOKEN_HEADER] = coordinatorInternalToken.trim();
656
661
  }
657
662
  return headers;
@@ -1132,6 +1137,25 @@ function normalizePlayRunLedgerStatus(value) {
1132
1137
  return "unknown";
1133
1138
  }
1134
1139
  }
1140
+ function summarizeRunRowOutcomes(snapshot) {
1141
+ let completedRows = 0;
1142
+ let failedRows = 0;
1143
+ let totalRows = 0;
1144
+ for (const step of Object.values(snapshot.stepsById)) {
1145
+ const progress = step.progress;
1146
+ if (!progress) continue;
1147
+ completedRows += Math.max(0, finiteNumber(progress.completed) ?? 0);
1148
+ failedRows += Math.max(0, finiteNumber(progress.failed) ?? 0);
1149
+ const stepTotal = finiteNumber(progress.total);
1150
+ totalRows += stepTotal !== null && stepTotal >= 0 ? stepTotal : Math.max(0, finiteNumber(progress.completed) ?? 0) + Math.max(0, finiteNumber(progress.failed) ?? 0);
1151
+ }
1152
+ return {
1153
+ completedRows,
1154
+ failedRows,
1155
+ totalRows,
1156
+ hasRowFailures: failedRows > 0
1157
+ };
1158
+ }
1135
1159
  function createEmptyPlayRunLedgerSnapshot(input) {
1136
1160
  const status = normalizePlayRunLedgerStatus(input.status ?? "unknown");
1137
1161
  const startedAt = finiteNumber(input.startedAt) ?? null;
@@ -1351,9 +1375,11 @@ function buildSnapshotFromLedger(snapshot) {
1351
1375
  completedAt: step.completedAt ?? null,
1352
1376
  updatedAt: step.updatedAt ?? null
1353
1377
  }));
1378
+ const liveStatus = normalizePlayRunLiveStatus(snapshot.status);
1379
+ const rowOutcomes = isTerminalPlayRunLiveStatus(liveStatus) && Object.keys(snapshot.stepsById).length > 0 ? summarizeRunRowOutcomes(snapshot) : null;
1354
1380
  return {
1355
1381
  runId: snapshot.runId,
1356
- status: normalizePlayRunLiveStatus(snapshot.status),
1382
+ status: liveStatus,
1357
1383
  createdAt: snapshot.createdAt ?? null,
1358
1384
  startedAt: snapshot.startedAt ?? null,
1359
1385
  finishedAt: snapshot.finishedAt ?? null,
@@ -1365,7 +1391,8 @@ function buildSnapshotFromLedger(snapshot) {
1365
1391
  activeArtifactTableNamespace: snapshot.activeArtifactTableNamespace ?? null,
1366
1392
  resultTableNamespace: snapshot.resultTableNamespace ?? null,
1367
1393
  nodeStates,
1368
- activeNodeId: snapshot.activeStepId ?? null
1394
+ activeNodeId: snapshot.activeStepId ?? null,
1395
+ ...rowOutcomes ? { rowOutcomes } : {}
1369
1396
  };
1370
1397
  }
1371
1398
  function buildPlayRunStatusSnapshot(input) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepline",
3
- "version": "0.1.207",
3
+ "version": "0.1.209",
4
4
  "description": "Deepline SDK + CLI — B2B data enrichment powered by durable cloud execution",
5
5
  "license": "MIT",
6
6
  "repository": {