deepline 0.3.316 → 0.3.318

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 (97) hide show
  1. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  2. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +64 -0
  3. package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +25 -18
  4. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +284 -26
  5. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-outbox-recovery.ts +123 -19
  6. package/dist/cli/{auth-JP7ZJ4OI.mjs → auth-S3C6DGZK.mjs} +4 -4
  7. package/dist/cli/auth-SPCCVKWR.js +31 -0
  8. package/dist/cli/{billing-KG6MC2BC.mjs → billing-2YFLKRPB.mjs} +4 -4
  9. package/dist/cli/{billing-WZGS32ME.js → billing-5RIRFKFK.js} +70 -70
  10. package/dist/cli/{chunk-46ZOD4PQ.mjs → chunk-43B4IQDT.mjs} +1 -1
  11. package/dist/cli/{chunk-SRUWVQ66.js → chunk-5KVYDOH3.js} +6 -6
  12. package/dist/cli/{chunk-K3BIRBT3.js → chunk-6BA2TLYP.js} +6 -6
  13. package/dist/cli/{chunk-VC25WFXV.mjs → chunk-7SMAPT4Q.mjs} +2 -2
  14. package/dist/cli/{chunk-GHLWDXUB.js → chunk-A4RINW7O.js} +6 -6
  15. package/dist/cli/{chunk-BOKHMPCZ.js → chunk-B3K7KANZ.js} +48 -48
  16. package/dist/cli/{chunk-ZNHGAWYI.js → chunk-GP5PLKPM.js} +2 -2
  17. package/dist/cli/{chunk-YNSAVFWL.mjs → chunk-GSGCLSB5.mjs} +5 -5
  18. package/dist/cli/{chunk-MCPHK7AF.js → chunk-H5JENUSW.js} +4 -4
  19. package/dist/cli/{chunk-J3ZPMADG.mjs → chunk-HDXBDRID.mjs} +1 -1
  20. package/dist/cli/{chunk-AXAPMVUC.mjs → chunk-HFYYLEXX.mjs} +4 -4
  21. package/dist/cli/{chunk-IDSDRGKF.mjs → chunk-HNGEUEUZ.mjs} +1 -1
  22. package/dist/cli/{chunk-D3NMIACS.mjs → chunk-N6SHI2NI.mjs} +1 -1
  23. package/dist/cli/{chunk-F2T5UENG.mjs → chunk-OQOCU7N2.mjs} +1 -1
  24. package/dist/cli/{chunk-OB3SYJGU.mjs → chunk-OUWH3UQI.mjs} +3 -3
  25. package/dist/cli/{chunk-TYSAKSX7.mjs → chunk-PBW4AMCS.mjs} +2 -2
  26. package/dist/cli/{chunk-C6QGM72M.js → chunk-QIDESZOK.js} +1 -1
  27. package/dist/cli/{chunk-PJERS5VW.js → chunk-SPPR7IUB.js} +6 -6
  28. package/dist/cli/{chunk-G2G67D3L.js → chunk-T4D5DSN2.js} +60 -60
  29. package/dist/cli/{chunk-35YXDTOB.js → chunk-TXWPV43B.js} +26 -26
  30. package/dist/cli/{chunk-6R5ACEWN.mjs → chunk-UIYTVYVJ.mjs} +6 -6
  31. package/dist/cli/{chunk-B6OOVO3A.js → chunk-UVEB46UN.js} +220 -220
  32. package/dist/cli/{chunk-YEMOOWZI.js → chunk-VQFYTD3E.js} +50 -50
  33. package/dist/cli/{chunk-RBBSRB56.js → chunk-WCR65D2N.js} +15 -15
  34. package/dist/cli/{chunk-VDPBQCRQ.mjs → chunk-XXNE65K5.mjs} +2 -2
  35. package/dist/cli/{chunk-DAFGPNVW.mjs → chunk-YNIUFZ5B.mjs} +1 -1
  36. package/dist/cli/{client-MNPM4ME3.mjs → client-BMLSQMUI.mjs} +3 -3
  37. package/dist/cli/client-LSNRA76T.js +20 -0
  38. package/dist/cli/{csv-ZME7HAPR.mjs → csv-RNUTR7LO.mjs} +3 -3
  39. package/dist/cli/{csv-G72FIQWI.js → csv-YQXSHIVH.js} +12 -12
  40. package/dist/cli/{db-KRBWHSMA.js → db-ABWJP4XY.js} +20 -20
  41. package/dist/cli/{db-K2DS4PEY.mjs → db-DOZJ35SZ.mjs} +4 -4
  42. package/dist/cli/{describe-LXBJP6OP.mjs → describe-JMUJC7S6.mjs} +8 -8
  43. package/dist/cli/{describe-UKFV376D.js → describe-JRWDWFIN.js} +15 -15
  44. package/dist/cli/{executions-2V3AROY6.mjs → executions-KF7WZKF4.mjs} +4 -4
  45. package/dist/cli/{executions-E66AM4JU.js → executions-WOQ3HYRQ.js} +6 -6
  46. package/dist/cli/{feedback-7C2N7M37.js → feedback-6ZPHQNTY.js} +6 -6
  47. package/dist/cli/{feedback-IEPZ2XKZ.mjs → feedback-KLO5S6CV.mjs} +3 -3
  48. package/dist/cli/git-2VCXV5SK.js +23 -0
  49. package/dist/cli/{git-AR5KGN4O.mjs → git-4AQH6JOC.mjs} +4 -4
  50. package/dist/cli/index.js +75 -75
  51. package/dist/cli/index.mjs +31 -31
  52. package/dist/cli/{legacy-noops-A2SH45P4.js → legacy-noops-PFCAMJ5O.js} +7 -7
  53. package/dist/cli/{legacy-noops-LC2EGAZU.mjs → legacy-noops-WJL3CCKD.mjs} +4 -4
  54. package/dist/cli/{monitors-5YPW3IZQ.mjs → monitors-RYTEFDAX.mjs} +4 -4
  55. package/dist/cli/{monitors-IZBUPKPW.js → monitors-RYZ6RQWJ.js} +85 -85
  56. package/dist/cli/{org-L42SQ65U.js → org-PZNEI4Z2.js} +60 -60
  57. package/dist/cli/{org-2OMYI5KJ.mjs → org-TUITFKO6.mjs} +4 -4
  58. package/dist/cli/play-PQ2PS5WY.js +152 -0
  59. package/dist/cli/{play-UPCBLAOH.mjs → play-STV34EKC.mjs} +7 -7
  60. package/dist/cli/{providers-VE2RM56M.mjs → providers-G374UPE3.mjs} +4 -4
  61. package/dist/cli/{providers-GGNDWUKB.js → providers-K2TDVWWY.js} +7 -7
  62. package/dist/cli/{quickstart-4CZHURUX.js → quickstart-QI6Z5VU2.js} +5 -5
  63. package/dist/cli/{quickstart-HSJ7FU7Z.mjs → quickstart-RBKEB32U.mjs} +3 -3
  64. package/dist/cli/search-3FQ6SCDN.js +26 -0
  65. package/dist/cli/{search-MWBM3I2L.mjs → search-VIVNNMFH.mjs} +5 -5
  66. package/dist/cli/{secrets-W5DQYKGU.mjs → secrets-FPD6A32B.mjs} +4 -4
  67. package/dist/cli/{secrets-CWBPGDZV.js → secrets-GXFMHRUN.js} +13 -13
  68. package/dist/cli/{sessions-Q42GUYTF.mjs → sessions-7XXZRPIR.mjs} +4 -4
  69. package/dist/cli/{sessions-EDCFU6P2.js → sessions-HQLIG25E.js} +5 -5
  70. package/dist/cli/{settings-SO56AJPQ.mjs → settings-C24HFGVP.mjs} +7 -7
  71. package/dist/cli/{settings-OKRENZGX.js → settings-J72DQVQO.js} +74 -74
  72. package/dist/cli/{setup-7PLHLNLS.js → setup-AM4MIXQJ.js} +41 -41
  73. package/dist/cli/{setup-OTYMF5CZ.mjs → setup-Z76VRJ3C.mjs} +6 -6
  74. package/dist/cli/{skills-4UFS4FXP.mjs → skills-2MNX5O4X.mjs} +4 -4
  75. package/dist/cli/skills-6Z2V3HBJ.js +28 -0
  76. package/dist/cli/{tools-6FV543YV.mjs → tools-GZIJWL36.mjs} +6 -6
  77. package/dist/cli/tools-XC2O6EHT.js +38 -0
  78. package/dist/cli/update-D4NV3VSL.js +28 -0
  79. package/dist/cli/{update-6POGDXYW.mjs → update-DDJS3QNN.mjs} +6 -6
  80. package/dist/cli/{workflow-RB4POZP5.js → workflow-2WDLLVYG.js} +15 -15
  81. package/dist/cli/{workflow-HVZSFWYR.mjs → workflow-DYC6Q4BG.mjs} +5 -5
  82. package/dist/index.js +6 -6
  83. package/dist/index.mjs +3 -3
  84. package/dist/install-integrity.json +74 -74
  85. package/dist/release.d.mts +1 -1
  86. package/dist/release.d.ts +1 -1
  87. package/dist/release.js +2 -2
  88. package/dist/release.mjs +1 -1
  89. package/package.json +1 -1
  90. package/dist/cli/auth-SPUJ4EXC.js +0 -31
  91. package/dist/cli/client-GMMPQT7B.js +0 -20
  92. package/dist/cli/git-EXYB66IH.js +0 -23
  93. package/dist/cli/play-CQI3IDDN.js +0 -152
  94. package/dist/cli/search-PD5FBCUN.js +0 -26
  95. package/dist/cli/skills-IP7IW7EQ.js +0 -28
  96. package/dist/cli/tools-A2YNR6PI.js +0 -38
  97. package/dist/cli/update-QXSGKLJG.js +0 -28
