deepline 0.1.200 → 0.1.202

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/entry.ts +49 -13
  2. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/map-chunk-plan.ts +25 -0
  3. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-dispatch.ts +139 -124
  4. package/dist/bundling-sources/sdk/src/release.ts +2 -2
  5. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +17 -2
  6. package/dist/bundling-sources/shared_libs/play-runtime/bounded-dispatch.ts +52 -0
  7. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +152 -23
  8. package/dist/bundling-sources/shared_libs/play-runtime/coordinator-headers.ts +10 -0
  9. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +11 -0
  10. package/dist/bundling-sources/shared_libs/play-runtime/execution-capabilities.ts +121 -0
  11. package/dist/bundling-sources/shared_libs/play-runtime/governor/adaptive-admission.ts +6 -1
  12. package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-budget-state-backend.ts +22 -0
  13. package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-rate-state-backend.ts +86 -19
  14. package/dist/bundling-sources/shared_libs/play-runtime/governor/block-reserving-budget-state-backend.ts +141 -0
  15. package/dist/bundling-sources/shared_libs/play-runtime/governor/budget-state-backend.ts +43 -0
  16. package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +129 -41
  17. package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +40 -2
  18. package/dist/bundling-sources/shared_libs/play-runtime/receipt-completion-sink.ts +92 -33
  19. package/dist/bundling-sources/shared_libs/play-runtime/resource-governor.ts +13 -5
  20. package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +43 -0
  21. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +122 -120
  22. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +10 -8
  23. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +140 -32
  24. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +327 -31
  25. package/dist/bundling-sources/shared_libs/play-runtime/runtime-scheduler-topology.ts +26 -0
  26. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +21 -0
  27. package/dist/bundling-sources/shared_libs/plays/dataset.ts +32 -10
  28. package/dist/cli/index.js +198 -76
  29. package/dist/cli/index.mjs +204 -82
  30. package/dist/index.js +3 -2
  31. package/dist/index.mjs +3 -2
  32. package/package.json +1 -1
  33. package/dist/bundling-sources/shared_libs/play-runtime/adaptive-tool-dispatcher.ts +0 -355
@@ -115,7 +115,11 @@ type RuntimeApiContext = {
115
115
  runId?: string | null;
116
116
  userEmail?: string | null;
117
117
  integrationMode?: 'live' | 'eval_stub' | 'fixture' | null;
118
- dbSessionStrategy?: 'preloaded' | 'sandbox_public_key' | null;
118
+ dbSessionStrategy?:
119
+ | 'preloaded'
120
+ | 'sandbox_public_key'
121
+ | 'gateway_only'
122
+ | null;
119
123
  preloadedDbSessions?: PreloadedRuntimeDbSession[] | null;
120
124
  vercelProtectionBypassToken?: string | null;
121
125
  runtimeTestFaultHeader?: string | null;
@@ -443,9 +447,33 @@ type RuntimeApiActionRequest =
443
447
  action: 'repair_runtime_storage_grants';
444
448
  playName: string;
445
449
  runId?: string | null;
450
+ }
451
+ | {
452
+ action: 'runtime_sheet_start';
453
+ input: Parameters<typeof startRuntimeSheetDataset>[1];
454
+ }
455
+ | {
456
+ action: 'runtime_sheet_complete_map_rows';
457
+ input: Parameters<typeof completeRuntimeMapRows>[1];
458
+ }
459
+ | {
460
+ action: 'runtime_sheet_read_rows';
461
+ input: Parameters<typeof readRuntimeSheetDatasetRows>[1];
462
+ }
463
+ | {
464
+ action: 'runtime_sheet_read_row_keys';
465
+ input: Parameters<typeof readRuntimeSheetDatasetRowKeys>[1];
466
+ }
467
+ | {
468
+ action: 'runtime_sheet_release_attempt';
469
+ input: Parameters<typeof releaseRuntimeSheetAttempt>[1];
470
+ }
471
+ | {
472
+ action: 'runtime_receipts_release_attempt';
473
+ input: Parameters<typeof releaseRuntimeWorkReceipts>[1];
446
474
  };
447
475
 
