deepline 0.1.187 → 0.1.188

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.
@@ -168,6 +168,10 @@ import {
168
168
  WorkerRunWorkDispatcher,
169
169
  type WorkerRunMapBatchesResult,
170
170
  } from './runtime/run-work-dispatcher';
171
+ import {
172
+ boundedWorkflowPreviewRows,
173
+ WORKFLOW_MAP_CHUNK_PREVIEW_MAX_BYTES,
174
+ } from './runtime/workflow-preview';
171
175
  import { WORKER_PLATFORM_SUBREQUESTS_PER_UNBATCHED_TOOL_CALL } from './runtime/worker-platform-budget';
172
176
  import {
173
177
  PLAY_RUNTIME_CONTRACT,
@@ -252,6 +256,7 @@ import { normalizePlayRunFailure } from '../../../shared_libs/play-runtime/run-f
252
256
  import {
253
257
  createRuntimePersistenceLatch,
254
258
  isRuntimePersistenceCircuitOpenError,
259
+ RuntimePersistenceCircuitOpenError,
255
260
  tripRuntimePersistenceLatch,
256
261
  } from '../../../shared_libs/play-runtime/persistence-latch';
257
262
  import {
@@ -2420,7 +2425,8 @@ type WorkerMapBlockedChunkSummary = {
2420
2425
  };
2421
2426
 
2422
2427
  type WorkerMapChunkSummary<T extends Record<string, unknown>> =
2423
- WorkerMapCompletedChunkSummary<T> | WorkerMapBlockedChunkSummary;
2428
+ | WorkerMapCompletedChunkSummary<T>
2429
+ | WorkerMapBlockedChunkSummary;
2424
2430
 
2425
2431
  function serializeDurableStepValue<T>(value: T, depth = 0): T {
2426
2432
  if (depth > 20 || value == null) return value;
@@ -2479,7 +2485,9 @@ type WorkerConditionalStepResolver = {
2479
2485
  type WorkerStepProgramStep = {
2480
2486
  name: string;
2481
2487
  resolver:
2482
- WorkerStepResolver | WorkerConditionalStepResolver | WorkerStepProgram;
2488
+ | WorkerStepResolver
2489
+ | WorkerConditionalStepResolver
2490
+ | WorkerStepProgram;
2483
2491
  };
2484
2492
 
2485
2493
  type WorkerStepProgram = {
@@ -3416,7 +3424,9 @@ function resolveSheetContractFromReq(
3416
3424
  // `staticPipeline` field is what `resolveSheetContractForTableNamespace`
3417
3425
  // expects. Reach in safely.
3418
3426
  const snapshot = req.contractSnapshot as
3419
- { staticPipeline?: unknown } | undefined | null;
3427
+ | { staticPipeline?: unknown }
3428
+ | undefined
3429
+ | null;
3420
3430
  const pipeline = snapshot?.staticPipeline;
3421
3431
  if (!pipeline || typeof pipeline !== 'object' || Array.isArray(pipeline)) {
3422
3432
  return null;
@@ -3508,7 +3518,9 @@ async function releaseRuntimeLeasesOnTeardown(input: {
3508
3518
 
3509
3519
  function staticPipelineFromReq(req: RunRequest): PlayStaticPipeline | null {
3510
3520
  const snapshot = req.contractSnapshot as
3511
- { staticPipeline?: unknown } | undefined | null;
3521
+ | { staticPipeline?: unknown }
3522
+ | undefined
3523
+ | null;
3512
3524
  const pipeline = snapshot?.staticPipeline;
3513
3525
  if (!pipeline || typeof pipeline !== 'object' || Array.isArray(pipeline)) {
3514
3526
  return null;
@@ -5100,6 +5112,15 @@ function createMinimalWorkerCtx(
5100
5112
  }
5101
5113
  };
5102
5114
 
5115
+ const runtimePersistenceCircuitError = (): Error | null => {
5116
+ if (persistFailure) {
5117
+ tripRuntimePersistenceLatch(persistenceLatch, persistFailure);
5118
+ }
5119
+ return persistenceLatch.tripped
5120
+ ? new RuntimePersistenceCircuitOpenError(persistenceLatch)
5121
+ : null;
5122
+ };
5123
+
5103
5124
  const persistExecutedRows = async () => {
5104
5125
  const rowsToPersist = executedRows
5105
5126
  .map((row, executedIndex) =>
@@ -5207,11 +5228,13 @@ function createMinimalWorkerCtx(
5207
5228
  pendingPersistRows = 0;
5208
5229
  pendingPersistBytes = 0;
5209
5230
  const task = persistFlushChain.then(async () => {
5210
- if (persistFailure) throw persistFailure;
5231
+ const circuitError = runtimePersistenceCircuitError();
5232
+ if (circuitError) throw circuitError;
5211
5233
  await persistExecutedRows();
5212
5234
  });
5213
5235
  persistFlushChain = task.catch((error) => {
5214
5236
  persistFailure ??= error;
5237
+ tripRuntimePersistenceLatch(persistenceLatch, error);
5215
5238
  });
5216
5239
  return task;
5217
5240
  };
@@ -5296,26 +5319,31 @@ function createMinimalWorkerCtx(
5296
5319
  return Promise.resolve();
5297
5320
  };
5298
5321
 
5299
- const schedulePersistExecutedRows = () => {
5300
- if (persistFailure) return;
5322
+ const schedulePersistExecutedRows = (): Promise<void> | null => {
5323
+ const circuitError = runtimePersistenceCircuitError();
5324
+ if (circuitError) return Promise.reject(circuitError);
5301
5325
  if (
5302
5326
  pendingPersistRows >= MAP_INCREMENTAL_PERSIST_CHUNK_ROWS ||
5303
5327
  pendingPersistBytes >= MAP_INCREMENTAL_PERSIST_CHUNK_BYTES
5304
5328
  ) {
5305
- void enqueuePersistExecutedRows().catch(() => undefined);
5306
- return;
5329
+ return enqueuePersistExecutedRows();
5307
5330
  }
5308
- if (scheduledPersistTimer) return;
5331
+ if (scheduledPersistTimer) return null;
5309
5332
  scheduledPersistTimer = setTimeout(() => {
5310
5333
  scheduledPersistTimer = null;
5311
5334
  void enqueuePersistExecutedRows().catch(() => undefined);
5312
5335
  }, MAP_INCREMENTAL_PERSIST_INTERVAL_MS);
5336
+ return null;
5313
5337
  };
5314
5338
 
5315
- const notePersistableRow = (row: Record<string, unknown>) => {
5339
+ const notePersistableRow = async (
5340
+ row: Record<string, unknown>,
5341
+ ): Promise<void> => {
5316
5342
  pendingPersistRows += 1;
5317
5343
  pendingPersistBytes += JSON.stringify(row).length;
5318
- schedulePersistExecutedRows();
5344
+ await (schedulePersistExecutedRows() ?? Promise.resolve());
5345
+ const circuitError = runtimePersistenceCircuitError();
5346
+ if (circuitError) throw circuitError;
5319
5347
  };
5320
5348
 
5321
5349
  let idx = 0;
@@ -5325,6 +5353,8 @@ function createMinimalWorkerCtx(
5325
5353
  (async () => {
5326
5354
  while (true) {
5327
5355
  if (abortSignal?.aborted) return;
5356
+ const circuitError = runtimePersistenceCircuitError();
5357
+ if (circuitError) throw circuitError;
5328
5358
  const myIndex = idx++;
5329
5359
  if (myIndex >= rowsToExecute.length) return;
5330
5360
  const rowSlot = await governor.acquireRowSlot({
@@ -5472,7 +5502,7 @@ function createMinimalWorkerCtx(
5472
5502
  executedRows[myIndex] = enriched as T &
5473
5503
  Record<string, unknown>;
5474
5504
  completedExecutedRows += 1;
5475
- notePersistableRow(enriched);
5505
+ await notePersistableRow(enriched);
5476
5506
  reportChunkProgress(false);
5477
5507
  } catch (rowError) {
5478
5508
  // Receipt persistence errors stay run-fatal, but keep the
@@ -5522,7 +5552,7 @@ function createMinimalWorkerCtx(
5522
5552
  };
5523
5553
  failedExecutedRows += 1;
5524
5554
  if (!failFastRowErrors) {
5525
- notePersistableRow(enriched);
5555
+ await notePersistableRow(enriched);
5526
5556
  }
5527
5557
  // Bounded per-chunk samples: every failure is persisted on
5528
5558
  // its row, but only the first few get a log line so a wide
@@ -5636,7 +5666,8 @@ function createMinimalWorkerCtx(
5636
5666
  rangeStart: baseOffset + chunkStart,
5637
5667
  rangeEnd: baseOffset + chunkStart,
5638
5668
  rowsRead: chunkRows.length,
5639
- rowsWritten: 0,
5669
+ rowsWritten:
5670
+ persistedExecutedIndexes.size + persistedFailedIndexes.size,
5640
5671
  rowsExecuted: rowsToExecute.length,
5641
5672
  rowsCached: 0,
5642
5673
  rowsDuplicateReused: duplicateInputReuseCount,
@@ -5867,7 +5898,11 @@ function createMinimalWorkerCtx(
5867
5898
  // storage may keep only the bounded preview sample; same-run play code
5868
5899
  // that needs more rows uses volatileWorkflowChunkRows, which is not
5869
5900
  // part of the persisted step result.
5870
- preview: toWorkflowSerializableValue(publicOut.slice(0, 5)),
5901
+ preview: boundedWorkflowPreviewRows(publicOut, {
5902
+ maxRows: WORKER_DATASET_PREVIEW_ROWS,
5903
+ maxBytes: WORKFLOW_MAP_CHUNK_PREVIEW_MAX_BYTES,
5904
+ serialize: toWorkflowSerializableValue,
5905
+ }),
5871
5906
  cachedRows:
5872
5907
  includeCachedRowsInChunkResult &&
5873
5908
  out.length <= WORKER_DATASET_IN_MEMORY_ROWS
@@ -6993,7 +7028,8 @@ function createMinimalWorkerCtx(
6993
7028
  // the small structural shape ChildPlayAwait needs; bridge it the
6994
7029
  // same way the inline implementation did.
6995
7030
  workflowStep: workflowStep as unknown as
6996
- WorkflowStepLike | undefined,
7031
+ | WorkflowStepLike
7032
+ | undefined,
6997
7033
  workflowId,
6998
7034
  playName: resolvedName,
6999
7035
  key: normalizedKey,
@@ -0,0 +1,26 @@
1
+ export const WORKFLOW_MAP_CHUNK_PREVIEW_MAX_BYTES = 64 * 1024;
2
+
3
+ const jsonByteLength = (value: unknown): number =>
4
+ new TextEncoder().encode(JSON.stringify(value)).byteLength;
5
+
6
+ export function boundedWorkflowPreviewRows<T extends Record<string, unknown>>(
7
+ rows: readonly T[],
8
+ input: {
9
+ maxRows: number;
10
+ maxBytes: number;
11
+ serialize?: (row: T) => T;
12
+ },
13
+ ): T[] {
14
+ const preview: T[] = [];
15
+ let bytes = 2; // Opening and closing array brackets.
16
+ for (const row of rows) {
17
+ if (preview.length >= input.maxRows) break;
18
+ const serialized = input.serialize ? input.serialize(row) : row;
19
+ const rowBytes = jsonByteLength(serialized) + (preview.length > 0 ? 1 : 0);
20
+ if (rowBytes > input.maxBytes) continue;
21
+ if (bytes + rowBytes > input.maxBytes) break;
22
+ preview.push(serialized);
23
+ bytes += rowBytes;
24
+ }
25
+ return preview;
26
+ }
@@ -105,10 +105,10 @@ export const SDK_RELEASE = {
105
105
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
106
106
  // fields shipped in 0.1.153.
107
107
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
108
- version: '0.1.187',
108
+ version: '0.1.188',
109
109
  apiContract: '2026-06-dataset-handle-results-hard-cutover',
110
110
  supportPolicy: {
111
- latest: '0.1.187',
111
+ latest: '0.1.188',
112
112
  minimumSupported: '0.1.53',
113
113
  deprecatedBelow: '0.1.53',
114
114
  commandMinimumSupported: [
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.187",
626
+ version: "0.1.188",
627
627
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
628
628
  supportPolicy: {
629
- latest: "0.1.187",
629
+ latest: "0.1.188",
630
630
  minimumSupported: "0.1.53",
631
631
  deprecatedBelow: "0.1.53",
632
632
  commandMinimumSupported: [
@@ -17587,11 +17587,12 @@ function helperSource() {
17587
17587
 
17588
17588
  // src/cli/commands/enrich.ts
17589
17589
  var ENRICH_EXPORT_PAGE_SIZE = 5e3;
17590
- var ENRICH_AUTO_BATCH_ROWS = 250;
17590
+ var ENRICH_AUTO_BATCH_ROWS = 200;
17591
17591
  var ENRICH_HEAVY_PLAY_AUTO_BATCH_ROWS = 25;
17592
17592
  var ENRICH_NESTED_PROVIDER_AUTO_BATCH_ROWS = 50;
17593
17593
  var ENRICH_EXPORT_BACKING_ROWS_WAIT_MS = 6e4;
17594
17594
  var ENRICH_EXPORT_BACKING_ROWS_POLL_MS = 1e3;
17595
+ var ENRICH_CUSTOMER_DB_FAILURE_LOOKUP_RETRY_DELAYS_MS = [1e3, 3e3, 7e3];
17595
17596
  var ENRICH_SOURCE_ROW_INDEX_COLUMN = "__deeplineSourceRowIndex";
17596
17597
  var ENRICH_ORIGINAL_SOURCE_ROW_INDEX_COLUMN = "__deeplineOriginalSourceRowIndex";
17597
17598
  var ENRICH_CELL_META_FIELD = "__deeplineCellMeta";
@@ -17742,6 +17743,13 @@ function enrichExportBackingRowsWaitMs() {
17742
17743
  const parsed = Number.parseInt(raw, 10);
17743
17744
  return Number.isFinite(parsed) && parsed >= 0 ? parsed : ENRICH_EXPORT_BACKING_ROWS_WAIT_MS;
17744
17745
  }
17746
+ function enrichCustomerDbFailureLookupRetryDelaysMs() {
17747
+ const raw = process.env.DEEPLINE_ENRICH_CUSTOMER_DB_LOOKUP_RETRY_DELAYS_MS?.trim();
17748
+ if (!raw) {
17749
+ return ENRICH_CUSTOMER_DB_FAILURE_LOOKUP_RETRY_DELAYS_MS;
17750
+ }
17751
+ return raw.split(",").map((part) => Number.parseInt(part.trim(), 10)).filter((value) => Number.isFinite(value) && value >= 0);
17752
+ }
17745
17753
  function emitEnrichDebugValidationLines(config) {
17746
17754
  for (const line of buildEnrichDebugValidationLines(config)) {
17747
17755
  emitEnrichDebug(line);
@@ -18682,13 +18690,71 @@ function failureAliasFromCellMeta(cellMeta) {
18682
18690
  }
18683
18691
  return null;
18684
18692
  }
18693
+ function formatEnrichDiagnosticError(error) {
18694
+ if (error instanceof DeeplineError) {
18695
+ const status = error.statusCode ? `HTTP ${error.statusCode}: ` : "";
18696
+ const code = error.code && error.code !== "API_ERROR" ? ` [${error.code}]` : "";
18697
+ return `${status}${error.message}${code}`;
18698
+ }
18699
+ return error instanceof Error ? error.message : String(error);
18700
+ }
18701
+ function isRetryableCustomerDbLookupError(error) {
18702
+ if (error instanceof DeeplineError) {
18703
+ const status = error.statusCode;
18704
+ if (status === 408 || status === 425 || status === 429 || status === 503 || typeof status === "number" && status >= 500) {
18705
+ return true;
18706
+ }
18707
+ if (error.code === "NETWORK_TIMEOUT" || error.code === "NETWORK_ABORTED" || error.code === "NETWORK_ERROR" || error.code === "42P01") {
18708
+ return true;
18709
+ }
18710
+ }
18711
+ const message = error instanceof Error ? error.message : String(error);
18712
+ return /Internal Server Error|fetch failed|ECONNRESET|ETIMEDOUT|timed out after \d+ms while waiting for a response|Unable to connect|relation .* does not exist|Neon API request failed \(404\)|ingestion plane .*not ready/i.test(
18713
+ message
18714
+ );
18715
+ }
18716
+ function customerDbLookupUnavailableIssue(input2) {
18717
+ const command = input2.customerDb.command ?? (input2.customerDb.sql ? `deepline db query --sql ${shellSingleQuote2(input2.customerDb.sql)} --json` : void 0);
18718
+ return {
18719
+ issue_id: `customer-db-failure-lookup-${input2.customerDb.runId ?? "run"}`,
18720
+ kind: "customer_db_lookup_unavailable",
18721
+ severity: "needs_attention",
18722
+ message: "Enrich completed, but Deepline could not inspect the Customer DB backing table for failed row details yet.",
18723
+ next_steps: [
18724
+ "Use the Customer DB query command below to inspect the durable rows after the data plane settles.",
18725
+ "If the command keeps failing, inspect the run output and runtime sheet export instead of rerunning provider enrichments blindly."
18726
+ ],
18727
+ follow_up_commands: command ? [
18728
+ {
18729
+ label: "query customer db",
18730
+ command,
18731
+ path: input2.customerDb.datasetPath
18732
+ }
18733
+ ] : [],
18734
+ ...input2.customerDb.runId ? { run_id: input2.customerDb.runId } : {},
18735
+ error: formatEnrichDiagnosticError(input2.error),
18736
+ attempts: input2.attempts
18737
+ };
18738
+ }
18739
+ function emitCustomerDbLookupUnavailableWarning(issue) {
18740
+ process.stderr.write(`Warning: ${issue.message}
18741
+ `);
18742
+ if (issue.error) {
18743
+ process.stderr.write(`Warning detail: ${issue.error}
18744
+ `);
18745
+ }
18746
+ for (const command of issue.follow_up_commands) {
18747
+ process.stderr.write(`Command: ${command.label}: ${command.command}
18748
+ `);
18749
+ }
18750
+ }
18685
18751
  async function collectCustomerDbFailureJobs(input2) {
18686
18752
  const customerDb = enrichCustomerDbJson({
18687
18753
  status: input2.status,
18688
18754
  client: input2.client
18689
18755
  });
18690
18756
  if (!customerDb?.runId || !customerDb.sqlQualifiedTableName) {
18691
- return [];
18757
+ return { jobs: [], issue: null };
18692
18758
  }
18693
18759
  const fallbackAliases = collectHardFailureAliasSpecs(input2.config);
18694
18760
  const fallbackAlias = fallbackAliases[0]?.alias ?? "enrich";
@@ -18696,16 +18762,49 @@ async function collectCustomerDbFailureJobs(input2) {
18696
18762
  fallbackAliases.map((spec, index) => [normalizeAlias2(spec.alias), index])
18697
18763
  );
18698
18764
  const sql = `select _input_index, _status, _error, _cell_meta from ${customerDb.sqlQualifiedTableName} where _run_id = ${sqlStringLiteral(customerDb.runId)} and (_error is not null or lower(coalesce(_status, '')) in ('failed', 'error')) order by _input_index limit 1000`;
18699
- const result = await input2.client.queryCustomerDb({
18700
- sql,
18701
- maxRows: 1e3
18702
- });
18765
+ const retryDelays = enrichCustomerDbFailureLookupRetryDelaysMs();
18766
+ let lastError = null;
18767
+ let attempts = 0;
18768
+ let result = null;
18769
+ for (let attempt = 0; attempt <= retryDelays.length; attempt += 1) {
18770
+ try {
18771
+ attempts = attempt + 1;
18772
+ result = await input2.client.queryCustomerDb({
18773
+ sql,
18774
+ maxRows: 1e3
18775
+ });
18776
+ lastError = null;
18777
+ break;
18778
+ } catch (error) {
18779
+ lastError = error;
18780
+ if (attempt >= retryDelays.length || !isRetryableCustomerDbLookupError(error)) {
18781
+ break;
18782
+ }
18783
+ const delayMs = retryDelays[attempt] ?? 0;
18784
+ emitEnrichDebug(
18785
+ `customer_db failure lookup retrying after ${delayMs}ms: ${formatEnrichDiagnosticError(error)}`
18786
+ );
18787
+ if (delayMs > 0) {
18788
+ await sleep6(delayMs);
18789
+ }
18790
+ }
18791
+ }
18792
+ if (!result) {
18793
+ return {
18794
+ jobs: [],
18795
+ issue: customerDbLookupUnavailableIssue({
18796
+ customerDb,
18797
+ error: lastError,
18798
+ attempts
18799
+ })
18800
+ };
18801
+ }
18703
18802
  const rows = Array.isArray(result.rows) ? result.rows : [];
18704
18803
  const failedRows = rows.filter((row) => {
18705
18804
  const status = typeof row._status === "string" ? row._status.trim().toLowerCase() : "";
18706
18805
  return typeof row._error === "string" && row._error.trim() || status === "failed" || status === "error";
18707
18806
  });
18708
- return failedRows.map((row, index) => {
18807
+ const jobs = failedRows.map((row, index) => {
18709
18808
  const metaFailure = failureAliasFromCellMeta(row._cell_meta);
18710
18809
  const alias = metaFailure?.alias ?? fallbackAlias;
18711
18810
  const normalizedAlias = normalizeAlias2(alias);
@@ -18729,6 +18828,7 @@ async function collectCustomerDbFailureJobs(input2) {
18729
18828
  ...metaFailure?.provider ? { provider: metaFailure.provider } : {}
18730
18829
  };
18731
18830
  });
18831
+ return { jobs, issue: null };
18732
18832
  }
18733
18833
  async function buildEnrichFailureReport(input2) {
18734
18834
  const fallbackRowsInfo = input2.exportResult ? null : extractCanonicalRowsInfo(input2.status);
@@ -19256,9 +19356,7 @@ function collectWaterfallAliasSpecs(config) {
19256
19356
  alias,
19257
19357
  childAliases: activeChildren.map((child) => child.alias).filter(Boolean),
19258
19358
  childRunIfJsByAlias: new Map(
19259
- activeChildren.map(
19260
- (child) => [child.alias, child.run_if_js]
19261
- )
19359
+ activeChildren.map((child) => [child.alias, child.run_if_js])
19262
19360
  ),
19263
19361
  childToolsByAlias: new Map(
19264
19362
  activeChildren.map(
@@ -20034,21 +20132,26 @@ async function maybeEmitEnrichFailureReport(input2) {
20034
20132
  status: input2.status,
20035
20133
  rowRange: input2.statusRowRange ?? input2.rowRange
20036
20134
  });
20037
- const customerDbJobs = input2.status === void 0 || rowJobs.length > 0 || statusJobs.length > 0 ? [] : await collectCustomerDbFailureJobs({
20135
+ const customerDbDiagnostics = input2.status === void 0 || rowJobs.length > 0 || statusJobs.length > 0 ? { jobs: [], issue: null } : await collectCustomerDbFailureJobs({
20038
20136
  client: input2.client,
20039
20137
  status: input2.status,
20040
20138
  config: input2.config
20041
20139
  });
20140
+ const customerDbJobs = customerDbDiagnostics.jobs;
20141
+ if (customerDbDiagnostics.issue) {
20142
+ emitCustomerDbLookupUnavailableWarning(customerDbDiagnostics.issue);
20143
+ }
20144
+ const allEnrichIssues = enrichIssues;
20042
20145
  const jobs = rowJobs.length > 0 || statusJobs.length > 0 || customerDbJobs.length > 0 || input2.status === void 0 ? mergeEnrichFailureJobs(
20043
20146
  mergeEnrichFailureJobs(rowJobs, statusJobs),
20044
20147
  customerDbJobs
20045
20148
  ) : [];
20046
- if (jobs.length === 0 && enrichIssues.length === 0) {
20149
+ if (jobs.length === 0 && allEnrichIssues.length === 0) {
20047
20150
  return null;
20048
20151
  }
20049
20152
  const reportPath = await persistEnrichFailureReport({
20050
20153
  jobs,
20051
- issues: enrichIssues,
20154
+ issues: allEnrichIssues,
20052
20155
  apiUrl: input2.client.baseUrl,
20053
20156
  outputPath: input2.outputPath,
20054
20157
  rows: input2.rowRange
@@ -20068,13 +20171,13 @@ async function maybeEmitEnrichFailureReport(input2) {
20068
20171
  `);
20069
20172
  }
20070
20173
  }
20071
- if (enrichIssues.length > 0) {
20174
+ if (allEnrichIssues.length > 0) {
20072
20175
  process.stderr.write("Enrichment needs attention.\n");
20073
20176
  process.stderr.write("Issue preview (up to 5 enrichment issues):\n");
20074
20177
  process.stderr.write(
20075
20178
  "issue_id column severity selected_rows rows_with_value message\n"
20076
20179
  );
20077
- for (const issue of enrichIssues.slice(0, 5)) {
20180
+ for (const issue of allEnrichIssues.slice(0, 5)) {
20078
20181
  process.stderr.write(
20079
20182
  `${issue.issue_id} ${issue.column} ${issue.severity} ${issue.selected_rows} ${issue.rows_with_value} ${issue.message}
20080
20183
  `
@@ -20088,9 +20191,9 @@ async function maybeEmitEnrichFailureReport(input2) {
20088
20191
  `);
20089
20192
  }
20090
20193
  }
20091
- if (enrichIssues.length > 5) {
20194
+ if (allEnrichIssues.length > 5) {
20092
20195
  process.stderr.write(
20093
- `Showing 5 of ${enrichIssues.length} enrichment issues.
20196
+ `Showing 5 of ${allEnrichIssues.length} enrichment issues.
20094
20197
  `
20095
20198
  );
20096
20199
  }
@@ -20108,12 +20211,12 @@ async function maybeEmitEnrichFailureReport(input2) {
20108
20211
  process.stderr.write(
20109
20212
  jobs.length > 0 ? "Enrichment failed. See report above.\n" : "Enrichment produced no values for at least one requested waterfall. See issue preview above.\n"
20110
20213
  );
20111
- return { path: reportPath, jobs, issues: enrichIssues };
20214
+ return { path: reportPath, jobs, issues: allEnrichIssues };
20112
20215
  }
20113
20216
  process.stderr.write(
20114
20217
  jobs.length > 0 ? "Enrichment failed.\n" : "Enrichment needs attention.\n"
20115
20218
  );
20116
- return { path: "", jobs, issues: enrichIssues };
20219
+ return { path: "", jobs, issues: allEnrichIssues };
20117
20220
  }
20118
20221
  function mergePreferredColumns(preferredColumns, rows) {
20119
20222
  const columns = [];
@@ -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.187",
611
+ version: "0.1.188",
612
612
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
613
613
  supportPolicy: {
614
- latest: "0.1.187",
614
+ latest: "0.1.188",
615
615
  minimumSupported: "0.1.53",
616
616
  deprecatedBelow: "0.1.53",
617
617
  commandMinimumSupported: [
@@ -17614,11 +17614,12 @@ function helperSource() {
17614
17614
 
17615
17615
  // src/cli/commands/enrich.ts
17616
17616
  var ENRICH_EXPORT_PAGE_SIZE = 5e3;
17617
- var ENRICH_AUTO_BATCH_ROWS = 250;
17617
+ var ENRICH_AUTO_BATCH_ROWS = 200;
17618
17618
  var ENRICH_HEAVY_PLAY_AUTO_BATCH_ROWS = 25;
17619
17619
  var ENRICH_NESTED_PROVIDER_AUTO_BATCH_ROWS = 50;
17620
17620
  var ENRICH_EXPORT_BACKING_ROWS_WAIT_MS = 6e4;
17621
17621
  var ENRICH_EXPORT_BACKING_ROWS_POLL_MS = 1e3;
17622
+ var ENRICH_CUSTOMER_DB_FAILURE_LOOKUP_RETRY_DELAYS_MS = [1e3, 3e3, 7e3];
17622
17623
  var ENRICH_SOURCE_ROW_INDEX_COLUMN = "__deeplineSourceRowIndex";
17623
17624
  var ENRICH_ORIGINAL_SOURCE_ROW_INDEX_COLUMN = "__deeplineOriginalSourceRowIndex";
17624
17625
  var ENRICH_CELL_META_FIELD = "__deeplineCellMeta";
@@ -17769,6 +17770,13 @@ function enrichExportBackingRowsWaitMs() {
17769
17770
  const parsed = Number.parseInt(raw, 10);
17770
17771
  return Number.isFinite(parsed) && parsed >= 0 ? parsed : ENRICH_EXPORT_BACKING_ROWS_WAIT_MS;
17771
17772
  }
17773
+ function enrichCustomerDbFailureLookupRetryDelaysMs() {
17774
+ const raw = process.env.DEEPLINE_ENRICH_CUSTOMER_DB_LOOKUP_RETRY_DELAYS_MS?.trim();
17775
+ if (!raw) {
17776
+ return ENRICH_CUSTOMER_DB_FAILURE_LOOKUP_RETRY_DELAYS_MS;
17777
+ }
17778
+ return raw.split(",").map((part) => Number.parseInt(part.trim(), 10)).filter((value) => Number.isFinite(value) && value >= 0);
17779
+ }
17772
17780
  function emitEnrichDebugValidationLines(config) {
17773
17781
  for (const line of buildEnrichDebugValidationLines(config)) {
17774
17782
  emitEnrichDebug(line);
@@ -18709,13 +18717,71 @@ function failureAliasFromCellMeta(cellMeta) {
18709
18717
  }
18710
18718
  return null;
18711
18719
  }
18720
+ function formatEnrichDiagnosticError(error) {
18721
+ if (error instanceof DeeplineError) {
18722
+ const status = error.statusCode ? `HTTP ${error.statusCode}: ` : "";
18723
+ const code = error.code && error.code !== "API_ERROR" ? ` [${error.code}]` : "";
18724
+ return `${status}${error.message}${code}`;
18725
+ }
18726
+ return error instanceof Error ? error.message : String(error);
18727
+ }
18728
+ function isRetryableCustomerDbLookupError(error) {
18729
+ if (error instanceof DeeplineError) {
18730
+ const status = error.statusCode;
18731
+ if (status === 408 || status === 425 || status === 429 || status === 503 || typeof status === "number" && status >= 500) {
18732
+ return true;
18733
+ }
18734
+ if (error.code === "NETWORK_TIMEOUT" || error.code === "NETWORK_ABORTED" || error.code === "NETWORK_ERROR" || error.code === "42P01") {
18735
+ return true;
18736
+ }
18737
+ }
18738
+ const message = error instanceof Error ? error.message : String(error);
18739
+ return /Internal Server Error|fetch failed|ECONNRESET|ETIMEDOUT|timed out after \d+ms while waiting for a response|Unable to connect|relation .* does not exist|Neon API request failed \(404\)|ingestion plane .*not ready/i.test(
18740
+ message
18741
+ );
18742
+ }
18743
+ function customerDbLookupUnavailableIssue(input2) {
18744
+ const command = input2.customerDb.command ?? (input2.customerDb.sql ? `deepline db query --sql ${shellSingleQuote2(input2.customerDb.sql)} --json` : void 0);
18745
+ return {
18746
+ issue_id: `customer-db-failure-lookup-${input2.customerDb.runId ?? "run"}`,
18747
+ kind: "customer_db_lookup_unavailable",
18748
+ severity: "needs_attention",
18749
+ message: "Enrich completed, but Deepline could not inspect the Customer DB backing table for failed row details yet.",
18750
+ next_steps: [
18751
+ "Use the Customer DB query command below to inspect the durable rows after the data plane settles.",
18752
+ "If the command keeps failing, inspect the run output and runtime sheet export instead of rerunning provider enrichments blindly."
18753
+ ],
18754
+ follow_up_commands: command ? [
18755
+ {
18756
+ label: "query customer db",
18757
+ command,
18758
+ path: input2.customerDb.datasetPath
18759
+ }
18760
+ ] : [],
18761
+ ...input2.customerDb.runId ? { run_id: input2.customerDb.runId } : {},
18762
+ error: formatEnrichDiagnosticError(input2.error),
18763
+ attempts: input2.attempts
18764
+ };
18765
+ }
18766
+ function emitCustomerDbLookupUnavailableWarning(issue) {
18767
+ process.stderr.write(`Warning: ${issue.message}
18768
+ `);
18769
+ if (issue.error) {
18770
+ process.stderr.write(`Warning detail: ${issue.error}
18771
+ `);
18772
+ }
18773
+ for (const command of issue.follow_up_commands) {
18774
+ process.stderr.write(`Command: ${command.label}: ${command.command}
18775
+ `);
18776
+ }
18777
+ }
18712
18778
  async function collectCustomerDbFailureJobs(input2) {
18713
18779
  const customerDb = enrichCustomerDbJson({
18714
18780
  status: input2.status,
18715
18781
  client: input2.client
18716
18782
  });
18717
18783
  if (!customerDb?.runId || !customerDb.sqlQualifiedTableName) {
18718
- return [];
18784
+ return { jobs: [], issue: null };
18719
18785
  }
18720
18786
  const fallbackAliases = collectHardFailureAliasSpecs(input2.config);
18721
18787
  const fallbackAlias = fallbackAliases[0]?.alias ?? "enrich";
@@ -18723,16 +18789,49 @@ async function collectCustomerDbFailureJobs(input2) {
18723
18789
  fallbackAliases.map((spec, index) => [normalizeAlias2(spec.alias), index])
18724
18790
  );
18725
18791
  const sql = `select _input_index, _status, _error, _cell_meta from ${customerDb.sqlQualifiedTableName} where _run_id = ${sqlStringLiteral(customerDb.runId)} and (_error is not null or lower(coalesce(_status, '')) in ('failed', 'error')) order by _input_index limit 1000`;
18726
- const result = await input2.client.queryCustomerDb({
18727
- sql,
18728
- maxRows: 1e3
18729
- });
18792
+ const retryDelays = enrichCustomerDbFailureLookupRetryDelaysMs();
18793
+ let lastError = null;
18794
+ let attempts = 0;
18795
+ let result = null;
18796
+ for (let attempt = 0; attempt <= retryDelays.length; attempt += 1) {
18797
+ try {
18798
+ attempts = attempt + 1;
18799
+ result = await input2.client.queryCustomerDb({
18800
+ sql,
18801
+ maxRows: 1e3
18802
+ });
18803
+ lastError = null;
18804
+ break;
18805
+ } catch (error) {
18806
+ lastError = error;
18807
+ if (attempt >= retryDelays.length || !isRetryableCustomerDbLookupError(error)) {
18808
+ break;
18809
+ }
18810
+ const delayMs = retryDelays[attempt] ?? 0;
18811
+ emitEnrichDebug(
18812
+ `customer_db failure lookup retrying after ${delayMs}ms: ${formatEnrichDiagnosticError(error)}`
18813
+ );
18814
+ if (delayMs > 0) {
18815
+ await sleep6(delayMs);
18816
+ }
18817
+ }
18818
+ }
18819
+ if (!result) {
18820
+ return {
18821
+ jobs: [],
18822
+ issue: customerDbLookupUnavailableIssue({
18823
+ customerDb,
18824
+ error: lastError,
18825
+ attempts
18826
+ })
18827
+ };
18828
+ }
18730
18829
  const rows = Array.isArray(result.rows) ? result.rows : [];
18731
18830
  const failedRows = rows.filter((row) => {
18732
18831
  const status = typeof row._status === "string" ? row._status.trim().toLowerCase() : "";
18733
18832
  return typeof row._error === "string" && row._error.trim() || status === "failed" || status === "error";
18734
18833
  });
18735
- return failedRows.map((row, index) => {
18834
+ const jobs = failedRows.map((row, index) => {
18736
18835
  const metaFailure = failureAliasFromCellMeta(row._cell_meta);
18737
18836
  const alias = metaFailure?.alias ?? fallbackAlias;
18738
18837
  const normalizedAlias = normalizeAlias2(alias);
@@ -18756,6 +18855,7 @@ async function collectCustomerDbFailureJobs(input2) {
18756
18855
  ...metaFailure?.provider ? { provider: metaFailure.provider } : {}
18757
18856
  };
18758
18857
  });
18858
+ return { jobs, issue: null };
18759
18859
  }
18760
18860
  async function buildEnrichFailureReport(input2) {
18761
18861
  const fallbackRowsInfo = input2.exportResult ? null : extractCanonicalRowsInfo(input2.status);
@@ -19283,9 +19383,7 @@ function collectWaterfallAliasSpecs(config) {
19283
19383
  alias,
19284
19384
  childAliases: activeChildren.map((child) => child.alias).filter(Boolean),
19285
19385
  childRunIfJsByAlias: new Map(
19286
- activeChildren.map(
19287
- (child) => [child.alias, child.run_if_js]
19288
- )
19386
+ activeChildren.map((child) => [child.alias, child.run_if_js])
19289
19387
  ),
19290
19388
  childToolsByAlias: new Map(
19291
19389
  activeChildren.map(
@@ -20061,21 +20159,26 @@ async function maybeEmitEnrichFailureReport(input2) {
20061
20159
  status: input2.status,
20062
20160
  rowRange: input2.statusRowRange ?? input2.rowRange
20063
20161
  });
20064
- const customerDbJobs = input2.status === void 0 || rowJobs.length > 0 || statusJobs.length > 0 ? [] : await collectCustomerDbFailureJobs({
20162
+ const customerDbDiagnostics = input2.status === void 0 || rowJobs.length > 0 || statusJobs.length > 0 ? { jobs: [], issue: null } : await collectCustomerDbFailureJobs({
20065
20163
  client: input2.client,
20066
20164
  status: input2.status,
20067
20165
  config: input2.config
20068
20166
  });
20167
+ const customerDbJobs = customerDbDiagnostics.jobs;
20168
+ if (customerDbDiagnostics.issue) {
20169
+ emitCustomerDbLookupUnavailableWarning(customerDbDiagnostics.issue);
20170
+ }
20171
+ const allEnrichIssues = enrichIssues;
20069
20172
  const jobs = rowJobs.length > 0 || statusJobs.length > 0 || customerDbJobs.length > 0 || input2.status === void 0 ? mergeEnrichFailureJobs(
20070
20173
  mergeEnrichFailureJobs(rowJobs, statusJobs),
20071
20174
  customerDbJobs
20072
20175
  ) : [];
20073
- if (jobs.length === 0 && enrichIssues.length === 0) {
20176
+ if (jobs.length === 0 && allEnrichIssues.length === 0) {
20074
20177
  return null;
20075
20178
  }
20076
20179
  const reportPath = await persistEnrichFailureReport({
20077
20180
  jobs,
20078
- issues: enrichIssues,
20181
+ issues: allEnrichIssues,
20079
20182
  apiUrl: input2.client.baseUrl,
20080
20183
  outputPath: input2.outputPath,
20081
20184
  rows: input2.rowRange
@@ -20095,13 +20198,13 @@ async function maybeEmitEnrichFailureReport(input2) {
20095
20198
  `);
20096
20199
  }
20097
20200
  }
20098
- if (enrichIssues.length > 0) {
20201
+ if (allEnrichIssues.length > 0) {
20099
20202
  process.stderr.write("Enrichment needs attention.\n");
20100
20203
  process.stderr.write("Issue preview (up to 5 enrichment issues):\n");
20101
20204
  process.stderr.write(
20102
20205
  "issue_id column severity selected_rows rows_with_value message\n"
20103
20206
  );
20104
- for (const issue of enrichIssues.slice(0, 5)) {
20207
+ for (const issue of allEnrichIssues.slice(0, 5)) {
20105
20208
  process.stderr.write(
20106
20209
  `${issue.issue_id} ${issue.column} ${issue.severity} ${issue.selected_rows} ${issue.rows_with_value} ${issue.message}
20107
20210
  `
@@ -20115,9 +20218,9 @@ async function maybeEmitEnrichFailureReport(input2) {
20115
20218
  `);
20116
20219
  }
20117
20220
  }
20118
- if (enrichIssues.length > 5) {
20221
+ if (allEnrichIssues.length > 5) {
20119
20222
  process.stderr.write(
20120
- `Showing 5 of ${enrichIssues.length} enrichment issues.
20223
+ `Showing 5 of ${allEnrichIssues.length} enrichment issues.
20121
20224
  `
20122
20225
  );
20123
20226
  }
@@ -20135,12 +20238,12 @@ async function maybeEmitEnrichFailureReport(input2) {
20135
20238
  process.stderr.write(
20136
20239
  jobs.length > 0 ? "Enrichment failed. See report above.\n" : "Enrichment produced no values for at least one requested waterfall. See issue preview above.\n"
20137
20240
  );
20138
- return { path: reportPath, jobs, issues: enrichIssues };
20241
+ return { path: reportPath, jobs, issues: allEnrichIssues };
20139
20242
  }
20140
20243
  process.stderr.write(
20141
20244
  jobs.length > 0 ? "Enrichment failed.\n" : "Enrichment needs attention.\n"
20142
20245
  );
20143
- return { path: "", jobs, issues: enrichIssues };
20246
+ return { path: "", jobs, issues: allEnrichIssues };
20144
20247
  }
20145
20248
  function mergePreferredColumns(preferredColumns, rows) {
20146
20249
  const columns = [];
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.187",
425
+ version: "0.1.188",
426
426
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
427
427
  supportPolicy: {
428
- latest: "0.1.187",
428
+ latest: "0.1.188",
429
429
  minimumSupported: "0.1.53",
430
430
  deprecatedBelow: "0.1.53",
431
431
  commandMinimumSupported: [
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.187",
355
+ version: "0.1.188",
356
356
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
357
357
  supportPolicy: {
358
- latest: "0.1.187",
358
+ latest: "0.1.188",
359
359
  minimumSupported: "0.1.53",
360
360
  deprecatedBelow: "0.1.53",
361
361
  commandMinimumSupported: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepline",
3
- "version": "0.1.187",
3
+ "version": "0.1.188",
4
4
  "description": "Deepline SDK + CLI — B2B data enrichment powered by durable cloud execution",
5
5
  "license": "MIT",
6
6
  "repository": {