deepline 0.3.315 → 0.3.317

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 (134) hide show
  1. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  2. package/dist/bundling-sources/sdk/src/runs/overview.ts +17 -10
  3. package/dist/bundling-sources/sdk/src/types.ts +6 -5
  4. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +64 -0
  5. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +217 -488
  6. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +15 -0
  7. package/dist/bundling-sources/shared_libs/play-runtime/execution-capabilities.ts +4 -1
  8. package/dist/bundling-sources/shared_libs/play-runtime/internal-bootstrap-token.ts +13 -4
  9. package/dist/bundling-sources/shared_libs/play-runtime/launch-identity.ts +1 -0
  10. package/dist/bundling-sources/shared_libs/play-runtime/live-events.ts +31 -0
  11. package/dist/bundling-sources/shared_libs/play-runtime/map-execution-frame.ts +444 -51
  12. package/dist/bundling-sources/shared_libs/play-runtime/run-snapshot-stream.ts +22 -43
  13. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +4 -3
  14. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +136 -87
  15. package/dist/bundling-sources/shared_libs/play-runtime/runtime-authority.ts +24 -6
  16. package/dist/bundling-sources/shared_libs/play-runtime/runtime-operation-contract.ts +56 -0
  17. package/dist/bundling-sources/shared_libs/play-runtime/runtime-sheet-errors.ts +94 -0
  18. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +2 -0
  19. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-shared.ts +5 -2
  20. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd.ts +20 -11
  21. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-progress.ts +18 -12
  22. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +396 -35
  23. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-dispatch-authority.ts +2 -0
  24. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-outbox-recovery.ts +123 -19
  25. package/dist/bundling-sources/shared_libs/play-runtime/work-receipt-storage-contract.ts +13 -0
  26. package/dist/bundling-sources/shared_libs/play-runtime/workflow-executor-auth.ts +2 -0
  27. package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +3 -2
  28. package/dist/cli/auth-XPLGQ2KO.js +31 -0
  29. package/dist/cli/{auth-OVWOO5NP.mjs → auth-YAHBE5WU.mjs} +4 -4
  30. package/dist/cli/{billing-W3OXKWNE.mjs → billing-AY4OS7MR.mjs} +4 -4
  31. package/dist/cli/{billing-SRZL7UOH.js → billing-ORZDEMH2.js} +70 -70
  32. package/dist/cli/{chunk-OJP4FCCX.js → chunk-2FKXFTOF.js} +48 -48
  33. package/dist/cli/{chunk-OJ243ZA5.js → chunk-2HKPAZVJ.js} +1 -1
  34. package/dist/cli/{chunk-LOWURQMF.js → chunk-342BTES3.js} +50 -50
  35. package/dist/cli/{chunk-FGAK6FET.js → chunk-3NRNDPAE.js} +26 -26
  36. package/dist/cli/{chunk-GK67FYMS.mjs → chunk-5BLF3HDM.mjs} +5 -5
  37. package/dist/cli/{chunk-TZ5KUDPP.mjs → chunk-5OFRM64Y.mjs} +1 -1
  38. package/dist/cli/{chunk-US4S3E4Y.mjs → chunk-7PZFGB7L.mjs} +1 -1
  39. package/dist/cli/{chunk-YL42TF53.js → chunk-AMJYFPFK.js} +6 -6
  40. package/dist/cli/{chunk-PPONZ6IE.js → chunk-AW355CLN.js} +15 -15
  41. package/dist/cli/{chunk-TQK662WG.js → chunk-BGBYK2T3.js} +60 -60
  42. package/dist/cli/{chunk-TQ3F77AC.mjs → chunk-CGGM4CE6.mjs} +3 -3
  43. package/dist/cli/{chunk-FTJQO757.mjs → chunk-D5MHSO5T.mjs} +1 -1
  44. package/dist/cli/{chunk-Y42UERUY.js → chunk-DSTUP75H.js} +6 -6
  45. package/dist/cli/{chunk-HNKHMHJ7.mjs → chunk-FRK2AGSG.mjs} +1 -1
  46. package/dist/cli/{chunk-OUIIYFG3.mjs → chunk-GX3WO4M4.mjs} +2 -2
  47. package/dist/cli/{chunk-OYJCNCUW.js → chunk-GYOLWON6.js} +2 -2
  48. package/dist/cli/{chunk-N5V2SBB2.mjs → chunk-KP7W5NO6.mjs} +1 -1
  49. package/dist/cli/{chunk-L5TSFCJ6.mjs → chunk-KXOXXVYJ.mjs} +2 -2
  50. package/dist/cli/{chunk-B473QUQU.mjs → chunk-L6ERGROE.mjs} +4 -4
  51. package/dist/cli/{chunk-R3IFZDJL.mjs → chunk-LI6YPPBR.mjs} +2 -2
  52. package/dist/cli/{chunk-IGE7EJJY.mjs → chunk-NDFBAMVI.mjs} +19 -15
  53. package/dist/cli/{chunk-JF4O5OMH.mjs → chunk-OTI562P3.mjs} +1 -1
  54. package/dist/cli/{chunk-AO4IWPP7.mjs → chunk-PSHIZP3K.mjs} +17 -15
  55. package/dist/cli/{chunk-VYK23G2C.js → chunk-QFKVAUIQ.js} +239 -235
  56. package/dist/cli/{chunk-AZWQJAQF.mjs → chunk-QPKHOZI3.mjs} +1 -1
  57. package/dist/cli/{chunk-URVZGYGG.js → chunk-SUPQQYGY.js} +4 -4
  58. package/dist/cli/{chunk-C5WSTXUB.js → chunk-TJ2V2JA3.js} +537 -535
  59. package/dist/cli/{chunk-6BJACIVK.js → chunk-UGQHYOT4.js} +1 -1
  60. package/dist/cli/{chunk-IALPYID6.js → chunk-XSEMQ4II.js} +3 -3
  61. package/dist/cli/{chunk-SNFSO2AN.js → chunk-Z5NRL7A7.js} +6 -6
  62. package/dist/cli/{client-WQ3J5BSH.mjs → client-QNLVLW54.mjs} +3 -3
  63. package/dist/cli/client-ZW5VAHWD.js +20 -0
  64. package/dist/cli/{csv-36ARCBNQ.mjs → csv-AKZASZP6.mjs} +3 -3
  65. package/dist/cli/{csv-CENMEWDH.js → csv-PW6S3SMJ.js} +12 -12
  66. package/dist/cli/{db-JU7XLKQM.mjs → db-DNF53LDS.mjs} +4 -4
  67. package/dist/cli/{db-6DQZG6NB.js → db-FLDYET2D.js} +20 -20
  68. package/dist/cli/{describe-VUD4AFBY.js → describe-JDAEOCYQ.js} +17 -17
  69. package/dist/cli/{describe-34ALEEFO.mjs → describe-U6RGIFMA.mjs} +10 -10
  70. package/dist/cli/{executions-H2UXS6FP.js → executions-DASCB6LS.js} +6 -6
  71. package/dist/cli/{executions-H66BMN6N.mjs → executions-W6BBU2HN.mjs} +4 -4
  72. package/dist/cli/{feedback-Q7LXXLSH.mjs → feedback-BVWPDWZG.mjs} +3 -3
  73. package/dist/cli/{feedback-YSYFQSAB.js → feedback-N3MBCT4A.js} +6 -6
  74. package/dist/cli/{git-XV43NSWN.mjs → git-4GJOKOLU.mjs} +4 -4
  75. package/dist/cli/git-WVHH3QXQ.js +23 -0
  76. package/dist/cli/index.js +171 -98
  77. package/dist/cli/index.mjs +114 -41
  78. package/dist/cli/{legacy-noops-Z2DTZQN3.mjs → legacy-noops-5XMSV7WL.mjs} +4 -4
  79. package/dist/cli/{legacy-noops-RGDW6SCA.js → legacy-noops-D7C7ZVKK.js} +7 -7
  80. package/dist/cli/{monitors-I75KZ2BP.js → monitors-NYP4LG3K.js} +85 -85
  81. package/dist/cli/{monitors-OFQ56O4S.mjs → monitors-Y4RKWAS5.mjs} +4 -4
  82. package/dist/cli/{org-75AH6RIB.js → org-PYKQMP6F.js} +60 -60
  83. package/dist/cli/{org-ZYMCU6XO.mjs → org-XZ26CUCV.mjs} +4 -4
  84. package/dist/cli/play-BYZCR4PP.js +152 -0
  85. package/dist/cli/{play-BKXM76DV.mjs → play-FYHIYZ3W.mjs} +9 -9
  86. package/dist/cli/{providers-GWG2WFIY.mjs → providers-3UG7NK55.mjs} +4 -4
  87. package/dist/cli/{providers-Z77MM7ID.js → providers-QS5X236G.js} +7 -7
  88. package/dist/cli/{quickstart-I4RECIQC.js → quickstart-GMASUT7T.js} +5 -5
  89. package/dist/cli/{quickstart-BGVIV374.mjs → quickstart-PHHHHHWO.mjs} +3 -3
  90. package/dist/cli/search-52CC3OVI.js +26 -0
  91. package/dist/cli/{search-TIKBP3RE.mjs → search-AVGITJP4.mjs} +5 -5
  92. package/dist/cli/{secrets-SNGRI4KS.js → secrets-HY5E6F6G.js} +13 -13
  93. package/dist/cli/{secrets-YCHKLWKC.mjs → secrets-RBEZRQ6P.mjs} +4 -4
  94. package/dist/cli/{sessions-WXLADGDX.js → sessions-7CDLWLVV.js} +5 -5
  95. package/dist/cli/{sessions-IRDG6ZRX.mjs → sessions-ME5R5FTG.mjs} +4 -4
  96. package/dist/cli/{settings-KZALJDXW.mjs → settings-X4JQLBB6.mjs} +7 -7
  97. package/dist/cli/{settings-72J4BVF6.js → settings-ZCVJPOFP.js} +74 -74
  98. package/dist/cli/{setup-FFB3KLFD.js → setup-DROGU6MC.js} +41 -41
  99. package/dist/cli/{setup-4KCA7ESV.mjs → setup-NEILS2UF.mjs} +6 -6
  100. package/dist/cli/skills-KUV3WWW5.js +28 -0
  101. package/dist/cli/{skills-MQZPYUQ3.mjs → skills-PC57GDXZ.mjs} +4 -4
  102. package/dist/cli/{tools-M3WKRZ5T.mjs → tools-IFJUWQC5.mjs} +6 -6
  103. package/dist/cli/tools-NHDAOQPB.js +38 -0
  104. package/dist/cli/update-DRWQCVXJ.js +28 -0
  105. package/dist/cli/{update-QJMNYGNF.mjs → update-N4HSH2TJ.mjs} +6 -6
  106. package/dist/cli/{workflow-6T2EUFCN.mjs → workflow-2OZBTUU2.mjs} +5 -5
  107. package/dist/cli/{workflow-35UUOZ5E.js → workflow-LP4Z6RF5.js} +15 -15
  108. package/dist/{client-Dh_4Ph1R.d.ts → client-BV68GMPo.d.ts} +7 -6
  109. package/dist/{client-CvpZsBqt.d.mts → client-D9ACjiRC.d.mts} +7 -6
  110. package/dist/{compiler-manifest-wOKNiXpa.d.mts → compiler-manifest-BXcZ4P4W.d.mts} +2 -2
  111. package/dist/{compiler-manifest-wOKNiXpa.d.ts → compiler-manifest-BXcZ4P4W.d.ts} +2 -2
  112. package/dist/index.d.mts +4 -4
  113. package/dist/index.d.ts +4 -4
  114. package/dist/index.js +7 -7
  115. package/dist/index.mjs +4 -4
  116. package/dist/install-integrity.json +82 -82
  117. package/dist/plays/bundle-play-file.d.mts +2 -2
  118. package/dist/plays/bundle-play-file.d.ts +2 -2
  119. package/dist/plays/bundle-play-file.mjs +2 -2
  120. package/dist/plays/run-request.d.mts +2 -2
  121. package/dist/plays/run-request.d.ts +2 -2
  122. package/dist/release.d.mts +1 -1
  123. package/dist/release.d.ts +1 -1
  124. package/dist/release.js +2 -2
  125. package/dist/release.mjs +1 -1
  126. package/package.json +1 -1
  127. package/dist/cli/auth-P2TTZU36.js +0 -31
  128. package/dist/cli/client-CXFPFCIG.js +0 -20
  129. package/dist/cli/git-SYFCYIFP.js +0 -23
  130. package/dist/cli/play-OKXUWPMO.js +0 -152
  131. package/dist/cli/search-3KISUDDT.js +0 -26
  132. package/dist/cli/skills-XGOK4GRW.js +0 -28
  133. package/dist/cli/tools-LEAJ7EPW.js +0 -38
  134. package/dist/cli/update-ZN6LDUHS.js +0 -28