448
- type RuntimeApiRowRecord = MapRowOutcome & {
476
+ export type RuntimeApiRowRecord = MapRowOutcome & {
449
477
  inputIndex?: number | null;
450
478
  };
451
479
 
@@ -614,8 +642,8 @@ function runtimeApiMaxAttempts(
614
642
  return runtimeApiRetryDelaysForAction(action).length + 1;
615
643
  }
616
644
 
617
- function isTransientRuntimeApiErrorMessage(message: string): boolean {
618
- return /timeout exceeded when trying to connect|timed out|fetch failed|ECONNRESET|ECONNREFUSED|UND_ERR_CONNECT_TIMEOUT|requested endpoint could not be found, or you don't have access/i.test(
645
+ export function isTransientRuntimeApiErrorMessage(message: string): boolean {
646
+ return /timeout exceeded when trying to connect|timed out|fetch failed|ECONNRESET|ECONNREFUSED|UND_ERR_CONNECT_TIMEOUT|requested endpoint could not be found, or you don't have access|RUNTIME_SCHEDULER_SATURATED|Runtime scheduler DB pool is saturated|Runtime scheduler DB circuit breaker is open/i.test(
619
647
  message,
620
648
  );
621
649
  }
@@ -726,6 +754,75 @@ async function isRuntimeSheetSchemaReady(
726
754
  }
727
755
  }
728
756
 
757
+ /**
758
+ * Report exactly what the scoped runtime role can see for the sheet table, from
759
+ * the same connection the readiness probe uses. When ensure_sheet reports the
760
+ * table as provisioned but the runner probe still returns not-ready, the cause
761
+ * is almost always that the runtime role lacks a privilege on the freshly
762
+ * created table (so information_schema.columns hides the attempt columns) or a
763
+ * schema/table-name mismatch. This turns the previously blind "still not ready"
764
+ * error into an actionable one that names the concrete missing piece.
765
+ */
766
+ async function readRuntimeSheetSchemaDiagnostic(
767
+ session: RuntimePostgresSession,
768
+ ): Promise<Record<string, unknown>> {
769
+ const query = async (
770
+ client: RuntimeQueryClient,
771
+ ): Promise<Record<string, unknown>> => {
772
+ const visibleColumns = await client.query<{ column_name: string }>(
773
+ `
774
+ SELECT column_name
775
+ FROM information_schema.columns
776
+ WHERE table_schema = $1
777
+ AND table_name = $2
778
+ ORDER BY ordinal_position
779
+ `,
780
+ [session.postgres.schema, session.postgres.sheetTable],
781
+ );
782
+ const privileges = await client.query<Record<string, unknown>>(
783
+ `
784
+ SELECT
785
+ current_user AS probe_role,
786
+ to_regclass($3) IS NOT NULL AS regclass_visible,
787
+ has_table_privilege(current_user, $3, 'SELECT') AS can_select,
788
+ has_table_privilege(current_user, $3, 'INSERT') AS can_insert,
789
+ has_table_privilege(current_user, $3, 'UPDATE') AS can_update
790
+ `,
791
+ [
792
+ session.postgres.schema,
793
+ session.postgres.sheetTable,
794
+ `${quoteIdentifier(session.postgres.schema)}.${quoteIdentifier(session.postgres.sheetTable)}`,
795
+ ],
796
+ );
797
+ const visible = new Set(visibleColumns.rows.map((row) => row.column_name));
798
+ return {
799
+ schema: session.postgres.schema,
800
+ table: session.postgres.sheetTable,
801
+ probeRole: privileges.rows[0]?.probe_role ?? null,
802
+ regclassVisible: privileges.rows[0]?.regclass_visible ?? null,
803
+ canSelect: privileges.rows[0]?.can_select ?? null,
804
+ canInsert: privileges.rows[0]?.can_insert ?? null,
805
+ canUpdate: privileges.rows[0]?.can_update ?? null,
806
+ visibleColumnCount: visible.size,
807
+ missingAttemptColumns: RUNTIME_SHEET_ATTEMPT_COLUMNS.filter(
808
+ (column) => !visible.has(column),
809
+ ),
810
+ };
811
+ };
812
+ try {
813
+ if (isRuntimeOneShotQueryFactoryRegistered()) {
814
+ return await withRuntimeOneShotPostgres(session, query);
815
+ }
816
+ return await withRuntimePostgres(session, query);
817
+ } catch (error) {
818
+ return {
819
+ schema: session.postgres.schema,
820
+ table: session.postgres.sheetTable,
821
+ diagnosticError: error instanceof Error ? error.message : String(error),
822
+ };
823
+ }
824
+ }
825
+
729
826
  async function waitForRuntimeSheetSchemaReadyAfterEnsure(
730
827
  session: RuntimePostgresSession,
731
828
  input: {
@@ -839,7 +936,7 @@ async function ensureRuntimeSheetForPreloadedSession(
839
936
  phase: 'ensure_sheet_for_preloaded_session',
840
937
  ms: Date.now() - ensureStartedAt,
841
938
  });
842
- const readyAfterEnsure = await waitForRuntimeSheetSchemaReadyAfterEnsure(
939
+ let readyAfterEnsure = await waitForRuntimeSheetSchemaReadyAfterEnsure(
843
940
  input.session,
844
941
  {
845
942
  sheetContract: input.sheetContract,
@@ -847,8 +944,39 @@ async function ensureRuntimeSheetForPreloadedSession(
847
944
  },
848
945
  );
849
946
  if (!readyAfterEnsure) {
947
+ // ensure_sheet provisions the sheet as the tenant admin role, but the
948
+ // preloaded session probes as the scoped runtime role. When the tenant
949
+ // role contract was only partially applied (e.g. role-membership grants
950
+ // skipped on a data plane where the owner cannot administer roles), the
951
+ // runtime role never inherits access to the freshly created table, so its
952
+ // information_schema view hides the attempt columns and the probe stays
953
+ // not-ready even though the table exists. Re-apply the storage grants
954
+ // through the same self-heal the pre-ensure probe uses, then re-check
955
+ // once. This is a grant repair, not a blind retry: if the runtime role
956
+ // still cannot see the sheet, we fail loudly below with the concrete
957
+ // runtime-role view.
958
+ const repairStartedAt = Date.now();
959
+ await repairRuntimeStorageGrants(context, {
960
+ playName: context.playName,
961
+ });
962
+ input.timings?.push({
963
+ phase: 'repair_storage_grants_after_preloaded_session_ensure',
964
+ ms: Date.now() - repairStartedAt,
965
+ retried: true,
966
+ });
967
+ readyAfterEnsure = await waitForRuntimeSheetSchemaReadyAfterEnsure(
968
+ input.session,
969
+ {
970
+ sheetContract: input.sheetContract,
971
+ timings: input.timings,
972
+ },
973
+ );
974
+ }
975
+ if (!readyAfterEnsure) {
976
+ const diagnostic = await readRuntimeSheetSchemaDiagnostic(input.session);
850
977
  throw new Error(
851
- `Runtime sheet schema for ctx.dataset("${input.tableNamespace}") is still not ready after ensure_sheet.`,
978
+ `Runtime sheet schema for ctx.dataset("${input.tableNamespace}") is still not ready after ensure_sheet. ` +
979
+ `Runtime-role view: ${JSON.stringify(diagnostic)}`,
852
980
  );
853
981
  }
854
982
  })();
@@ -4158,6 +4286,36 @@ export async function markRuntimeWorkReceiptsQueued(
4158
4286
  );
4159
4287
  }
