deepline 0.1.161 → 0.1.163

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.
@@ -64,11 +64,13 @@ import {
64
64
  import { RECEIPT_STATUS_CODE, receiptStatusFromCode } from './receipt-status';
65
65
  import type { MapRowOutcome } from './durability-store';
66
66
  import {
67
+ normalizeRuntimeMapInputIndex,
67
68
  prepareRuntimeSheetRowTransitions,
68
69
  type RuntimePreparedCompletedRow,
69
70
  type RuntimePreparedFailedRow,
70
71
  } from './runtime-sheet-row-transition';
71
72
  import {
73
+ MAP_ROW_OUTCOME_RUNTIME_FIELDS,
72
74
  mapRowOutcomeRuntimeFields,
73
75
  resolveMapRowOutcomeKey,
74
76
  } from './map-row-outcome';
@@ -2251,6 +2253,21 @@ async function prepareRuntimeSheetDatasetRows(
2251
2253
  AND (${targetMissingOutputSql})
2252
2254
  RETURNING target._key
2253
2255
  ),
2256
+ claimed_existing_rows AS (
2257
+ UPDATE ${sheetTable(session)} AS target
2258
+ SET _run_id = $4::text,
2259
+ _input_index = input_rows._input_index,
2260
+ _updated_at = now(),
2261
+ _version = ${nextRuntimeSheetVersionExpression(session)}
2262
+ FROM input_rows
2263
+ WHERE target._key = input_rows._key
2264
+ AND target._status IN ('pending', 'running', 'failed')
2265
+ AND (
2266
+ target._run_id IS DISTINCT FROM $4::text
2267
+ OR target._input_index IS DISTINCT FROM input_rows._input_index
2268
+ )
2269
+ RETURNING target._key
2270
+ ),
2254
2271
  pending_rows AS (
2255
2272
  SELECT _key
2256
2273
  FROM inserted_rows
@@ -2258,6 +2275,9 @@ async function prepareRuntimeSheetDatasetRows(
2258
2275
  SELECT _key
2259
2276
  FROM missing_output_rows
2260
2277
  UNION
2278
+ SELECT _key
2279
+ FROM claimed_existing_rows
2280
+ UNION
2261
2281
  SELECT existing._key
2262
2282
  FROM ${sheetTable(session)} AS existing
2263
2283
  JOIN input_rows ON input_rows._key = existing._key
@@ -3206,7 +3226,10 @@ export async function startRuntimeSheetDataset(
3206
3226
  rows: input.rows.length,
3207
3227
  });
3208
3228
  const normalizeStartedAt = Date.now();
3209
- const uniqueRows = new Map<string, Record<string, unknown>>();
3229
+ const uniqueRows = new Map<
3230
+ string,
3231
+ { row: Record<string, unknown>; inputIndex: number | null }
3232
+ >();
3210
3233
  for (const row of input.rows) {
3211
3234
  // Materializes projected CSV aliases as visible cells and drops internal
3212
3235
  // __deepline* keys — a plain spread would silently lose the
@@ -3216,15 +3239,20 @@ export async function startRuntimeSheetDataset(
3216
3239
  resolveMapRowOutcomeKey(row) ??
3217
3240
  derivePlayRowIdentity(cleanedRow, input.tableNamespace);
3218
3241
  if (key && !uniqueRows.has(key)) {
3219
- uniqueRows.set(key, cleanedRow);
3242
+ uniqueRows.set(key, {
3243
+ row: cleanedRow,
3244
+ inputIndex: normalizeRuntimeMapInputIndex(
3245
+ row[MAP_ROW_OUTCOME_RUNTIME_FIELDS.inputIndex],
3246
+ ),
3247
+ });
3220
3248
  }
3221
3249
  }
3222
3250
  const inputOffset = Math.max(0, Math.floor(input.inputOffset ?? 0));
3223
3251
  const rowEntries = [...uniqueRows.entries()].map(
3224
- ([key, row], inputIndex) => ({
3252
+ ([key, entry], inputIndex) => ({
3225
3253
  key,
3226
- row,
3227
- inputIndex: inputOffset + inputIndex,
3254
+ row: entry.row,
3255
+ inputIndex: entry.inputIndex ?? inputOffset + inputIndex,
3228
3256
  }),
3229
3257
  );
3230
3258
  timings.push({
@@ -3409,6 +3437,7 @@ async function completeRuntimeMapRowChunks(
3409
3437
  AND (target._run_id IS NULL OR target._run_id <= $5::text)
3410
3438
  AND (
3411
3439
  target._status <> 'enriched'
3440
+ OR target._run_id IS DISTINCT FROM $5::text
3412
3441
  OR (${targetChangedPatchedCellSql})
3413
3442
  OR EXISTS (
3414
3443
  SELECT 1
@@ -3608,6 +3637,7 @@ async function completeRuntimeMapRowChunksWithInputIndexRepair(
3608
3637
  AND (target._run_id IS NULL OR target._run_id <= $5::text)
3609
3638
  AND (
3610
3639
  target._status <> 'enriched'
3640
+ OR target._run_id IS DISTINCT FROM $5::text
3611
3641
  OR (${targetChangedPatchedCellSql})
3612
3642
  OR EXISTS (
3613
3643
  SELECT 1
@@ -3722,6 +3752,148 @@ async function completeRuntimeMapRowChunksWithInputIndexRepair(
3722
3752
  return { updated };
3723
3753
  }
3724
3754
 
3755
+ async function insertMissingCompletedMapRowChunks(
3756
+ client: RuntimeQueryClient,
3757
+ session: RuntimePostgresSession,
3758
+ input: CompleteRuntimeMapRowChunksInput,
3759
+ ): Promise<{ inserted: number }> {
3760
+ let inserted = 0;
3761
+ const physicalInsertColumnsSql =
3762
+ input.physicalColumnProjections.length > 0
3763
+ ? `, ${input.physicalColumnProjections
3764
+ .map((column) => quoteIdentifier(column.sqlName))
3765
+ .join(', ')}`
3766
+ : '';
3767
+ const physicalInsertValuesSql =
3768
+ input.physicalColumnProjections.length > 0
3769
+ ? `, ${input.physicalColumnProjections
3770
+ .map(
3771
+ (column) =>
3772
+ `missing_rows.data_patch -> ${quoteLiteral(column.fieldName)}`,
3773
+ )
3774
+ .join(', ')}`
3775
+ : '';
3776
+
3777
+ for (const chunk of input.chunks) {
3778
+ const chunkKeys = chunk.map((row) => row.key);
3779
+ const chunkInputIndexes = chunk.map((row) => row.input_index);
3780
+ const chunkDataPatches = chunk.map((row) =>
3781
+ stringifyPostgresJson(row.data_patch),
3782
+ );
3783
+ const chunkCellMetaPatches = chunk.map((row) =>
3784
+ stringifyPostgresJson(row.cell_meta_patch),
3785
+ );
3786
+ const { rows } = await client.query<{ inserted: number }>(
3787
+ `WITH input_rows AS (
3788
+ SELECT key_values._key,
3789
+ input_index_values.input_index,
3790
+ data_values.data_patch,
3791
+ cell_meta_values.cell_meta_patch
3792
+ FROM unnest($1::text[]) WITH ORDINALITY AS key_values(_key, ord)
3793
+ JOIN unnest($2::bigint[]) WITH ORDINALITY AS input_index_values(input_index, ord)
3794
+ ON input_index_values.ord = key_values.ord
3795
+ JOIN unnest($3::jsonb[]) WITH ORDINALITY AS data_values(data_patch, ord)
3796
+ ON data_values.ord = key_values.ord
3797
+ JOIN unnest($4::jsonb[]) WITH ORDINALITY AS cell_meta_values(cell_meta_patch, ord)
3798
+ ON cell_meta_values.ord = key_values.ord
3799
+ ),
3800
+ missing_rows AS (
3801
+ SELECT input_rows.*
3802
+ FROM input_rows
3803
+ WHERE NOT EXISTS (
3804
+ SELECT 1
3805
+ FROM ${sheetTable(session)} AS target
3806
+ WHERE target._key = input_rows._key
3807
+ OR (
3808
+ input_rows.input_index IS NOT NULL
3809
+ AND target._run_id = $5::text
3810
+ AND target._input_index = input_rows.input_index
3811
+ )
3812
+ )
3813
+ ),
3814
+ inserted_rows AS (
3815
+ INSERT INTO ${sheetTable(session)} (_key, _status, _run_id, _input_index, _cell_meta${physicalInsertColumnsSql})
3816
+ SELECT _key, 'enriched', $5::text, input_index, cell_meta_patch${physicalInsertValuesSql}
3817
+ FROM missing_rows
3818
+ ON CONFLICT (_key) DO NOTHING
3819
+ RETURNING _key
3820
+ ),
3821
+ inserted_count AS (
3822
+ SELECT count(*)::bigint AS c FROM inserted_rows
3823
+ ),
3824
+ summary_delta AS (
3825
+ INSERT INTO ${summaryTable(session)} AS target (
3826
+ play_name,
3827
+ table_namespace,
3828
+ total,
3829
+ queued,
3830
+ running,
3831
+ completed,
3832
+ failed
3833
+ )
3834
+ SELECT $6::text,
3835
+ $7::text,
3836
+ c::int,
3837
+ 0,
3838
+ 0,
3839
+ c::int,
3840
+ 0
3841
+ FROM inserted_count
3842
+ WHERE c > 0
3843
+ ON CONFLICT (play_name, table_namespace) DO UPDATE SET
3844
+ total = ${runtimeSummaryTotalSql({
3845
+ currentTotal: 'target.total',
3846
+ totalDelta: 'EXCLUDED.total',
3847
+ queued: 'target.queued',
3848
+ running: 'target.running',
3849
+ completed: 'target.completed + EXCLUDED.completed',
3850
+ failed: 'target.failed',
3851
+ })},
3852
+ completed = target.completed + EXCLUDED.completed,
3853
+ _updated_at = now()
3854
+ RETURNING 1
3855
+ ),
3856
+ completed_cell_delta AS (
3857
+ SELECT field_values.field, (SELECT c FROM inserted_count) AS c
3858
+ FROM unnest($8::text[]) AS field_values(field)
3859
+ WHERE (SELECT c FROM inserted_count) > 0
3860
+ ),
3861
+ column_delta AS (
3862
+ INSERT INTO ${columnSummaryTable(session)} AS target (
3863
+ play_name,
3864
+ table_namespace,
3865
+ field,
3866
+ completed,
3867
+ failed
3868
+ )
3869
+ SELECT $6::text,
3870
+ $7::text,
3871
+ field,
3872
+ c::int,
3873
+ 0
3874
+ FROM completed_cell_delta
3875
+ ON CONFLICT (play_name, table_namespace, field) DO UPDATE SET
3876
+ completed = target.completed + EXCLUDED.completed,
3877
+ _updated_at = now()
3878
+ RETURNING 1
3879
+ )
3880
+ SELECT c::int AS inserted FROM inserted_count`,
3881
+ [
3882
+ chunkKeys,
3883
+ chunkInputIndexes,
3884
+ chunkDataPatches,
3885
+ chunkCellMetaPatches,
3886
+ input.runId,
3887
+ input.normalizedPlayName,
3888
+ input.normalizedTableNamespace,
3889
+ [...new Set(input.outputFields)],
3890
+ ],
3891
+ );
3892
+ inserted += Number(rows[0]?.inserted ?? 0);
3893
+ }
3894
+ return { inserted };
3895
+ }
3896
+
3725
3897
  /**
3726
3898
  * Mark map rows FAILED in the per-run scoped Postgres sheet table by key.
3727
3899
  *
@@ -4003,17 +4175,30 @@ export async function completeRuntimeMapRows(
4003
4175
  async (client) => {
4004
4176
  const completed =
4005
4177
  completedRows.length > 0
4006
- ? await completeRuntimeMapRowChunks(client, session, {
4007
- chunks,
4008
- physicalUpdateSetSql,
4009
- physicalColumnProjections: projections,
4010
- runId: input.runId,
4011
- normalizedPlayName: normalizePlayNameForSheet(session.playName),
4012
- normalizedTableNamespace: normalizeTableNamespace(
4013
- input.tableNamespace,
4014
- ),
4015
- outputFields,
4016
- })
4178
+ ? await (async () => {
4179
+ const chunkInput = {
4180
+ chunks,
4181
+ physicalUpdateSetSql,
4182
+ physicalColumnProjections: projections,
4183
+ runId: input.runId,
4184
+ normalizedPlayName: normalizePlayNameForSheet(session.playName),
4185
+ normalizedTableNamespace: normalizeTableNamespace(
4186
+ input.tableNamespace,
4187
+ ),
4188
+ outputFields,
4189
+ };
4190
+ const updated = await completeRuntimeMapRowChunks(
4191
+ client,
4192
+ session,
4193
+ chunkInput,
4194
+ );
4195
+ const inserted = await insertMissingCompletedMapRowChunks(
4196
+ client,
4197
+ session,
4198
+ chunkInput,
4199
+ );
4200
+ return { updated: updated.updated + inserted.inserted };
4201
+ })()
4017
4202
  : { updated: 0 };
4018
4203
  const failed =
4019
4204
  failedRows.length > 0
@@ -4075,6 +4260,65 @@ export async function readRuntimeSheetDatasetRows(
4075
4260
  };
4076
4261
  }
4077
4262
 
4263
+ export async function readRuntimeSheetDatasetRowKeys(
4264
+ context: RuntimeApiContext & { playName: string },
4265
+ input: {
4266
+ tableNamespace: string;
4267
+ runId: string;
4268
+ keys: string[];
4269
+ rowMode?: 'output' | 'all';
4270
+ },
4271
+ ): Promise<{ keys: string[] }> {
4272
+ const keys = [
4273
+ ...new Set(
4274
+ input.keys
4275
+ .map((key) => key.trim())
4276
+ .filter((key) => key.length > 0),
4277
+ ),
4278
+ ];
4279
+ if (keys.length === 0) {
4280
+ return { keys: [] };
4281
+ }
4282
+ const session = requireRuntimePostgresSession(
4283
+ await getRuntimeDbSession(
4284
+ {
4285
+ ...context,
4286
+ playName: context.playName,
4287
+ runId: context.runId ?? input.runId,
4288
+ },
4289
+ {
4290
+ tableNamespace: input.tableNamespace,
4291
+ logicalTable: 'sheet_rows',
4292
+ operations: ['rows.read'],
4293
+ limits: { maxRows: runtimeDbSessionRowLimit(keys.length) },
4294
+ },
4295
+ ),
4296
+ );
4297
+ const rows = await withRuntimePostgres(session, async (client) => {
4298
+ if (input.rowMode === 'all') {
4299
+ const { rows: matchedRows } = await client.query<{ _key: string }>(
4300
+ `SELECT _key
4301
+ FROM ${sheetTable(session)}
4302
+ WHERE _run_id = $1::text
4303
+ AND _key = ANY($2::text[])
4304
+ AND _status IN ('enriched', 'failed')`,
4305
+ [input.runId, keys],
4306
+ );
4307
+ return matchedRows;
4308
+ }
4309
+ const { rows: matchedRows } = await client.query<{ _key: string }>(
4310
+ `SELECT _key
4311
+ FROM ${sheetTable(session)}
4312
+ WHERE _run_id = $1::text
4313
+ AND _key = ANY($2::text[])
4314
+ AND _status = 'enriched'`,
4315
+ [input.runId, keys],
4316
+ );
4317
+ return matchedRows;
4318
+ });
4319
+ return { keys: rows.map((row) => row._key) };
4320
+ }
4321
+
4078
4322
  export async function persistRuntimeCsvDataset(
4079
4323
  context: RuntimeApiContext & { playName: string },
4080
4324
  input: {
@@ -12,6 +12,14 @@ export { sqlSafePlayColumnName };
12
12
  export interface PlayStaticReturnField {
13
13
  name: string;
14
14
  isDataset: boolean;
15
+ /**
16
+ * For a dataset-valued field, the `ctx.dataset(KEY, ...)` key backing it
17
+ * (e.g. `job_change_checks`) — so the UI can label the return by the dataset
18
+ * it actually produces instead of the bland object key (`rows`). Undefined
19
+ * for non-dataset fields, `ctx.csv(...)` (no durable name), or when the key
20
+ * isn't a static string literal.
21
+ */
22
+ datasetName?: string;
15
23
  }
16
24
 
17
25
  export interface PlayStaticPipeline {
@@ -333,6 +341,19 @@ type PlayStaticSubstepMetadata = {
333
341
  dependsOnFields?: string[];
334
342
  };
335
343
 
344
+ /**
345
+ * One arm of a conditional `control_flow` substep — an `if`/`else if`/`else`
346
+ * leg, a `switch` case, or a ternary branch. Carries its own steps so the graph
347
+ * can render the conditional as a real fork instead of a flat strip.
348
+ */
349
+ export type PlayStaticControlFlowBranch = {
350
+ /** Short arm label, e.g. `if`, `else if`, `else`, `case 'x'`, `default`. */
351
+ label: string;
352
+ /** The arm's condition source text, when it has one (omitted for `else`). */
353
+ condition?: string;
354
+ steps: PlayStaticSubstep[];
355
+ };
356
+
336
357
  export type PlayStaticSubstep = PlayStaticSubstepMetadata &
337
358
  (
338
359
  | {
@@ -421,7 +442,12 @@ export type PlayStaticSubstep = PlayStaticSubstepMetadata &
421
442
  type: 'control_flow';
422
443
  kind: 'conditional' | 'loop';
423
444
  field: string;
445
+ /** Flattened steps across every arm, in source order (back-compat). */
424
446
  steps: PlayStaticSubstep[];
447
+ /** Discriminant source text (the `if`/ternary test, `switch` subject). */
448
+ condition?: string;
449
+ /** Per-arm breakdown for conditionals; omitted for loops. */
450
+ branches?: PlayStaticControlFlowBranch[];
425
451
  description?: string;
426
452
  sourceRange?: PlayStaticSourceRange;
427
453
  callDepth?: number;
package/dist/cli/index.js CHANGED
@@ -622,10 +622,10 @@ var SDK_RELEASE = {
622
622
  // 0.1.111 ships dataset-native tool list getters and result row datasets.
623
623
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
624
624
  // fields shipped in 0.1.153.
625
- version: "0.1.161",
625
+ version: "0.1.163",
626
626
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
627
627
  supportPolicy: {
628
- latest: "0.1.161",
628
+ latest: "0.1.163",
629
629
  minimumSupported: "0.1.53",
630
630
  deprecatedBelow: "0.1.53",
631
631
  commandMinimumSupported: [
@@ -17742,7 +17742,7 @@ function fallbackRowsInfoForGeneratedEnrichExport(status, options) {
17742
17742
  columns: [],
17743
17743
  columnsExplicit: false,
17744
17744
  complete: false,
17745
- source: GENERATED_ENRICH_ROWS_TABLE_NAMESPACE,
17745
+ source: null,
17746
17746
  tableNamespace: GENERATED_ENRICH_ROWS_TABLE_NAMESPACE
17747
17747
  };
17748
17748
  }
@@ -17763,10 +17763,45 @@ function hasLossyPreviewPlaceholder(value, depth = 0) {
17763
17763
  }
17764
17764
  return false;
17765
17765
  }
17766
+ function statusReferencesGeneratedEnrichRows(value, depth = 0) {
17767
+ if (depth > 12 || value === null || value === void 0) {
17768
+ return false;
17769
+ }
17770
+ if (typeof value === "string") {
17771
+ return value.trim() === GENERATED_ENRICH_ROWS_TABLE_NAMESPACE;
17772
+ }
17773
+ if (Array.isArray(value)) {
17774
+ return value.some(
17775
+ (item) => statusReferencesGeneratedEnrichRows(item, depth + 1)
17776
+ );
17777
+ }
17778
+ if (typeof value === "object") {
17779
+ return Object.values(value).some(
17780
+ (item) => statusReferencesGeneratedEnrichRows(item, depth + 1)
17781
+ );
17782
+ }
17783
+ return false;
17784
+ }
17785
+ function generatedEnrichRowsTableNamespaceForExport(rowsInfo, status) {
17786
+ const tableNamespace = rowsInfo.tableNamespace?.trim() || null;
17787
+ if (tableNamespace === "result.rows") {
17788
+ return GENERATED_ENRICH_ROWS_TABLE_NAMESPACE;
17789
+ }
17790
+ if (!tableNamespace && statusReferencesGeneratedEnrichRows(status)) {
17791
+ return GENERATED_ENRICH_ROWS_TABLE_NAMESPACE;
17792
+ }
17793
+ return tableNamespace;
17794
+ }
17766
17795
  function shouldFetchBackingRowsForEnrichExport(rowsInfo, status, options = {}) {
17767
17796
  const terminalStatus = readEnrichRunStatus(status);
17768
- const tableNamespace = rowsInfo.tableNamespace?.trim();
17797
+ const tableNamespace = generatedEnrichRowsTableNamespaceForExport(
17798
+ rowsInfo,
17799
+ status
17800
+ );
17769
17801
  if (terminalStatus === "failed" || terminalStatus === "cancelled") {
17802
+ if (tableNamespace === GENERATED_ENRICH_ROWS_TABLE_NAMESPACE && rowsInfo.source !== null && typeof options.selectedSourceRows === "number" && rowsInfo.rows.length < options.selectedSourceRows) {
17803
+ return true;
17804
+ }
17770
17805
  return tableNamespace === GENERATED_ENRICH_ROWS_TABLE_NAMESPACE && (rowsInfo.recovered === true || hasPartialRunOutputWarning(status));
17771
17806
  }
17772
17807
  if (tableNamespace === GENERATED_ENRICH_ROWS_TABLE_NAMESPACE && typeof options.selectedSourceRows === "number" && rowsInfo.rows.length < options.selectedSourceRows) {
@@ -17894,6 +17929,45 @@ function exportableSheetRow2(row, sourceRowStart = 0) {
17894
17929
  }
17895
17930
  return fallback;
17896
17931
  }
17932
+ function mergeExportedSheetRow(target, next) {
17933
+ const baseMetadata = target._metadata;
17934
+ const nextMetadata = next._metadata;
17935
+ for (const [key, value] of Object.entries(next)) {
17936
+ const existing = target[key];
17937
+ if (isNonEmptyCsvCell(existing) && !isNonEmptyCsvCell(value)) {
17938
+ continue;
17939
+ }
17940
+ target[key] = value;
17941
+ }
17942
+ const metadata = mergeLegacyMetadataCell(baseMetadata, nextMetadata);
17943
+ if (metadata !== void 0) {
17944
+ target._metadata = metadata;
17945
+ }
17946
+ }
17947
+ function coalesceExportableSheetRows(rows, sourceRowStart = 0) {
17948
+ const mergedRows = [];
17949
+ const bySourceRowIndex = /* @__PURE__ */ new Map();
17950
+ for (const row of rows) {
17951
+ const rowIndex = sourceRowIndexFromEnrichRow(
17952
+ row,
17953
+ sourceRowStart,
17954
+ Number.MAX_SAFE_INTEGER
17955
+ );
17956
+ if (rowIndex === null) {
17957
+ mergedRows.push(row);
17958
+ continue;
17959
+ }
17960
+ const existing = bySourceRowIndex.get(rowIndex);
17961
+ if (existing) {
17962
+ mergeExportedSheetRow(existing, row);
17963
+ continue;
17964
+ }
17965
+ const next = { ...row };
17966
+ bySourceRowIndex.set(rowIndex, next);
17967
+ mergedRows.push(next);
17968
+ }
17969
+ return mergedRows;
17970
+ }
17897
17971
  function sourceRowIndexFromEnrichRow(row, start, end) {
17898
17972
  const value = row[ENRICH_SOURCE_ROW_INDEX_COLUMN];
17899
17973
  const parsed = typeof value === "number" ? value : typeof value === "string" && value.trim() ? Number(value) : Number.NaN;
@@ -17998,7 +18072,11 @@ function aliasFailureCellCandidates(row, alias) {
17998
18072
  if (key.startsWith(dottedPrefix)) {
17999
18073
  assignFlattenedFailurePath(nested, key.slice(dottedPrefix.length), value);
18000
18074
  } else if (key.startsWith(underscorePrefix)) {
18001
- assignFlattenedFailurePath(nested, key.slice(underscorePrefix.length), value);
18075
+ assignFlattenedFailurePath(
18076
+ nested,
18077
+ key.slice(underscorePrefix.length),
18078
+ value
18079
+ );
18002
18080
  }
18003
18081
  }
18004
18082
  if (Object.keys(nested).length > 0) {
@@ -18376,13 +18454,14 @@ function mergePreferredColumns(preferredColumns, rows) {
18376
18454
  async function fetchBackingRowsForCsvExport(input2) {
18377
18455
  const runId = extractRunId(input2.status);
18378
18456
  const playName = extractPlayName2(input2.status);
18379
- const tableNamespace = input2.rowsInfo.tableNamespace?.trim() || GENERATED_ENRICH_ROWS_TABLE_NAMESPACE;
18457
+ const tableNamespace = generatedEnrichRowsTableNamespaceForExport(input2.rowsInfo, input2.status) || GENERATED_ENRICH_ROWS_TABLE_NAMESPACE;
18380
18458
  if (!runId || !playName || !tableNamespace) {
18381
18459
  return null;
18382
18460
  }
18383
18461
  const deadline = Date.now() + enrichExportBackingRowsWaitMs();
18384
18462
  let lastRows = [];
18385
- const minimumExpectedRows = typeof input2.expectedRows === "number" && input2.expectedRows > 0 ? Math.trunc(input2.expectedRows) : input2.rowsInfo.totalRows;
18463
+ const hasExplicitExpectedRows = typeof input2.expectedRows === "number" && input2.expectedRows > 0;
18464
+ const minimumExpectedRows = hasExplicitExpectedRows ? Math.trunc(Number(input2.expectedRows)) : input2.rowsInfo.totalRows;
18386
18465
  let lastExpectedTotal = minimumExpectedRows;
18387
18466
  for (; ; ) {
18388
18467
  const sheetRows = [];
@@ -18407,10 +18486,15 @@ async function fetchBackingRowsForCsvExport(input2) {
18407
18486
  }
18408
18487
  offset += page.rows.length;
18409
18488
  }
18410
- const rows = sheetRows.map((row) => exportableSheetRow2(row, input2.sourceRowStart ?? 0)).filter((row) => Boolean(row));
18489
+ const rawRows = sheetRows.map((row) => exportableSheetRow2(row, input2.sourceRowStart ?? 0)).filter((row) => Boolean(row));
18490
+ const rows = coalesceExportableSheetRows(
18491
+ rawRows,
18492
+ input2.sourceRowStart ?? 0
18493
+ );
18411
18494
  lastRows = rows;
18412
18495
  lastExpectedTotal = expectedTotal;
18413
- if (expectedTotal > 0 && rows.length >= expectedTotal || expectedTotal === 0 && rows.length > 0) {
18496
+ const requiredExportRows = hasExplicitExpectedRows ? minimumExpectedRows : expectedTotal;
18497
+ if (requiredExportRows > 0 && rows.length >= requiredExportRows || requiredExportRows === 0 && rows.length > 0) {
18414
18498
  return {
18415
18499
  ...input2.rowsInfo,
18416
18500
  rows,
@@ -18418,7 +18502,7 @@ async function fetchBackingRowsForCsvExport(input2) {
18418
18502
  input2.rowsInfo.columnsExplicit ? input2.rowsInfo.columns : [],
18419
18503
  rows
18420
18504
  ),
18421
- totalRows: Math.max(rows.length, expectedTotal),
18505
+ totalRows: hasExplicitExpectedRows ? Math.max(rows.length, minimumExpectedRows) : Math.max(rows.length, expectedTotal),
18422
18506
  complete: true,
18423
18507
  source: `${input2.rowsInfo.source ?? "result.rows"} -> /api/v2/plays/${playName}/sheet?tableNamespace=${tableNamespace}`
18424
18508
  };
@@ -18438,7 +18522,7 @@ async function fetchBackingRowsForCsvExport(input2) {
18438
18522
  input2.rowsInfo.columnsExplicit ? input2.rowsInfo.columns : [],
18439
18523
  lastRows
18440
18524
  ),
18441
- totalRows: Math.max(lastExpectedTotal, input2.rowsInfo.totalRows),
18525
+ totalRows: hasExplicitExpectedRows ? Math.max(lastRows.length, minimumExpectedRows) : Math.max(lastExpectedTotal, input2.rowsInfo.totalRows),
18442
18526
  complete: false,
18443
18527
  source: `${input2.rowsInfo.source ?? "result.rows"} -> /api/v2/plays/${playName}/sheet?tableNamespace=${tableNamespace}`
18444
18528
  };
@@ -18626,8 +18710,13 @@ function materializeAliasSuccessCell(row, alias) {
18626
18710
  directCells.push({ field, value });
18627
18711
  }
18628
18712
  }
18629
- for (const preferredField of [alias, ...ENRICH_FLATTENED_SUCCESS_FIELD_PRIORITY]) {
18630
- const preferred = directCells.find(({ field }) => field === preferredField);
18713
+ for (const preferredField of [
18714
+ alias,
18715
+ ...ENRICH_FLATTENED_SUCCESS_FIELD_PRIORITY
18716
+ ]) {
18717
+ const preferred = directCells.find(
18718
+ ({ field }) => field === preferredField
18719
+ );
18631
18720
  if (preferred) {
18632
18721
  return materializeCsvCellValue(preferred.value);
18633
18722
  }
@@ -18829,7 +18918,7 @@ function assertCompleteRowsForCsvExport(rowsInfo, status, outputPath, options =
18829
18918
  return;
18830
18919
  }
18831
18920
  const runId = status && typeof status === "object" && !Array.isArray(status) && typeof status.runId === "string" ? status.runId : null;
18832
- const dataset = rowsInfo.source ?? "result.rows";
18921
+ const dataset = rowsInfo.source ?? rowsInfo.tableNamespace ?? "result.rows";
18833
18922
  const retry = runId ? ` Retry after the run finalizes its backing dataset with: deepline runs export ${runId} --dataset ${dataset} --out ${outputPath}` : "";
18834
18923
  throw new Error(
18835
18924
  `Refusing to write a partial CSV export: the run returned ${rowsInfo.rows.length} preview row(s) out of ${rowsInfo.totalRows}.${retry}`