@@ -200,7 +200,7 @@ export const SDK_RELEASE = {
200
200
  // getters keep their established compatibility behavior.
201
201
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
202
202
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
203
- version: '0.3.316',
203
+ version: '0.3.318',
204
204
  updateSummary:
205
205
  'Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.',
206
206
  packageCapabilities: {
@@ -385,9 +385,24 @@ export type WorkerRuntimeApiContext = {
385
385
  * gateway record that produced it.
386
386
  */
387
387
  onResponseMeta?: (meta: RuntimeApiResponseMeta) => void;
388
+ /**
389
+ * Observe each request attempt as it is sent. `onResponseMeta` only fires
390
+ * for a successful response, so an attempt that is aborted or times out
391
+ * names nothing there; this carries the per-attempt id that the request
392
+ * already sends in its transport-attempt header, which a receiver can log.
393
+ * Diagnostic only: log it, never persist it on a run, status, or receipt
394
+ * document.
395
+ */
396
+ onRequestAttempt?: (attempt: RuntimeApiRequestAttempt) => void;
388
397
  signal?: AbortSignal;
389
398
  };
390
399
 
400
+ export type RuntimeApiRequestAttempt = {
401
+ action: RuntimeApiRequest['action'];
402
+ /** The value of this attempt's transport-attempt request header. */
403
+ transportAttemptId: string;
404
+ };
405
+
391
406
  /**
392
407
  * The receipt gateway's own account of a request, from its `Server-Timing`
393
408
  * response header. Its `runtime.gateway.action.finished` durationMs starts
@@ -423,6 +438,19 @@ export type RuntimeApiResponseMeta = {
423
438
  roundTripMs?: number | null;
424
439
  /** Absent when the gateway sent no `Server-Timing` header. */
425
440
  serverTiming?: RuntimeGatewayServerTiming | null;
441
+ /**
442
+ * The hosting platform's id for the responding request (`x-vercel-id`), so a
443
+ * slow app-runtime hop can be matched to its platform request log. Null when
444
+ * the receiver is not fronted by one. Diagnostic only: log it, never persist
445
+ * it on a run, status, or receipt document.
446
+ */
447
+ platformRequestId?: string | null;
448
+ /**
449
+ * The raw `Server-Timing` header, truncated. App routes name their own
450
+ * entries, which `serverTiming` (the gateway's schema) does not parse.
451
+ * Diagnostic only, under the same rule as `platformRequestId`.
452
+ */
453
+ serverTimingHeader?: string | null;
426
454
  /**
427
455
  * Serialized JSON bytes of the request body, before compression. Set on
428
456
  * every request, so `wire / raw` across a run is the compression ratio the
@@ -447,6 +475,27 @@ export type RuntimeApiResponseMeta = {
447
475
  requestBodyPackMs?: number | null;
448
476
  };
449
477
 
478
+ const RUNTIME_API_DIAGNOSTIC_HEADER_MAX_CHARS = 256;
479
+
480
+ /**
481
+ * Read one response header for a log line: trimmed, bounded, and total. A
482
+ * receiver controls this value, so it is capped before it reaches a record.
483
+ */
484
+ export function readRuntimeApiDiagnosticHeader(
485
+ headers: Pick<Headers, 'get'> | null | undefined,
486
+ name: string,
487
+ ): string | null {
488
+ try {
489
+ const value = headers?.get(name)?.trim();
490
+ return value
491
+ ? value.slice(0, RUNTIME_API_DIAGNOSTIC_HEADER_MAX_CHARS)
492
+ : null;
493
+ } catch {
494
+ // Observation must never affect durable delivery.
495
+ return null;
496
+ }
497
+ }
498
+
450
499
  const RUNTIME_GATEWAY_AUTH_SESSION_VALUES = new Set([
451
500
  'hit',
452
501
  'miss',
@@ -1519,6 +1568,13 @@ async function postAppRuntimeApi<TResponse>(
1519
1568
  // would show up as network cost that no round trip explains.
1520
1569
  const attemptStartedAt = Date.now();
1521
1570
  const transportAttemptId = randomUUID();
1571
+ if (context.onRequestAttempt) {
1572
+ try {
1573
+ context.onRequestAttempt({ action: body.action, transportAttemptId });
1574
+ } catch {
1575
+ // Observation must never affect durable delivery.
1576
+ }
1577
+ }
1522
1578
  const requestSignal = context.signal
1523
1579
  ? AbortSignal.any([context.signal, AbortSignal.timeout(requestTimeoutMs)])
1524
1580
  : AbortSignal.timeout(requestTimeoutMs);
@@ -1680,6 +1736,14 @@ async function postAppRuntimeApi<TResponse>(
1680
1736
  serverTiming: parseRuntimeGatewayServerTiming(
1681
1737
  response.headers.get('server-timing'),
1682
1738
  ),
1739
+ platformRequestId: readRuntimeApiDiagnosticHeader(
1740
+ response.headers,
1741
+ 'x-vercel-id',
1742
+ ),
1743
+ serverTimingHeader: readRuntimeApiDiagnosticHeader(
1744
+ response.headers,
1745
+ 'server-timing',
1746
+ ),
1683
1747
  requestBodyRawBytes: wireBody.rawBytes,
1684
1748
  requestBodyWireBytes: wireBody.wireBytes,
1685
1749
  requestBodySerializeMs,
@@ -1302,36 +1302,43 @@ function terminalFailureSummary(
1302
1302
  export function ledgerTerminalResultRefForValue(
1303
1303
  value: unknown,
1304
1304
  reason: LedgerTerminalResultRefReason,
1305
- options: { content?: 'full' } = {},
1305
+ options: { content?: 'full'; deriveMetadata?: boolean } = {},
1306
1306
  ): LedgerTerminalResultRef {
1307
+ // Fallbacks after a rejected projection must not serialize the same payload
1308
+ // again just to derive optional metadata.
1309
+ const { content, deriveMetadata = true } = options;
1307
1310
  let bytes: number | undefined;
1308
- try {
1309
- bytes = jsonByteLengthUpTo(value, LEDGER_TERMINAL_RESULT_MAX_BYTES).bytes;
1310
- } catch {
1311
- // The bounded reason is the useful diagnostic. Never serialize the
1312
- // customer payload again merely to populate reference metadata.
1313
- }
1314
1311
  let preview: BoundedRunListOutputPreview | undefined;
1315
1312
  let responsePreview: LedgerStoredRunOutputPreview | undefined;
1316
- if (options.content && isPlainObject(value)) {
1313
+ let failure: LedgerTerminalFailureSummary | undefined;
1314
+ if (deriveMetadata) {
1317
1315
  try {
1318
- preview = buildBoundedRunListOutputPreview(value);
1319
- responsePreview = reuseRunListValuesInOutputPreview(
1320
- buildBoundedRunOutputPreview(value),
1321
- preview,
1322
- );
1316
+ bytes = jsonByteLengthUpTo(value, LEDGER_TERMINAL_RESULT_MAX_BYTES).bytes;
1323
1317
  } catch {
1324
- // The terminal reference is the durable fallback. A hostile/non-JSON
1325
- // value must not turn optional list-preview derivation into a terminal
1326
- // persistence failure.
1318
+ // The bounded reason is the useful diagnostic. Never serialize the
1319
+ // customer payload again merely to populate reference metadata.
1320
+ }
1321
+ if (content && isPlainObject(value)) {
1322
+ try {
1323
+ preview = buildBoundedRunListOutputPreview(value);
1324
+ responsePreview = reuseRunListValuesInOutputPreview(
1325
+ buildBoundedRunOutputPreview(value),
1326
+ preview,
1327
+ );
1328
+ } catch {
1329
+ // The terminal reference is the durable fallback. A hostile/non-JSON
1330
+ // value must not turn optional list-preview derivation into a terminal
1331
+ // persistence failure.
1332
+ }
1327
1333
  }
1334
+ failure = terminalFailureSummary(value);
1328
1335
  }
1329
1336
  return ledgerTerminalResultRef(reason, {
1330
- ...options,
1337
+ ...(content ? { content } : {}),
1331
1338
  bytes,
1332
1339
  preview,
1333
1340
  responsePreview,
1334
- failure: terminalFailureSummary(value),
1341
+ failure,
1335
1342
  });
1336
1343
  }
1337
1344
 
@@ -161,7 +161,10 @@ import {
161
161
  loadArtifactFromAppRuntime,
162
162
  loadStagedFileFromAppRuntime,
163
163
  projectRunCreatedViaAppRuntime,
164
+ readRuntimeApiDiagnosticHeader,
164
165
  startRunViaAppRuntime,
166
+ type RuntimeApiRequestAttempt,
167
+ type RuntimeApiResponseMeta,
165
168
  type StoredPlayArtifactPayload,
166
169
  type WorkerRuntimeApiContext,
167
170
  } from '../app-runtime-api';
@@ -19723,6 +19726,14 @@ export type RunLedgerOutboxDispatchInput = {
19723
19726
  * can take the same row immediately under the same idempotency key.
19724
19727
  */
19725
19728
  signal?: AbortSignal;
19729
+ /**
19730
+ * Told once when an attempt abandoned by `signal` has handed back the lease
19731
+ * it took: `true` when the owner-fenced release statement completed (a
19732
+ * release that matched no row counts, since nothing is then held), `false`
19733
+ * when it could not run and the lease is left to expire. Not called when
19734
+ * the attempt never took a lease. Never affects delivery.
19735
+ */
19736
+ onAbortedLeaseRelease?: (released: boolean) => void;
19726
19737
  /**
19727
19738
  * Observation hook for acknowledged rows (event type and commit-to-ack lag
19728
19739
  * measured on the database clock). Never affects delivery.
@@ -20079,7 +20090,45 @@ async function dispatchRunLedgerOutboxBatchWithScope(
20079
20090
  });
20080
20091
  }
20081
20092
  };
20093
+ // The claim can be invoked more than once for one dispatch: the pool
20094
+ // re-runs a checkout's operation after a connection failure, and the claim
20095
+ // itself is retried once on the missing-marker compatibility path.
20096
+ let claimInvocations = 0;
20097
+ // An abandoned attempt that already handed its lease back on a checkout it
20098
+ // held does not spend another checkout on the same release.
20099
+ const abandonedLease = { released: false };
20082
20100
  const claimEvents = async (client: PostgresSchedulerQueryClient) => {
20101
+ claimInvocations += 1;
20102
+ const abandonedHeadEventId = input.headEventId?.trim();
20103
+ if (
20104
+ input.signal?.aborted &&
20105
+ (claimInvocations === 1 || abandonedHeadEventId)
20106
+ ) {
20107
+ // The caller's deadline elapsed while this checkout was queued. Its
20108
+ // attempt is already abandoned, so taking a lease now could only keep
20109
+ // the durable projector off the row until that lease expires. Claim
20110
+ // nothing: the row stays pending and unleased for its next owner.
20111
+ if (claimInvocations > 1 && abandonedHeadEventId) {
20112
+ // An earlier invocation's COMMIT may have reached the server before
20113
+ // its connection failed, so this owner can already hold the named
20114
+ // head. Hand it back here, fenced to this owner; returning empty
20115
+ // would leave that lease with nobody to release it. After a rolled
20116
+ // back invocation it matches no row. A failure propagates, so the
20117
+ // attempt is never reported as settled.
20118
+ await releasePostgresSchedulerOutboxLease(
20119
+ client,
20120
+ [abandonedHeadEventId],
20121
+ { ...options, leaseOwner },
20122
+ );
20123
+ }
20124
+ const unclaimed: {
20125
+ events: PostgresSchedulerOutboxEvent[];
20126
+ launchJson: unknown;
20127
+ } = { events: [], launchJson: undefined };
20128
+ return unclaimed;
20129
+ }
20130
+ // A re-invocation with no named head claims again under the same owner,
20131
+ // as it always has; the abort check after the claim releases by id.
20083
20132
  // The checkout is exclusive. Hold the existing scheduler run's row lock
20084
20133
  // only while choosing/claiming its outbox prefix, never over HTTP. A
20085
20134
  // second statement takes a fresh READ COMMITTED snapshot after the lock:
@@ -20274,6 +20323,26 @@ async function dispatchRunLedgerOutboxBatchWithScope(
20274
20323
  let authorityReadyAtMs: number | null = null;
20275
20324
  let appendFinishedAtMs: number | null = null;
20276
20325
  let acknowledgedAtMs: number | null = null;
20326
+ // How this delivery obtained its app authority, for the slow-delivery
20327
+ // record only. `token` is set only when the dispatch-token endpoint was
20328
+ // actually consulted; a token pre-minted at admission and an authority
20329
+ // reused within the drain make no such request.
20330
+ const authorityObserved: {
20331
+ token: RunLedgerDispatchTokenObservation | null;
20332
+ reusedWithinDrain: boolean;
20333
+ } = { token: null, reusedWithinDrain: false };
20334
+ // Platform identity of the slowest append response, for the same record.
20335
+ // Null when no append was answered or its receiver sent no such header.
20336
+ let appendResponse:
20337
+ | (RunLedgerDispatchResponseTrace & { roundTripMs: number | null })
20338
+ | null = null;
20339
+ const callerOnResponseMeta = input.runtimeApi?.onResponseMeta;
20340
+ // The last append attempt sent, named even when it never gets a response
20341
+ // (an append aborted at the caller's deadline has no response to read).
20342
+ const appendAttempt: { transportAttemptId: string | null } = {
20343
+ transportAttemptId: null,
20344
+ };
20345
+ const callerOnRequestAttempt = input.runtimeApi?.onRequestAttempt;
20277
20346
  const materializeDeferredObservability = async () => {
20278
20347
  if (
20279
20348
  events.some(
@@ -20401,6 +20470,10 @@ async function dispatchRunLedgerOutboxBatchWithScope(
20401
20470
  return null;
20402
20471
  };
20403
20472
  try {
20473
+ // A deadline that elapsed during the claim abandons the attempt before
20474
+ // any authority or renewal work. The abort branch below hands the lease
20475
+ // straight back without charging a projection attempt.
20476
+ input.signal?.throwIfAborted();
20404
20477
  // The ledger converter rejects raw deferred facts. Inline callers hand
20405
20478
  // them off; the background owner projects them before inspecting the
20406
20479
  // compact lifecycle payload or deciding that it needs no HTTP append.
@@ -20472,6 +20545,11 @@ async function dispatchRunLedgerOutboxBatchWithScope(
20472
20545
  ),
20473
20546
  ) + RUNTIME_RELIABILITY_POLICY.schedulerDatabase.queryTimeoutMs;
20474
20547
  const cachedAuthority = authorityScope.authority;
20548
+ const observeDispatchTokenResponse = (
20549
+ observation: RunLedgerDispatchTokenObservation,
20550
+ ) => {
20551
+ authorityObserved.token = observation;
20552
+ };
20475
20553
  const resolveRunRuntimeApi = () =>
20476
20554
  launchJson !== null
20477
20555
  ? resolvePostgresSchedulerRuntimeApiForRun(
@@ -20484,6 +20562,7 @@ async function dispatchRunLedgerOutboxBatchWithScope(
20484
20562
  options,
20485
20563
  input.runtimeApi?.signal,
20486
20564
  reuseMarginMs,
20565
+ observeDispatchTokenResponse,
20487
20566
  )
20488
20567
  : loadPostgresSchedulerRuntimeApiForRun(
20489
20568
  withClient,
@@ -20495,6 +20574,7 @@ async function dispatchRunLedgerOutboxBatchWithScope(
20495
20574
  options,
20496
20575
  input.runtimeApi?.signal,
20497
20576
  reuseMarginMs,
20577
+ observeDispatchTokenResponse,
20498
20578
  );
20499
20579
  const gatewayRuntimeApi =
20500
20580
  needsRuntimeApi && tokenAuthority === 'gateway'
@@ -20505,6 +20585,11 @@ async function dispatchRunLedgerOutboxBatchWithScope(
20505
20585
  ? cachedAuthority.runtimeApi
20506
20586
  : await resolveRunRuntimeApi()
20507
20587
  : null;
20588
+ // Read-only: an authority carried over from an earlier prefix of this
20589
+ // drain made no request for this delivery.
20590
+ authorityObserved.reusedWithinDrain =
20591
+ gatewayRuntimeApi !== null &&
20592
+ gatewayRuntimeApi === cachedAuthority?.runtimeApi;
20508
20593
  if (
20509
20594
  gatewayRuntimeApi &&
20510
20595
  cachedAuthority?.runId === first.runId &&
@@ -20542,6 +20627,27 @@ async function dispatchRunLedgerOutboxBatchWithScope(
20542
20627
  : {}),
20543
20628
  }
20544
20629
  : {}),
20630
+ // Keep the slowest append response's platform identity for the
20631
+ // slow-delivery record, then hand the caller's own observer the same
20632
+ // meta it always received. Observation never affects delivery.
20633
+ onResponseMeta: (meta: RuntimeApiResponseMeta) => {
20634
+ const roundTripMs = meta.roundTripMs ?? null;
20635
+ if (
20636
+ appendResponse === null ||
20637
+ (roundTripMs ?? 0) >= (appendResponse.roundTripMs ?? 0)
20638
+ ) {
20639
+ appendResponse = {
20640
+ platformRequestId: meta.platformRequestId ?? null,
20641
+ serverTimingHeader: meta.serverTimingHeader ?? null,
20642
+ roundTripMs,
20643
+ };
20644
+ }
20645
+ callerOnResponseMeta?.(meta);
20646
+ },
20647
+ onRequestAttempt: (attempt: RuntimeApiRequestAttempt) => {
20648
+ appendAttempt.transportAttemptId = attempt.transportAttemptId;
20649
+ callerOnRequestAttempt?.(attempt);
20650
+ },
20545
20651
  retryPolicy: 'none' as const,
20546
20652
  // The caller-owned admission deadline (see `signal` above) wins.
20547
20653
  ...(input.signal ? { signal: input.signal } : {}),
@@ -20669,11 +20775,22 @@ async function dispatchRunLedgerOutboxBatchWithScope(
20669
20775
  expiresAtMs: runtimeApiTokenExpiresAtMs(runtimeApi.executorToken),
20670
20776
  };
20671
20777
  }
20672
- await withClient((client) =>
20673
- renewPostgresRunLedgerDelivery(
20778
+ const renewed = await withClient(async (client) => {
20779
+ const eventIds = events.map((event) => event.eventId);
20780
+ if (input.signal?.aborted) {
20781
+ // The caller's deadline elapsed while this checkout was queued.
20782
+ // Renewing now would extend an abandoned attempt's lease by a full
20783
+ // term. Hand it back on this same checkout instead.
20784
+ await releasePostgresSchedulerOutboxLease(client, eventIds, {
20785
+ ...options,
20786
+ leaseOwner,
20787
+ });
20788
+ return false;
20789
+ }
20790
+ await renewPostgresRunLedgerDelivery(
20674
20791
  client,
20675
20792
  {
20676
- eventIds: events.map((event) => event.eventId),
20793
+ eventIds,
20677
20794
  leaseOwner,
20678
20795
  leaseSeconds: input.leaseSeconds ?? 120,
20679
20796
  freezeReceipt:
@@ -20684,8 +20801,14 @@ async function dispatchRunLedgerOutboxBatchWithScope(
20684
20801
  ),
20685
20802
  },
20686
20803
  options,
20687
- ),
20688
- );
20804
+ );
20805
+ return true;
20806
+ });
20807
+ if (!renewed) {
20808
+ abandonedLease.released = true;
20809
+ // Stop before the append; the abort branch below reports the outcome.
20810
+ input.signal?.throwIfAborted();
20811
+ }
20689
20812
  };
20690
20813
  if (needsRuntimeApi && runtimeApi) {
20691
20814
  const append = async (runtimeApi: WorkerRuntimeApiContext) => {
@@ -20832,28 +20955,41 @@ async function dispatchRunLedgerOutboxBatchWithScope(
20832
20955
  // replay carries the same idempotency key and is a no-op there.
20833
20956
  const eventIds = events.map((event) => event.eventId);
20834
20957
  let released: string[];
20835
- try {
20836
- released = await withClient(
20837
- (client) =>
20838
- releasePostgresSchedulerOutboxLease(client, eventIds, {
20839
- ...options,
20840
- leaseOwner,
20841
- }),
20842
- {
20843
- runId: events[0]!.runId,
20844
- phase: 'run_ledger_outbox_lease_release',
20845
- priority: 'critical',
20846
- },
20847
- );
20848
- } catch (settlementError) {
20849
- logRunLedgerOutboxSettlementFailure({
20850
- runId: events[0]!.runId,
20851
- eventIds,
20852
- stage: 'aborted_release',
20853
- settlementError,
20854
- deliveryError: error,
20855
- });
20958
+ let releaseLanded = abandonedLease.released;
20959
+ if (releaseLanded) {
20960
+ // The renewal checkout already handed the lease back.
20856
20961
  released = eventIds;
20962
+ } else {
20963
+ try {
20964
+ released = await withClient(
20965
+ (client) =>
20966
+ releasePostgresSchedulerOutboxLease(client, eventIds, {
20967
+ ...options,
20968
+ leaseOwner,
20969
+ }),
20970
+ {
20971
+ runId: events[0]!.runId,
20972
+ phase: 'run_ledger_outbox_lease_release',
20973
+ priority: 'critical',
20974
+ },
20975
+ );
20976
+ releaseLanded = true;
20977
+ } catch (settlementError) {
20978
+ logRunLedgerOutboxSettlementFailure({
20979
+ runId: events[0]!.runId,
20980
+ eventIds,
20981
+ stage: 'aborted_release',
20982
+ settlementError,
20983
+ deliveryError: error,
20984
+ });
20985
+ released = eventIds;
20986
+ }
20987
+ }
20988
+ try {
20989
+ // The caller must not read a failed release as a settled lease.
20990
+ input.onAbortedLeaseRelease?.(releaseLanded);
20991
+ } catch {
20992
+ // Observation must never affect durable delivery.
20857
20993
  }
20858
20994
  return {
20859
20995
  attempted: events.length,
@@ -21036,6 +21172,19 @@ async function dispatchRunLedgerOutboxBatchWithScope(
21036
21172
  continuationMs:
21037
21173
  acknowledgedAtMs === null ? null : settledAtMs - acknowledgedAtMs,
21038
21174
  durationMs: settledAtMs - dispatchStartedAtMs,
21175
+ // Which platform requests served the two app hops, so a slow
21176
+ // authority or append stage can be found in the app's request log.
21177
+ ...runLedgerSlowDeliveryResponseFields(
21178
+ runLedgerDeliveryAuthoritySource({
21179
+ authorityReady: authorityReadyAtMs !== null,
21180
+ tokenAuthority,
21181
+ reusedWithinDrain: authorityObserved.reusedWithinDrain,
21182
+ token: authorityObserved.token,
21183
+ }),
21184
+ authorityObserved.token?.trace ?? null,
21185
+ appendResponse,
21186
+ appendAttempt.transportAttemptId,
21187
+ ),
21039
21188
  });
21040
21189
  }
21041
21190
  }
@@ -21380,6 +21529,9 @@ async function resolvePostgresSchedulerRuntimeApiForRun(
21380
21529
  options?: Pick<PostgresSchedulerOptions, 'schema'>,
21381
21530
  signal?: AbortSignal,
21382
21531
  tokenReuseMarginMs = 0,
21532
+ onDispatchTokenResponse?: (
21533
+ observation: RunLedgerDispatchTokenObservation,
21534
+ ) => void,
21383
21535
  ): Promise<
21384
21536
  WorkerRuntimeApiContext & {
21385
21537
  refreshExecutorToken?: () => Promise<string>;
@@ -21441,6 +21593,14 @@ async function resolvePostgresSchedulerRuntimeApiForRun(
21441
21593
  } else {
21442
21594
  const dispatchAuthority =
21443
21595
  await requestRunLedgerDispatchToken(dispatchRequest);
21596
+ try {
21597
+ onDispatchTokenResponse?.({
21598
+ reused: dispatchAuthority.reused,
21599
+ trace: dispatchAuthority.responseTrace ?? null,
21600
+ });
21601
+ } catch {
21602
+ // Observation must never affect durable delivery.
21603
+ }
21444
21604
  invalidateExecutorToken = () =>
21445
21605
  runLedgerDispatchTokens.delete(dispatchAuthority.cacheKey);
21446
21606
  if (dispatchAuthority.reused) {
@@ -21475,6 +21635,9 @@ async function loadPostgresSchedulerRuntimeApiForRun(
21475
21635
  options?: Pick<PostgresSchedulerOptions, 'schema'>,
21476
21636
  signal?: AbortSignal,
21477
21637
  tokenReuseMarginMs = 0,
21638
+ onDispatchTokenResponse?: (
21639
+ observation: RunLedgerDispatchTokenObservation,
21640
+ ) => void,
21478
21641
  ): ReturnType<typeof resolvePostgresSchedulerRuntimeApiForRun> {
21479
21642
  // A continuation already owns its next event lease, so its launch context
21480
21643
  // is not part of the preclaim result. Load only the authority fields here.
@@ -21495,9 +21658,92 @@ async function loadPostgresSchedulerRuntimeApiForRun(
21495
21658
  options,
21496
21659
  signal,
21497
21660
  tokenReuseMarginMs,
21661
+ onDispatchTokenResponse,
21498
21662
  );
21499
21663
  }
21500
21664
 
21665
+ /**
21666
+ * Platform identity of one app response on the Run Ledger delivery path
21667
+ * (`x-vercel-id` and the raw `Server-Timing` header, both bounded). It exists
21668
+ * only to label the `[run-ledger-outbox.slow_delivery]` log record. It carries
21669
+ * no credential and no run, org, or customer identifier, and it must never be
21670
+ * written to a run, status, or receipt document.
21671
+ */
21672
+ type RunLedgerDispatchResponseTrace = {
21673
+ platformRequestId: string | null;
21674
+ serverTimingHeader: string | null;
21675
+ };
21676
+
21677
+ /**
21678
+ * What one consultation of the dispatch-token endpoint returned: a token
21679
+ * reused from this process's cache (`reused`, no request made, so no trace)
21680
+ * or a fresh response. Reported only where that endpoint is consulted, never
21681
+ * for a token pre-minted at admission.
21682
+ */
21683
+ type RunLedgerDispatchTokenObservation = {
21684
+ reused: boolean;
21685
+ trace: RunLedgerDispatchResponseTrace | null;
21686
+ };
21687
+
21688
+ /**
21689
+ * Where a delivery's app authority came from, for the slow-delivery record:
21690
+ * - `requested`: a dispatch-token request was made for this delivery, so
21691
+ * `authorityRequestId` names it when the receiver sent a platform id.
21692
+ * - `cached`: a dispatch token reused from this process or this drain.
21693
+ * - `pre_minted`: the run's admission-minted projection token.
21694
+ * - `local`: signed in-process or supplied by the caller.
21695
+ * Only `requested` makes an authority request; for every other source a null
21696
+ * `authorityRequestId` means no request happened, not a missing header.
21697
+ * `null` means the delivery ended before it had an authority.
21698
+ */
21699
+ type RunLedgerDeliveryAuthoritySource =
21700
+ | 'requested'
21701
+ | 'cached'
21702
+ | 'pre_minted'
21703
+ | 'local';
21704
+
21705
+ function runLedgerDeliveryAuthoritySource(input: {
21706
+ authorityReady: boolean;
21707
+ tokenAuthority: RunLedgerOutboxTokenAuthority;
21708
+ reusedWithinDrain: boolean;
21709
+ token: RunLedgerDispatchTokenObservation | null;
21710
+ }): RunLedgerDeliveryAuthoritySource | null {
21711
+ if (!input.authorityReady) return null;
21712
+ if (input.tokenAuthority !== 'gateway') return 'local';
21713
+ if (input.token) return input.token.reused ? 'cached' : 'requested';
21714
+ return input.reusedWithinDrain ? 'cached' : 'pre_minted';
21715
+ }
21716
+
21717
+ function runLedgerSlowDeliveryResponseFields(
21718
+ authoritySource: RunLedgerDeliveryAuthoritySource | null,
21719
+ authority: RunLedgerDispatchResponseTrace | null,
21720
+ append:
21721
+ | (RunLedgerDispatchResponseTrace & { roundTripMs: number | null })
21722
+ | null,
21723
+ appendTransportAttemptId: string | null,
21724
+ ): {
21725
+ authoritySource: RunLedgerDeliveryAuthoritySource | null;
21726
+ authorityRequestId: string | null;
21727
+ authorityServerTiming: string | null;
21728
+ appendRequestId: string | null;
21729
+ appendServerTiming: string | null;
21730
+ appendRoundTripMs: number | null;
21731
+ appendTransportAttemptId: string | null;
21732
+ } {
21733
+ return {
21734
+ authoritySource,
21735
+ authorityRequestId: authority?.platformRequestId ?? null,
21736
+ authorityServerTiming: authority?.serverTimingHeader ?? null,
21737
+ appendRequestId: append?.platformRequestId ?? null,
21738
+ appendServerTiming: append?.serverTimingHeader ?? null,
21739
+ appendRoundTripMs: append?.roundTripMs ?? null,
21740
+ // The id this delivery sent in its last append request's
21741
+ // transport-attempt header. Unlike the response fields above it is set
21742
+ // even when that request was aborted or never answered.
21743
+ appendTransportAttemptId,
21744
+ };
21745
+ }
21746
+
21501
21747
  /**
21502
21748
  * Admission persists an optional, run-scoped `run.ledger.project` token for the
21503
21749
  * worker's terminal fast path. Treat it as usable only when its decoded claims
@@ -21600,6 +21846,8 @@ async function requestRunLedgerDispatchToken(
21600
21846
  reused: boolean;
21601
21847
  cacheKey: string;
21602
21848
  runLedgerIngressPrefixBatching?: true;
21849
+ /** Present only when this call made the request (never for a reused token). */
21850
+ responseTrace?: RunLedgerDispatchResponseTrace;
21603
21851
  }> {
21604
21852
  const internalToken = process.env.DEEPLINE_INTERNAL_TOKEN?.trim();
21605
21853
  if (!internalToken || !input.eventId || !input.leaseOwner) {
@@ -21750,6 +21998,16 @@ async function requestRunLedgerDispatchToken(
21750
21998
  ...(body.runLedgerIngressPrefixBatching === true
21751
21999
  ? { runLedgerIngressPrefixBatching: true as const }
21752
22000
  : {}),
22001
+ responseTrace: {
22002
+ platformRequestId: readRuntimeApiDiagnosticHeader(
22003
+ response.headers,
22004
+ 'x-vercel-id',
22005
+ ),
22006
+ serverTimingHeader: readRuntimeApiDiagnosticHeader(
22007
+ response.headers,
22008
+ 'server-timing',
22009
+ ),
22010
+ },
21753
22011
  };
21754
22012
  }
21755
22013