4160
4288
 
4289
+ /**
4290
+ * Replay-idempotency fence for a receipt whose active complete/fail UPDATE
4291
+ * matched 0 rows. This fires when the durable write committed but the HTTP
4292
+ * response was lost and the SAME caller retries: the row is already terminal,
4293
+ * so the active-owner predicate (which requires status IN (queued, running))
4294
+ * can never match again. We surface the already-terminal row as success ONLY
4295
+ * when its run identity matches the retrying caller, so the retry does not
4296
+ * spuriously fail a receipt whose provider spend and durable write both
4297
+ * succeeded.
4298
+ *
4299
+ * The predicate mirrors the run-identity half of {@link
4300
+ * workReceiptActiveOwnerPredicateSql}: `COALESCE(lease_owner_run_id, run_id)`
4301
+ * must equal the caller's run id. complete/fail null the lease-owner and
4302
+ * attempt columns as part of the terminal write, so run id is the only durable
4303
+ * ownership marker left on a terminal row — a different run (the stale-owner
4304
+ * rejection case) never matches and still resolves to null exactly as before.
4305
+ * This is replay-idempotency only; it never lets a foreign run read or claim a
4306
+ * receipt it did not complete.
4307
+ */
4308
+ function workReceiptTerminalReplayPredicateSql(input: {
4309
+ receiptTable: string;
4310
+ terminalStatusSql: string;
4311
+ ownerRunIdSql: string;
4312
+ }): string {
4313
+ const table = input.receiptTable;
4314
+ return `${table}.status = ${input.terminalStatusSql}::smallint
4315
+ /* replay-idempotency: same-run retry after a lost response; run identity is the only durable owner marker on a terminal row */
4316
+ AND COALESCE(${table}.lease_owner_run_id, ${table}.run_id) = ${input.ownerRunIdSql}`;
4317
+ }
4318
+
4161
4319
  export async function completeRuntimeWorkReceipt(
4162
4320
  context: RuntimeApiContext,
4163
4321
  input: {
@@ -4240,8 +4398,31 @@ export async function completeRuntimeWorkReceipt(
4240
4398
  lease_owner_attempt,
4241
4399
  lease_expires_at,
4242
4400
  updated_at
4401
+ ),
4402
+ replay AS (
4403
+ SELECT convert_from(k, 'UTF8') AS k,
4404
+ status,
4405
+ output,
4406
+ error,
4407
+ failure_kind,
4408
+ run_id,
4409
+ lease_id,
4410
+ lease_owner_run_id,
4411
+ lease_owner_attempt,
4412
+ lease_expires_at,
4413
+ updated_at
4414
+ FROM ${workReceiptTable(session)}
4415
+ WHERE k = decode($1, 'hex')
4416
+ AND NOT EXISTS (SELECT 1 FROM completed)
4417
+ AND ${workReceiptTerminalReplayPredicateSql({
4418
+ receiptTable: workReceiptTable(session),
4419
+ terminalStatusSql: '$2',
4420
+ ownerRunIdSql: '$4',
4421
+ })}
4243
4422
  )
4244
4423
  SELECT k, status, output, error, failure_kind, run_id, lease_id, lease_owner_run_id, lease_owner_attempt, lease_expires_at, updated_at FROM completed
4424
+ UNION ALL
4425
+ SELECT k, status, output, error, failure_kind, run_id, lease_id, lease_owner_run_id, lease_owner_attempt, lease_expires_at, updated_at FROM replay
4245
4426
  `,
4246
4427
  [
4247
4428
  workReceiptKeyHex(input.key),
@@ -4378,21 +4559,49 @@ export async function completeRuntimeWorkReceipts(
4378
4559
  target.updated_at,
4379
4560
  inputs.ord
4380
4561
  ),
4562
+ replay AS (
4563
+ SELECT target.k,
4564
+ target.status,
4565
+ target.output,
4566
+ target.error,
4567
+ target.failure_kind,
4568
+ target.run_id,
4569
+ target.lease_id,
4570
+ target.lease_owner_run_id,
4571
+ target.lease_owner_attempt,
4572
+ target.lease_expires_at,
4573
+ target.updated_at,
4574
+ inputs.ord
4575
+ FROM inputs
4576
+ JOIN ${workReceiptTable(session)} AS target
4577
+ ON target.k = decode(inputs.key_hex, 'hex')
4578
+ WHERE NOT EXISTS (SELECT 1 FROM completed WHERE completed.ord = inputs.ord)
4579
+ AND ${workReceiptTerminalReplayPredicateSql({
4580
+ receiptTable: 'target',
4581
+ terminalStatusSql: '$6',
4582
+ ownerRunIdSql: 'inputs.run_id',
4583
+ })}
4584
+ ),
4585
+ resolved AS (
4586
+ SELECT ord, k, status, output, error, failure_kind, run_id, lease_id, lease_owner_run_id, lease_owner_attempt, lease_expires_at, updated_at FROM completed
4587
+ UNION ALL
4588
+ SELECT ord, k, status, output, error, failure_kind, run_id, lease_id, lease_owner_run_id, lease_owner_attempt, lease_expires_at, updated_at FROM replay
4589
+ ),
4381
4590
  returned AS (
4382
- SELECT completed.k,
4383
- completed.status,
4384
- completed.output,
4385
- completed.error,
4386
- completed.failure_kind,
4387
- completed.run_id,
4388
- completed.lease_id,
4389
- completed.lease_owner_run_id,
4390
- completed.lease_owner_attempt,
4391
- completed.lease_expires_at,
4392
- completed.updated_at,
4591
+ SELECT resolved.k,
4592
+ resolved.status,
4593
+ resolved.output,
4594
+ resolved.error,
4595
+ resolved.failure_kind,
4596
+ resolved.run_id,
4597
+ resolved.lease_id,
4598
+ resolved.lease_owner_run_id,
4599
+ resolved.lease_owner_attempt,
4600
+ resolved.lease_expires_at,
4601
+ resolved.updated_at,
4393
4602
  inputs.ord
4394
4603
  FROM inputs
4395
- LEFT JOIN completed ON completed.ord = inputs.ord
4604
+ LEFT JOIN resolved ON resolved.ord = inputs.ord
4396
4605
  )
4397
4606
  SELECT convert_from(returned.k, 'UTF8') AS k,
4398
4607
  returned.status,
@@ -4484,8 +4693,31 @@ export async function failRuntimeWorkReceipt(
4484
4693
  lease_owner_attempt,
4485
4694
  lease_expires_at,
4486
4695
  updated_at
4696
+ ),
4697
+ replay AS (
4698
+ SELECT convert_from(k, 'UTF8') AS k,
4699
+ status,
4700
+ output,
4701
+ error,
4702
+ failure_kind,
4703
+ run_id,
4704
+ lease_id,
4705
+ lease_owner_run_id,
4706
+ lease_owner_attempt,
4707
+ lease_expires_at,
4708
+ updated_at
4709
+ FROM ${workReceiptTable(session)}
4710
+ WHERE k = decode($1, 'hex')
4711
+ AND NOT EXISTS (SELECT 1 FROM failed)
4712
+ AND ${workReceiptTerminalReplayPredicateSql({
4713
+ receiptTable: workReceiptTable(session),
4714
+ terminalStatusSql: '$2',
4715
+ ownerRunIdSql: '$4',
4716
+ })}
4487
4717
  )
4488
4718
  SELECT k, status, output, error, failure_kind, run_id, lease_id, lease_owner_run_id, lease_owner_attempt, lease_expires_at, updated_at FROM failed
4719
+ UNION ALL
4720
+ SELECT k, status, output, error, failure_kind, run_id, lease_id, lease_owner_run_id, lease_owner_attempt, lease_expires_at, updated_at FROM replay
4489
4721
  `,
4490
4722
  [
4491
4723
  workReceiptKeyHex(input.key),
@@ -4649,21 +4881,49 @@ export async function failRuntimeWorkReceipts(
4649
4881
  target.updated_at,
4650
4882
  inputs.ord
4651
4883
  ),
4884
+ replay AS (
4885
+ SELECT target.k,
4886
+ target.status,
4887
+ target.output,
4888
+ target.error,
4889
+ target.failure_kind,
4890
+ target.run_id,
4891
+ target.lease_id,
4892
+ target.lease_owner_run_id,
4893
+ target.lease_owner_attempt,
4894
+ target.lease_expires_at,
4895
+ target.updated_at,
4896
+ inputs.ord
4897
+ FROM inputs
4898
+ JOIN ${workReceiptTable(session)} AS target
4899
+ ON target.k = decode(inputs.key_hex, 'hex')
4900
+ WHERE NOT EXISTS (SELECT 1 FROM failed WHERE failed.ord = inputs.ord)
4901
+ AND ${workReceiptTerminalReplayPredicateSql({
4902
+ receiptTable: 'target',
4903
+ terminalStatusSql: '$7',
4904
+ ownerRunIdSql: 'inputs.run_id',
4905
+ })}
4906
+ ),
4907
+ resolved AS (
4908
+ SELECT ord, k, status, output, error, failure_kind, run_id, lease_id, lease_owner_run_id, lease_owner_attempt, lease_expires_at, updated_at FROM failed
4909
+ UNION ALL
4910
+ SELECT ord, k, status, output, error, failure_kind, run_id, lease_id, lease_owner_run_id, lease_owner_attempt, lease_expires_at, updated_at FROM replay
4911
+ ),
4652
4912
  returned AS (
4653
- SELECT failed.k,
4654
- failed.status,
4655
- failed.output,
4656
- failed.error,
4657
- failed.failure_kind,
4658
- failed.run_id,
4659
- failed.lease_id,
4660
- failed.lease_owner_run_id,
4661
- failed.lease_owner_attempt,
4662
- failed.lease_expires_at,
4663
- failed.updated_at,
4913
+ SELECT resolved.k,
4914
+ resolved.status,
4915
+ resolved.output,
4916
+ resolved.error,
4917
+ resolved.failure_kind,
4918
+ resolved.run_id,
4919
+ resolved.lease_id,
4920
+ resolved.lease_owner_run_id,
4921
+ resolved.lease_owner_attempt,
4922
+ resolved.lease_expires_at,
4923
+ resolved.updated_at,
4664
4924
  inputs.ord
4665
4925
  FROM inputs
4666
- LEFT JOIN failed ON failed.ord = inputs.ord
4926
+ LEFT JOIN resolved ON resolved.ord = inputs.ord
4667
4927
  )
4668
4928
  SELECT convert_from(returned.k, 'UTF8') AS k,
4669
4929
  returned.status,
@@ -4892,6 +5152,12 @@ export async function startRuntimeSheetDataset(
4892
5152
  force?: boolean;
4893
5153
  },
4894
5154
  ): Promise<PrepareRuntimeSheetResult> {
5155
+ if (context.dbSessionStrategy === 'gateway_only') {
5156
+ return await postRuntimeApi<PrepareRuntimeSheetResult>(context, {
5157
+ action: 'runtime_sheet_start',
5158
+ input,
5159
+ });
5160
+ }
4895
5161
  const totalStartedAt = Date.now();
4896
5162
  const timings: RuntimeSheetTiming[] = [];
4897
5163
  const playName = context.playName?.trim() || input.playName;
@@ -5283,6 +5549,12 @@ export async function releaseRuntimeSheetAttempt(
5283
5549
  attemptSeq?: number | null;
5284
5550
  },
5285
5551
  ): Promise<RuntimeSheetAttemptReleaseResult> {
5552
+ if (context.dbSessionStrategy === 'gateway_only') {
5553
+ return await postRuntimeApi<RuntimeSheetAttemptReleaseResult>(context, {
5554
+ action: 'runtime_sheet_release_attempt',
5555
+ input,
5556
+ });
5557
+ }
5286
5558
  const playName = context.playName?.trim() || input.playName;
5287
5559
  if (!playName) {
5288
5560
  throw new Error('Runtime sheet attempt release requires a playName.');
@@ -5371,6 +5643,12 @@ export async function releaseRuntimeWorkReceipts(
5371
5643
  runAttempt?: number | null;
5372
5644
  },
5373
5645
  ): Promise<RuntimeWorkReceiptReleaseResult> {
5646
+ if (context.dbSessionStrategy === 'gateway_only') {
5647
+ return await postRuntimeApi<RuntimeWorkReceiptReleaseResult>(context, {
5648
+ action: 'runtime_receipts_release_attempt',
5649
+ input,
5650
+ });
5651
+ }
5374
5652
  const runId = input.runId.trim();
5375
5653
  if (!runId) {
5376
5654
  return { released: 0, releasedKeys: [] };
@@ -5423,7 +5701,7 @@ type CompleteRuntimeMapRowChunksInput = {
5423
5701
  outputFields: string[];
5424
5702
  };
5425
5703
 
5426
- type RuntimeMapRowsWriteResult = {
5704
+ export type RuntimeMapRowsWriteResult = {
5427
5705
  updated: number;
5428
5706
  fencedKeys: string[];
5429
5707
  };
@@ -6344,6 +6622,12 @@ export async function completeRuntimeMapRows(
6344
6622
  forceFailedRows?: boolean;
6345
6623
  },
6346
6624
  ): Promise<RuntimeMapRowsWriteResult> {
6625
+ if (context.dbSessionStrategy === 'gateway_only') {
6626
+ return await postRuntimeApi<RuntimeMapRowsWriteResult>(context, {
6627
+ action: 'runtime_sheet_complete_map_rows',
6628
+ input,
6629
+ });
6630
+ }
6347
6631
  if (input.rows.length === 0) {
6348
6632
  return { updated: 0, fencedKeys: [] };
6349
6633
  }
@@ -6498,6 +6782,12 @@ export async function readRuntimeSheetDatasetRows(
6498
6782
  offset: number;
6499
6783
  },
6500
6784
  ): Promise<{ rows: Record<string, unknown>[]; limit: number; offset: number }> {
6785
+ if (context.dbSessionStrategy === 'gateway_only') {
6786
+ return await postRuntimeApi(context, {
6787
+ action: 'runtime_sheet_read_rows',
6788
+ input,
6789
+ });
6790
+ }
6501
6791
  const limit = Math.max(
6502
6792
  1,
6503
6793
  Math.min(DIRECT_POSTGRES_BATCH_SIZE, Math.floor(input.limit)),
@@ -6540,6 +6830,12 @@ export async function readRuntimeSheetDatasetRowKeys(
6540
6830
  rowMode?: 'output' | 'all' | 'terminalAnyRun';
6541
6831
  },
6542
6832
  ): Promise<{ keys: string[] }> {
6833
+ if (context.dbSessionStrategy === 'gateway_only') {
6834
+ return await postRuntimeApi(context, {
6835
+ action: 'runtime_sheet_read_row_keys',
6836
+ input,
6837
+ });
6838
+ }
6543
6839
  const keys = [
6544
6840
  ...new Set(
6545
6841
  input.keys.map((key) => key.trim()).filter((key) => key.length > 0),
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Runtime-scheduler topology predicate shared by the app-side lane helpers
3
+ * (`src/lib/plays/scheduler-backends/absurd-shared.ts`) and the runner
4
+ * backends (`runner-backends/backends/daytona-lifecycle.ts`).
5
+ *
6
+ * ONE distinction drives several guards: a run whose scheduler schema is the
7
+ * prod default rides the production topology (base queue names, customer code,
8
+ * production egress policy), while any other schema is an ISOLATED topology —
9
+ * a per-PR preview fleet or a per-worktree dev fleet running synthetic
10
+ * internal test plays. Keeping the predicate here (dependency-free) lets
11
+ * shared_libs code use it without importing the app-side scheduler stack.
12
+ */
13
+ export const PROD_DEFAULT_RUNTIME_SCHEDULER_SCHEMA = 'runtime_scheduler';
14
+
15
+ /**
16
+ * True when the scheduler schema names an isolated (preview CI / worktree)
17
+ * topology. Null/empty/prod-default => false (production topology). Callers
18
+ * that gate SECURITY policy on this must treat `false` as the fail-closed
19
+ * production posture — an absent schema is production, never "unknown".
20
+ */
21
+ export function isIsolatedRuntimeSchedulerSchema(
22
+ schedulerSchema: string | null | undefined,
23
+ ): boolean {
24
+ const schema = schedulerSchema?.trim();
25
+ return Boolean(schema) && schema !== PROD_DEFAULT_RUNTIME_SCHEDULER_SCHEMA;
26
+ }
@@ -18,6 +18,7 @@ import type {
18
18
  import type { ExecutionPlan } from './execution-plan';
19
19
  import type { PlayRuntimeManifestMap } from '../plays/compiler-manifest';
20
20
  import type { PreloadedRuntimeDbSession } from './db-session';
21
+ import type { RuntimeAuthorityDescriptor } from './execution-capabilities';
21
22
  import type { PlayRunnerRuntimeTiming } from './protocol';
22
23
  import type { RuntimeTestPolicyOverrides } from './test-runtime-seams';
23
24
  import type { PlayRunInputPayload } from './play-input';
@@ -123,9 +124,21 @@ export type PlaySchedulerSubmitInput = {
123
124
  childPlayManifests?: PlayRuntimeManifestMap | null;
124
125
  playCallGovernance?: PlayCallGovernanceSnapshot | null;
125
126
  preloadedDbSessions?: PreloadedRuntimeDbSession[] | null;
127
+ /**
128
+ * Secret that decrypts `preloadedDbSessions` postgres URLs. Equals the run's
129
+ * original submit-time executor (authority) token that AES-GCM sealed the
130
+ * sessions. Held separately from `executorToken` because durable schedulers
131
+ * re-mint a per-attempt `executorToken` (adding `run_attempt`/capabilities
132
+ * claims) for API auth; that re-minted string is NOT valid decryption key
133
+ * material for sessions sealed under the original token. The worker/runner use
134
+ * this field for DB-session unwrap and the re-minted `executorToken` for auth.
135
+ */
136
+ preloadedDbSessionUnwrapKey?: string | null;
126
137
  /** Optional immutable Worker module source for local Dynamic Worker loading. */
127
138
  dynamicWorkerCode?: string | null;
128
139
  executorToken: string;
140
+ /** Immutable facts used by durable schedulers to mint a fresh leg token. */
141
+ runtimeAuthority: RuntimeAuthorityDescriptor;
129
142
  /**
130
143
  * Public app origin used by Workers to call Deepline runtime API routes.
131
144
  * When omitted, legacy schedulers fall back to baseUrl.
@@ -151,6 +164,14 @@ export type PlaySchedulerSubmitInput = {
151
164
  coordinatorInternalToken?: string | null;
152
165
  /** Runtime deploy generation/version that owns this run, when known. */
153
166
  runtimeDeployVersion?: string | null;
167
+ /**
168
+ * Absurd release lane that owns this run for its whole life (children, parks,
169
+ * wakes, retries). Stamped at launch by the absurd scheduler backend and
170
+ * persisted inside launch_json. The worker derives the run's queue from this,
171
+ * never from process-local config. Absent on pre-release launch rows, in which
172
+ * case the worker falls back to the dev-collapse id (today's queue).
173
+ */
174
+ absurdReleaseId?: string | null;
154
175
  /** Request-scoped Vercel Deployment Protection bypass for preview runtime callbacks. */
155
176
  vercelProtectionBypassToken?: string | null;
156
177
  /** Request-scoped, dev-only runtime fault injection header for black-box durability tests. */
@@ -4,6 +4,7 @@ const PLAY_DATASET_BRAND = Symbol.for('deepline.play.dataset');
4
4
  const NODE_INSPECT_CUSTOM = Symbol.for('nodejs.util.inspect.custom');
5
5
  const DEFAULT_MATERIALIZE_LIMIT = 10_000;
6
6
  export const PLAY_DATASET_EXECUTION_PAGE_ROWS = 1_000;
7
+ export const PLAY_DATASET_EXECUTION_PAGE_BYTES = 64 * 1024 * 1024;
7
8
 
8
9
  export type PlayDatasetKind = 'csv' | 'map';
9
10
 
@@ -545,6 +546,8 @@ export type MaterializePlayDatasetInputOptions<T> = {
545
546
 
546
547
  export type IteratePlayDatasetInputPagesOptions<T> = {
547
548
  pageSize?: number;
549
+ maxPageBytes?: number;
550
+ estimateRowBytes?: (row: T) => number;
548
551
  onRow?: (row: T, index: number) => void;
549
552
  };
550
553
 
@@ -560,21 +563,40 @@ export async function* iteratePlayDatasetInputPages<T>(
560
563
  options?: IteratePlayDatasetInputPagesOptions<T>,
561
564
  ): AsyncIterable<{ rows: T[]; offset: number }> {
562
565
  const pageSize = normalizeDatasetExecutionPageSize(options?.pageSize);
566
+ const maxPageBytes = Math.max(
567
+ 1,
568
+ Math.floor(options?.maxPageBytes ?? PLAY_DATASET_EXECUTION_PAGE_BYTES),
569
+ );
570
+ const estimateRowBytes =
571
+ options?.estimateRowBytes ??
572
+ ((row: T) => {
573
+ const serialized = JSON.stringify(row);
574
+ return serialized === undefined ? 0 : serialized.length;
575
+ });
563
576
  let page: T[] = [];
577
+ let pageBytes = 0;
564
578
  let offset = 0;
565
579
  let index = 0;
566
- const pushRow = (row: T): { rows: T[]; offset: number } | null => {
580
+ const pushRow = (row: T): Array<{ rows: T[]; offset: number }> => {
567
581
  options?.onRow?.(row, index);
568
582
  index += 1;
583
+ const rowBytes = Math.max(0, Math.ceil(estimateRowBytes(row)));
584
+ const ready: Array<{ rows: T[]; offset: number }> = [];
585
+ if (page.length > 0 && pageBytes + rowBytes > maxPageBytes) {
586
+ ready.push({ rows: page, offset });
587
+ offset += page.length;
588
+ page = [];
589
+ pageBytes = 0;
590
+ }
569
591
  page.push(row);
570
- if (page.length < pageSize) {
571
- return null;
592
+ pageBytes += rowBytes;
593
+ if (page.length >= pageSize || pageBytes >= maxPageBytes) {
594
+ ready.push({ rows: page, offset });
595
+ offset += page.length;
596
+ page = [];
597
+ pageBytes = 0;
572
598
  }
573
- const fullPage = page;
574
- const fullOffset = offset;
575
- page = [];
576
- offset += fullPage.length;
577
- return { rows: fullPage, offset: fullOffset };
599
+ return ready;
578
600
  };
579
601
 
580
602
  const flush = (): { rows: T[]; offset: number } | null => {
@@ -582,13 +604,13 @@ export async function* iteratePlayDatasetInputPages<T>(
582
604
  const finalPage = page;
583
605
  const finalOffset = offset;
584
606
  page = [];
607
+ pageBytes = 0;
585
608
  offset += finalPage.length;
586
609
  return { rows: finalPage, offset: finalOffset };
587
610
  };
588
611
 
589
612
  const emitRow = async function* (row: T) {
590
- const ready = pushRow(row);
591
- if (ready) yield ready;
613
+ for (const ready of pushRow(row)) yield ready;
592
614
  };
593
615
 
594
616
  if (isPlayDataset(input)) {