@@ -1,3 +1,15 @@
1
+ import {
2
+ RuntimeSheetAttemptSupersededError,
3
+ RuntimeSheetWriteIntentUnavailableError,
4
+ type RuntimeMapRowsStaleReason,
5
+ type RuntimeMapRowsStaleRow,
6
+ } from './runtime-sheet-errors';
7
+ export {
8
+ RuntimeSheetAttemptSupersededError,
9
+ RuntimeSheetWriteIntentUnavailableError,
10
+ type RuntimeMapRowsStaleReason,
11
+ type RuntimeMapRowsStaleRow,
12
+ } from './runtime-sheet-errors';
1
13
  import {
2
14
  prepareRetainedPlayPipelinesForTransport,
3
15
  hydrateRetainedPlayPipelines,
@@ -74,6 +86,7 @@ import {
74
86
  } from './db-session-crypto';
75
87
  import { createRuntimeDatasetId } from './dataset-id';
76
88
  import {
89
+ buildScopedWorkReceiptKey,
77
90
  scopedWorkReceiptKeyPrefix,
78
91
  isReusableWorkReceipt,
79
92
  type WorkReceipt,
@@ -88,7 +101,10 @@ import {
88
101
  stringifyPostgresJson,
89
102
  } from './postgres-json';
90
103
  import { RECEIPT_STATUS_CODE, receiptStatusFromCode } from './receipt-status';
91
- import { WORK_RECEIPT_EXECUTION_LOCK_TABLE } from './work-receipt-storage-contract';
104
+ import {
105
+ WORK_RECEIPT_EXECUTION_LOCK_TABLE,
106
+ RUNTIME_SHEET_WRITE_INTENT_RECEIPT_KIND,
107
+ } from './work-receipt-storage-contract';
92
108
  import {
93
109
  workReceiptClaimableStatusCodes,
94
110
  workReceiptActiveOwnerPredicateSql,
@@ -103,6 +119,7 @@ import {
103
119
  } from './sheet-attempt-sql';
104
120
  import type { MapRowOutcome } from './durability-store';
105
121
  import { RUNTIME_CAPACITY_POLICY } from './runtime-capacity-policy';
122
+ import type { RUNTIME_SHEET_ADMISSION_CAPABILITIES } from './runtime-operation-contract';
106
123
  import {
107
124
  normalizeRuntimeMapInputIndex,
108
125
  prepareRuntimeSheetRowsForJsonTransport,
@@ -562,7 +579,7 @@ type RuntimeApiActionRequest =
562
579
  runId?: string | null;
563
580
  }
564
581
  | {
565
- action: 'runtime_sheet_start';
582
+ action: keyof typeof RUNTIME_SHEET_ADMISSION_CAPABILITIES;
566
583
  input: Parameters<typeof startRuntimeSheetDataset>[1];
567
584
  }
568
585
  | {
@@ -960,6 +977,17 @@ async function postRuntimeApi<TResponse>(
960
977
  ]
961
978
  .filter((value): value is string => Boolean(value))
962
979
  .join(', ');
980
+ if (
981
+ body.action === 'runtime_sheet_start_with_intent' &&
982
+ (response.status === 400 || response.status === 403) &&
983
+ (errorMessage === 'Unsupported runtime action capability scope.' ||
984
+ errorMessage === 'Unsupported runtime data-plane action.' ||
985
+ errorMessage === `Unsupported action: ${body.action}`)
986
+ ) {
987
+ throw new RuntimeSheetWriteIntentUnavailableError(
988
+ new Error(`${errorMessage} (${diagnosticContext}).`),
989
+ );
990
+ }
963
991
  throw new Error(
964
992
  details
965
993
  ? `${errorMessage} (${diagnosticContext}): ${details}`
@@ -989,7 +1017,8 @@ function runtimeApiRequestTimeoutMs(
989
1017
  if (action === 'runtime_sheet_complete_map_rows') {
990
1018
  return RUNTIME_SHEET_COMPLETION_REQUEST_TIMEOUT_MS;
991
1019
  }
992
- return action === 'runtime_sheet_start'
1020
+ return action === 'runtime_sheet_start' ||
1021
+ action === 'runtime_sheet_start_with_intent'
993
1022
  ? RUNTIME_SHEET_ADMISSION_REQUEST_TIMEOUT_MS
994
1023
  : RUNTIME_API_REQUEST_TIMEOUT_MS;
995
1024
  }
@@ -3073,6 +3102,92 @@ async function mintRuntimeSheetWriteVersion(
3073
3102
  return value;
3074
3103
  }
3075
3104
 
3105
+ /**
3106
+ * One run/table admits one write intent, independently of runner attempts and
3107
+ * source pages. Publish its immutable scalar in the row-admission transaction:
3108
+ * a lost response or checkpoint cannot turn a wake into newer customer intent.
3109
+ * Older callers without the opt-in retain the existing allocation behavior.
3110
+ */
3111
+ async function resolveRuntimeSheetWriteVersion(
3112
+ client: RuntimeQueryClient,
3113
+ session: RuntimePostgresSession,
3114
+ input: Pick<
3115
+ Parameters<typeof startRuntimeSheetDataset>[1],
3116
+ 'runId' | 'tableNamespace' | 'writeVersion' | 'stableWriteIntent'
3117
+ >,
3118
+ ): Promise<number> {
3119
+ if (input.stableWriteIntent !== true) {
3120
+ return await mintRuntimeSheetWriteVersion(
3121
+ client,
3122
+ session,
3123
+ input.writeVersion,
3124
+ );
3125
+ }
3126
+ const key = buildScopedWorkReceiptKey({
3127
+ orgId: session.target.orgId,
3128
+ playName: session.playName,
3129
+ key: JSON.stringify([
3130
+ RUNTIME_SHEET_WRITE_INTENT_RECEIPT_KIND,
3131
+ input.runId,
3132
+ normalizeTableNamespace(input.tableNamespace),
3133
+ ]),
3134
+ });
3135
+ const keyHex = workReceiptKeyHex(key);
3136
+ type WriteIntentReceipt = {
3137
+ status: number;
3138
+ run_id: string;
3139
+ output: { writeVersion?: unknown } | null;
3140
+ };
3141
+ const read = async () => {
3142
+ const { rows } = await client.query<WriteIntentReceipt>(
3143
+ `SELECT status, run_id, output FROM ${workReceiptTable(session)} WHERE k = decode($1, 'hex')`,
3144
+ [keyHex],
3145
+ );
3146
+ return rows[0];
3147
+ };
3148
+ let receipt = await read();
3149
+ if (!receipt) {
3150
+ const candidate = await mintRuntimeSheetWriteVersion(
3151
+ client,
3152
+ session,
3153
+ input.writeVersion,
3154
+ );
3155
+ const { rows } = await client.query<WriteIntentReceipt>(
3156
+ `INSERT INTO ${workReceiptTable(session)} (k, status, output, run_id)
3157
+ VALUES (decode($1, 'hex'), $2::smallint, $3::jsonb, $4)
3158
+ ON CONFLICT (k) DO NOTHING
3159
+ RETURNING status, run_id, output`,
3160
+ [
3161
+ keyHex,
3162
+ RECEIPT_STATUS_COMPLETED,
3163
+ stringifyPostgresJson({ writeVersion: candidate }),
3164
+ input.runId,
3165
+ ],
3166
+ );
3167
+ // A conflicting INSERT may wait for its winner. A new statement is needed
3168
+ // to see that commit under READ COMMITTED; never use the losing candidate.
3169
+ receipt = rows[0] ?? (await read());
3170
+ }
3171
+ const version = receipt?.output?.writeVersion;
3172
+ if (
3173
+ receipt?.status !== RECEIPT_STATUS_COMPLETED ||
3174
+ receipt.run_id !== input.runId ||
3175
+ typeof version !== 'number' ||
3176
+ !Number.isSafeInteger(version) ||
3177
+ version <= 0
3178
+ ) {
3179
+ throw new Error(
3180
+ 'Runtime sheet write intent did not contain its admitted version.',
3181
+ );
3182
+ }
3183
+ if (input.writeVersion != null && input.writeVersion !== version) {
3184
+ throw new Error(
3185
+ 'Runtime sheet writeVersion disagrees with its admitted write intent.',
3186
+ );
3187
+ }
3188
+ return version;
3189
+ }
3190
+
3076
3191
  function parseRuntimeCellMeta(value: unknown): Record<string, unknown> {
3077
3192
  if (value && typeof value === 'object' && !Array.isArray(value)) {
3078
3193
  return value as Record<string, unknown>;
@@ -6558,6 +6673,14 @@ export async function skipRuntimeWorkReceipt(
6558
6673
  );
6559
6674
  }
6560
6675
 
6676
+ /**
6677
+ * Prepare one dataset page and return its row dispositions and write version.
6678
+ * With stableWriteIntent, the first admission for a run/table is durable in
6679
+ * the same transaction as its rows; subsequent pages and wakes reuse it even
6680
+ * after losing all runner-local state. A new run admits a newer intent.
6681
+ * Gateway transport uses a named operation; an older receiver cannot silently
6682
+ * ignore this opt-in or trigger unsafe legacy admission.
6683
+ */
6561
6684
  export async function startRuntimeSheetDataset(
6562
6685
  context: RuntimeApiContext,
6563
6686
  input: {
@@ -6573,6 +6696,8 @@ export async function startRuntimeSheetDataset(
6573
6696
  attemptSeq?: number | null;
6574
6697
  attemptLeaseTtlMs?: number | null;
6575
6698
  writeVersion?: number | null;
6699
+ /** Retain this run/table's first admission across pages, retries and wakes. Absence keeps legacy allocation. */
6700
+ stableWriteIntent?: boolean;
6576
6701
  inputOffset?: number;
6577
6702
  force?: boolean;
6578
6703
  mode?: RuntimeSheetDatasetMode;
@@ -6582,7 +6707,12 @@ export async function startRuntimeSheetDataset(
6582
6707
  ): Promise<PrepareRuntimeSheetResult> {
6583
6708
  if (context.dbSessionStrategy === 'gateway_only') {
6584
6709
  return await postRuntimeApi<PrepareRuntimeSheetResult>(context, {
6585
- action: 'runtime_sheet_start',
6710
+ // A named operation prevents an old gateway from silently ignoring the
6711
+ // intent opt-in and re-admitting this run under a new version.
6712
+ action:
6713
+ input.stableWriteIntent === true
6714
+ ? 'runtime_sheet_start_with_intent'
6715
+ : 'runtime_sheet_start',
6586
6716
  input: { ...input, pendingRerunAdmission: true },
6587
6717
  });
6588
6718
  }
@@ -6738,10 +6868,10 @@ export async function startRuntimeSheetDataset(
6738
6868
  client,
6739
6869
  input.attemptLeaseTtlMs,
6740
6870
  );
6741
- const writeVersion = await mintRuntimeSheetWriteVersion(
6871
+ const writeVersion = await resolveRuntimeSheetWriteVersion(
6742
6872
  client,
6743
6873
  session,
6744
- input.writeVersion,
6874
+ input,
6745
6875
  );
6746
6876
  const columnTypes = await RuntimeSheetColumns.prepareWrite(client, {
6747
6877
  schema: session.postgres.schema,
@@ -7258,35 +7388,6 @@ type CompleteRuntimeMapRowChunksInput = {
7258
7388
  outputFields: string[];
7259
7389
  };
7260
7390
 
7261
- /**
7262
- * Why a terminal row write was rejected as stale. Runtime Sheet rows are fenced
7263
- * by their schedule-time `_write_version` alone (the legacy attempt-lease
7264
- * predicates are stubbed to TRUE/FALSE in sheet-attempt-sql.ts), so a stale
7265
- * versioned write always means the row is owned by a different admission than
7266
- * the one the writer carries:
7267
- * - `newer_write_version`: a later admission (rerun, resumed attempt, or a
7268
- * concurrent run of the same play) re-admitted the row after this writer
7269
- * admitted it.
7270
- * - `older_write_version`: the row was admitted under an older version than
7271
- * the writer sent; the writer's version never admitted this row.
7272
- * - `already_terminal`: an unversioned writer hit an already-enriched row.
7273
- * Nothing is being overwritten, so this is the one benign reason.
7274
- * - `unreported`: the gateway returned stale keys without reasons (predates
7275
- * this field). Treated as superseded: every stale versioned write is.
7276
- */
7277
- export type RuntimeMapRowsStaleReason =
7278
- | 'newer_write_version'
7279
- | 'older_write_version'
7280
- | 'already_terminal'
7281
- | 'unreported';
7282
-
7283
- export type RuntimeMapRowsStaleRow = {
7284
- key: string;
7285
- reason: RuntimeMapRowsStaleReason;
7286
- /** The admission version currently stamped on the sheet row. */
7287
- rowVersionStamp: number | null;
7288
- };
7289
-
7290
7391
  export type RuntimeMapRowsWriteResult = {
7291
7392
  /** Submitted row identities durably accepted, including idempotent replays. */
7292
7393
  committedKeys: string[];
@@ -7417,58 +7518,6 @@ export function supersededRuntimeMapRows(
7417
7518
  return superseded;
7418
7519
  }
7419
7520
 
7420
- /**
7421
- * A terminal write batch was explicitly marked as an attempt-wide
7422
- * supersession. Retained for compatibility with older terminal-write handlers
7423
- * and the Context's explicit `supersededKeys` stop signal. The current
7424
- * runner-app writer reports ordinary stale latest-view rows without throwing
7425
- * this error.
7426
- */
7427
- export class RuntimeSheetAttemptSupersededError extends Error {
7428
- readonly tableNamespace: string;
7429
- readonly runId: string;
7430
- readonly writeVersion: number | null;
7431
- readonly submittedRows: number;
7432
- readonly supersededRows: RuntimeMapRowsStaleRow[];
7433
-
7434
- constructor(input: {
7435
- tableNamespace: string;
7436
- runId: string;
7437
- writeVersionValue: number | null;
7438
- submittedRows: number;
7439
- supersededRows: RuntimeMapRowsStaleRow[];
7440
- }) {
7441
- const reasonCounts = new Map<RuntimeMapRowsStaleReason, number>();
7442
- for (const row of input.supersededRows) {
7443
- reasonCounts.set(row.reason, (reasonCounts.get(row.reason) ?? 0) + 1);
7444
- }
7445
- const reasons = [...reasonCounts.entries()]
7446
- .map(([reason, count]) => `${reason}=${count}`)
7447
- .join(', ');
7448
- const samples = input.supersededRows
7449
- .slice(0, 5)
7450
- .map(
7451
- (row) =>
7452
- `key=${row.key} row_write_version=${row.rowVersionStamp ?? 'unknown'}`,
7453
- )
7454
- .join('; ');
7455
- super(
7456
- `RUNTIME_SHEET_ATTEMPT_SUPERSEDED: Runtime Sheet table "${input.tableNamespace}" ` +
7457
- `rejected ${input.supersededRows.length} of ${input.submittedRows} terminal row write(s) ` +
7458
- `from run ${input.runId} at write version ${input.writeVersionValue ?? 'none'} ` +
7459
- `because the rows are owned by a different write version (${reasons || 'unreported'}). ` +
7460
- `This attempt has been superseded by a newer admission of these rows and must stop ` +
7461
- `executing: nothing it persists from here on can be accepted. Sample: ${samples}.`,
7462
- );
7463
- this.name = 'RuntimeSheetAttemptSupersededError';
7464
- this.tableNamespace = input.tableNamespace;
7465
- this.runId = input.runId;
7466
- this.writeVersion = input.writeVersionValue;
7467
- this.submittedRows = input.submittedRows;
7468
- this.supersededRows = input.supersededRows;
7469
- }
7470
- }
7471
-
7472
7521
  export function isRuntimeSheetAttemptSupersededError(
7473
7522
  error: unknown,
7474
7523
  ): error is RuntimeSheetAttemptSupersededError {
@@ -11,6 +11,8 @@ import type { DirectCompletedTerminalContract } from './/scheduler-backends/term
11
11
 
12
12
  export type RuntimeAuthority = {
13
13
  executorToken: string;
14
+ /** Narrow credential for append-only Run Ledger projection from a leased outbox. */
15
+ runLedgerExecutorToken: string;
14
16
  descriptor: RuntimeAuthorityDescriptor;
15
17
  };
16
18
 
@@ -60,13 +62,25 @@ export function deriveAsyncChildRuntimeAuthority(input: {
60
62
  export async function mintPlayRunRuntimeAuthorityDescriptor(input: {
61
63
  descriptor: RuntimeAuthorityDescriptor;
62
64
  runtimeOrigin?: string | null;
65
+ /** Current immutable app receiver; absent retains legacy delivery grouping. */
66
+ runLedgerIngressPrefixOrigin?: string | null;
63
67
  }): Promise<RuntimeAuthority> {
64
- return {
65
- descriptor: input.descriptor,
66
- executorToken: await mintWorkflowExecutorToken({
68
+ const [executorToken, runLedgerExecutorToken] = await Promise.all([
69
+ mintWorkflowExecutorToken({
67
70
  ...runtimeAuthorityMintInput(input.descriptor),
68
71
  runtimeOrigin: input.runtimeOrigin,
69
72
  }),
73
+ mintPlayRunAttemptRuntimeToken({
74
+ descriptor: input.descriptor,
75
+ capabilities: ['run.ledger.project'],
76
+ runtimeOrigin: input.runtimeOrigin,
77
+ runLedgerIngressPrefixOrigin: input.runLedgerIngressPrefixOrigin,
78
+ }),
79
+ ]);
80
+ return {
81
+ descriptor: input.descriptor,
82
+ executorToken,
83
+ runLedgerExecutorToken,
70
84
  };
71
85
  }
72
86
 
@@ -87,6 +101,7 @@ export async function mintPlayRunRuntimeAuthority(input: {
87
101
  /** Docflow rollout answer for the launching actor, resolved by the caller. */
88
102
  docflowEnabled?: boolean | null;
89
103
  runtimeOrigin?: string | null;
104
+ runLedgerIngressPrefixOrigin?: string | null;
90
105
  }): Promise<RuntimeAuthority> {
91
106
  const descriptor: RuntimeAuthorityDescriptor = {
92
107
  orgId: input.orgId,
@@ -110,6 +125,7 @@ export async function mintPlayRunRuntimeAuthority(input: {
110
125
  return await mintPlayRunRuntimeAuthorityDescriptor({
111
126
  descriptor,
112
127
  runtimeOrigin: input.runtimeOrigin,
128
+ runLedgerIngressPrefixOrigin: input.runLedgerIngressPrefixOrigin,
113
129
  });
114
130
  }
115
131
 
@@ -152,10 +168,12 @@ export async function mintPlayRunAttemptRuntimeToken(input: {
152
168
  terminalContract?: DirectCompletedTerminalContract | null;
153
169
  capabilities?: readonly RuntimeExecutionCapability[];
154
170
  runtimeOrigin?: string | null;
171
+ runLedgerIngressPrefixOrigin?: string | null;
155
172
  }): Promise<string> {
156
- return await mintWorkflowExecutorToken(
157
- runtimeAuthorityMintInput(input.descriptor, input),
158
- );
173
+ return await mintWorkflowExecutorToken({
174
+ ...runtimeAuthorityMintInput(input.descriptor, input),
175
+ runLedgerIngressPrefixOrigin: input.runLedgerIngressPrefixOrigin,
176
+ });
159
177
  }
160
178
 
161
179
  /**
@@ -4,6 +4,26 @@ import {
4
4
  } from '@deepline/deployed-contracts';
5
5
  import type { RuntimeExecutionCapability } from './execution-capabilities';
6
6
 
7
+ /** Gateway sheet admission operations retain distinct old/new semantics. */
8
+ export const RUNTIME_SHEET_ADMISSION_CAPABILITIES = {
9
+ runtime_sheet_start: 'sheet.write',
10
+ runtime_sheet_start_with_intent: 'sheet.write',
11
+ } as const satisfies Readonly<Record<string, RuntimeExecutionCapability>>;
12
+
13
+ export const RUNTIME_SHEET_ADMISSION_OPERATION_CONTRACT: DeployedOperationContract =
14
+ deployed.operation({
15
+ id: 'runtime-sheet-admission-actions',
16
+ actions: RUNTIME_SHEET_ADMISSION_CAPABILITIES,
17
+ olderReceiver: {
18
+ // A legacy start would mint newer intent after a wake or lost response.
19
+ // Refuse unsupported receivers before any row admission instead.
20
+ runtime_sheet_start_with_intent: {
21
+ kind: 'feature-unavailable',
22
+ code: 'RUNTIME_SHEET_WRITE_INTENT_UNAVAILABLE',
23
+ },
24
+ },
25
+ });
26
+
7
27
  /**
8
28
  * One declarative owner for the runtime action → authority relationship. The
9
29
  * route still owns authentication and execution; callers can add an action in
@@ -89,3 +109,39 @@ export function runtimeOperationCapability(
89
109
  ] ?? null
90
110
  );
91
111
  }
112
+
113
+ /**
114
+ * Projection credentials permit only keyed outbox deliveries, never progress
115
+ * producers. Each accepted action still validates its key, run scope and live
116
+ * lease in the receiver before writing. Ordinary executor authority keeps the
117
+ * established action mapping. This policy is shared by preflight and dispatch,
118
+ * including every action in a batch.
119
+ */
120
+ export function runtimeOperationCapabilityForRequest(
121
+ body: unknown,
122
+ capabilities: readonly string[] | null | undefined,
123
+ ): RuntimeExecutionCapability | null {
124
+ if (!body || typeof body !== 'object' || Array.isArray(body)) return null;
125
+ const request = body as Record<string, unknown>;
126
+ const action = request.action;
127
+ if (typeof action !== 'string') return null;
128
+ if (capabilities?.includes('run.ledger.project')) {
129
+ if (
130
+ capabilities.length !== 1 ||
131
+ ![
132
+ 'project_run_events',
133
+ 'project_run_created',
134
+ 'append_run_events',
135
+ 'start_run',
136
+ ].includes(action) ||
137
+ typeof request.idempotencyKey !== 'string' ||
138
+ !request.idempotencyKey.trim() ||
139
+ typeof request.deliveryLeaseOwner !== 'string' ||
140
+ !request.deliveryLeaseOwner.trim()
141
+ ) {
142
+ return null;
143
+ }
144
+ return 'run.ledger.project';
145
+ }
146
+ return runtimeOperationCapability(action);
147
+ }
@@ -1,5 +1,18 @@
1
1
  import { resolveMapRowOutcomeKey } from './map-row-outcome';
2
2
 
3
+ /** An older gateway cannot safely translate durable intent to legacy start. */
4
+ export class RuntimeSheetWriteIntentUnavailableError extends Error {
5
+ readonly code = 'RUNTIME_SHEET_WRITE_INTENT_UNAVAILABLE';
6
+
7
+ constructor(cause: Error) {
8
+ super(
9
+ 'Runtime Sheet write intent is unavailable on this gateway. Retry after the runtime rollout.',
10
+ { cause },
11
+ );
12
+ this.name = 'RuntimeSheetWriteIntentUnavailableError';
13
+ }
14
+ }
15
+
3
16
  export interface RuntimeSheetBlockedRowDetail {
4
17
  rowKey: string | null;
5
18
  attemptId: string | null;
@@ -86,3 +99,84 @@ export class RuntimeSheetRowsBlockedError extends Error {
86
99
  this.blockedRowDetails = blockedRowDetails.slice(0, 20);
87
100
  }
88
101
  }
102
+
103
+ /**
104
+ * Why a terminal row write was rejected as stale. Runtime Sheet rows are fenced
105
+ * by their schedule-time `_write_version` alone (the legacy attempt-lease
106
+ * predicates are stubbed to TRUE/FALSE in sheet-attempt-sql.ts), so a stale
107
+ * versioned write always means the row is owned by a different admission than
108
+ * the one the writer carries:
109
+ * - `newer_write_version`: a later admission (a new run, or a legacy caller
110
+ * that allocated again on resume) re-admitted the row after this writer
111
+ * admitted it. Stable-intent callers retain their version through wakes.
112
+ * - `older_write_version`: the row was admitted under an older version than
113
+ * the writer sent; the writer's version never admitted this row.
114
+ * - `already_terminal`: an unversioned writer hit an already-enriched row.
115
+ * Nothing is being overwritten, so this is the one benign reason.
116
+ * - `unreported`: the gateway returned stale keys without reasons (predates
117
+ * this field). Treated as superseded: every stale versioned write is.
118
+ */
119
+ export type RuntimeMapRowsStaleReason =
120
+ | 'newer_write_version'
121
+ | 'older_write_version'
122
+ | 'already_terminal'
123
+ | 'unreported';
124
+
125
+ export type RuntimeMapRowsStaleRow = {
126
+ key: string;
127
+ reason: RuntimeMapRowsStaleReason;
128
+ /** The admission version currently stamped on the sheet row. */
129
+ rowVersionStamp: number | null;
130
+ };
131
+
132
+ /**
133
+ * A terminal write batch was explicitly marked as an attempt-wide
134
+ * supersession. Retained for compatibility with older terminal-write handlers
135
+ * and the Context's explicit `supersededKeys` stop signal. The current
136
+ * runner-app writer reports ordinary stale latest-view rows without throwing
137
+ * this error.
138
+ */
139
+ export class RuntimeSheetAttemptSupersededError extends Error {
140
+ readonly tableNamespace: string;
141
+ readonly runId: string;
142
+ readonly writeVersion: number | null;
143
+ readonly submittedRows: number;
144
+ readonly supersededRows: RuntimeMapRowsStaleRow[];
145
+
146
+ constructor(input: {
147
+ tableNamespace: string;
148
+ runId: string;
149
+ writeVersionValue: number | null;
150
+ submittedRows: number;
151
+ supersededRows: RuntimeMapRowsStaleRow[];
152
+ }) {
153
+ const reasonCounts = new Map<RuntimeMapRowsStaleReason, number>();
154
+ for (const row of input.supersededRows) {
155
+ reasonCounts.set(row.reason, (reasonCounts.get(row.reason) ?? 0) + 1);
156
+ }
157
+ const reasons = [...reasonCounts.entries()]
158
+ .map(([reason, count]) => `${reason}=${count}`)
159
+ .join(', ');
160
+ const samples = input.supersededRows
161
+ .slice(0, 5)
162
+ .map(
163
+ (row) =>
164
+ `key=${row.key} row_write_version=${row.rowVersionStamp ?? 'unknown'}`,
165
+ )
166
+ .join('; ');
167
+ super(
168
+ `RUNTIME_SHEET_ATTEMPT_SUPERSEDED: Runtime Sheet table "${input.tableNamespace}" ` +
169
+ `rejected ${input.supersededRows.length} of ${input.submittedRows} terminal row write(s) ` +
170
+ `from run ${input.runId} at write version ${input.writeVersionValue ?? 'none'} ` +
171
+ `because the rows are owned by a different write version (${reasons || 'unreported'}). ` +
172
+ `This attempt has been superseded by a newer admission of these rows and must stop ` +
173
+ `executing: nothing it persists from here on can be accepted. Sample: ${samples}.`,
174
+ );
175
+ this.name = 'RuntimeSheetAttemptSupersededError';
176
+ this.tableNamespace = input.tableNamespace;
177
+ this.runId = input.runId;
178
+ this.writeVersion = input.writeVersionValue;
179
+ this.submittedRows = input.submittedRows;
180
+ this.supersededRows = input.supersededRows;
181
+ }
182
+ }
@@ -149,6 +149,8 @@ export type PlaySchedulerSubmitInput = RetainedPipelineCarrier & {
149
149
  */
150
150
  preloadedDbSessionUnwrapKey?: string | null;
151
151
  executorToken: string;
152
+ /** Optional run.progress-only authority minted at admission for ledger projection. */
153
+ runLedgerExecutorToken?: string | null;
152
154
  /** Immutable facts used by durable schedulers to mint a fresh leg token. */
153
155
  runtimeAuthority: RuntimeAuthorityDescriptor;
154
156
  /**
@@ -588,8 +588,11 @@ const absurdReadyPromises = new Map<string, Promise<void>>();
588
588
  /**
589
589
  * Verify, once per process (keyed by pool url + schema), the deployment-owned
590
590
  * Absurd schema contract and provision the shared queue with its policies.
591
- * Schema DDL belongs exclusively to the migration gate: a worker or Vercel
592
- * cold start may read this contract, but may never take the global bootstrap
591
+ * Worker startup owns hosted release queues; ordinary Vercel admission never
592
+ * calls this maintenance path. Local callers may prepare a queue lazily, and
593
+ * historic task recovery may prepare the run's original lane.
594
+ * Schema DDL belongs exclusively to the migration gate: startup or recovery
595
+ * may read this contract, but may never take the global bootstrap
593
596
  * lock. The memoized promise is shared; a failure evicts the cache so the next
594
597
  * caller retries loudly.
595
598
  */
@@ -9,10 +9,9 @@
9
9
  * modules.
10
10
  *
11
11
  * Lifecycle:
12
- * submit → ensure schemas + queues → insert launch row (postgres) → spawn an
13
- * absurd task (idempotencyKey=runId, orgKey=orgId) on `runs`.
14
- * Persist the absurd task id
15
- * on the run row so a later cancel can target it.
12
+ * submit → atomically insert launch row and spawn its absurd task on the
13
+ * release queue prepared by worker startup. Non-Vercel callers
14
+ * retain lazy queue setup for local app-before-worker startup.
16
15
  * observe/result → reuse the postgres LISTEN/NOTIFY run handle.
17
16
  * cancel → commit the Absurd stop and a durable cancellation request;
18
17
  * the worker deletes sandboxes before the final run write.
@@ -419,13 +418,21 @@ export function createAbsurdSchedulerBackend(
419
418
  queueDepth: permit.queueDepth,
420
419
  waitMs: permit.waitMs,
421
420
  });
422
- await ensureAbsurdRuntimeReady(
423
- poolOptions,
424
- normalizedSchedulerOptions,
425
- queueSuffix,
426
- releaseId,
427
- );
428
- recordAbsurdSubmitPhase(input, 'schema_ready', submitStartedAt);
421
+ // Vercel only admits work. The release worker prepares its Absurd
422
+ // queue before it reports ready; repeating schema checks, queue
423
+ // inventory, cutover cleanup, and queue-policy writes in each cold
424
+ // admission isolate adds database round trips to the user's launch
425
+ // path. If the worker has not prepared the queue, the atomic submit
426
+ // below fails loudly and a webhook receipt remains retryable.
427
+ if (!process.env.VERCEL?.trim()) {
428
+ await ensureAbsurdRuntimeReady(
429
+ poolOptions,
430
+ normalizedSchedulerOptions,
431
+ queueSuffix,
432
+ releaseId,
433
+ );
434
+ recordAbsurdSubmitPhase(input, 'schema_ready', submitStartedAt);
435
+ }
429
436
 
430
437
  // Loud, structured submit log: the #1 way an absurd run silently hangs
431
438
  // is an app→worker queue-name mismatch (the shared preview app
@@ -480,6 +487,8 @@ export function createAbsurdSchedulerBackend(
480
487
  spawn = await withRuntimeSchedulerSubmitAdmission(
481
488
  admissionParams,
482
489
  async () => {
490
+ // Historic launches may outlive a physically reclaimed queue.
491
+ // Recovery retains its original-lane preparation on every host.
483
492
  await ensureAbsurdRuntimeReady(
484
493
  poolOptions,
485
494
  normalizedSchedulerOptions,