deepline 0.3.244 → 0.3.245

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.
@@ -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.244',
203
+ version: '0.3.245',
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: {
@@ -10,9 +10,7 @@ import {
10
10
  jsonByteLength,
11
11
  jsonByteLengthUpTo,
12
12
  } from '../output-size-limits';
13
- import {
14
- PLAY_RUNTIME_TRANSPORT_ATTEMPT_HEADER,
15
- } from '../runtime-contract';
13
+ import { PLAY_RUNTIME_TRANSPORT_ATTEMPT_HEADER } from '../runtime-contract';
16
14
  import {
17
15
  createRunnerGatewayTransportAttemptId,
18
16
  runnerGatewayTransportErrorCode,
@@ -595,8 +593,14 @@ export async function pushRunnerTerminal(
595
593
  : 'redirect',
596
594
  { status: response.status },
597
595
  );
598
- // 4xx (scope/fence rejections) are deterministic — retrying cannot help.
599
- if (response.status >= 400 && response.status < 500) {
596
+ // Gateway queue admission can shed this first-write-wins terminal with
597
+ // 429 before acquiring a database client. Retry the same terminal fact
598
+ // within the existing attempt budget; scope/fence rejections stay final.
599
+ if (
600
+ response.status >= 400 &&
601
+ response.status < 500 &&
602
+ response.status !== 429
603
+ ) {
600
604
  warn('terminal_push_rejected', {
601
605
  runId: options.runId,
602
606
  status: response.status,
@@ -606,9 +610,12 @@ export async function pushRunnerTerminal(
606
610
  }
607
611
  } catch (error) {
608
612
  lastError = error instanceof Error ? error.message : String(error);
609
- reportTransport('network_error', {
610
- errorCode: runnerGatewayTransportErrorCode(error),
611
- });
613
+ reportTransport(
614
+ requestController.signal.aborted ? 'timeout' : 'network_error',
615
+ {
616
+ errorCode: runnerGatewayTransportErrorCode(error),
617
+ },
618
+ );
612
619
  } finally {
613
620
  clearTimeout(requestTimeout);
614
621
  }
@@ -488,10 +488,15 @@ async function main() {
488
488
  checkpointBytes: 0,
489
489
  tableNamespace: null,
490
490
  });
491
+ const requestBody = JSON.stringify({
492
+ action: 'runner_terminal',
493
+ runId: push.runId,
494
+ result,
495
+ });
491
496
  for (let attempt = 1; attempt <= 3; attempt += 1) {
497
+ const controller = new AbortController();
498
+ const timer = setTimeout(() => controller.abort(), 10000);
492
499
  try {
493
- const controller = new AbortController();
494
- const timer = setTimeout(() => controller.abort(), 10000);
495
500
  const response = await fetch(gateway + '/api/v2/plays/runtime', {
496
501
  method: 'POST',
497
502
  headers: {
@@ -501,28 +506,32 @@ async function main() {
501
506
  ? { 'fly-force-instance-id': preferredGatewayMachineId }
502
507
  : {}),
503
508
  },
504
- body: JSON.stringify({
505
- action: 'runner_terminal',
506
- runId: push.runId,
507
- result,
508
- }),
509
+ body: requestBody,
509
510
  signal: controller.signal,
510
511
  redirect: 'manual',
511
512
  });
512
- clearTimeout(timer);
513
+ // Keep the HTTP deadline through body consumption so retries do not
514
+ // leave an unread socket behind. The status already acknowledges the
515
+ // durable terminal even if its diagnostic response body is interrupted.
516
+ await response.text().catch(() => '');
513
517
  if (response.ok) {
514
518
  writeDiagnostic('[crash-terminal] pushed status=' + result.status);
515
519
  return;
516
520
  }
517
521
  writeDiagnostic('[crash-terminal] rejected http=' + response.status);
518
- // Deterministic scope/fence rejections cannot succeed on retry.
519
- if (response.status >= 400 && response.status < 500) return;
522
+ // A 429 is gateway admission pressure, not a scope/fence rejection.
523
+ // Replaying this terminal fact never replays customer execution.
524
+ if (response.status >= 400 && response.status < 500 && response.status !== 429) return;
520
525
  } catch (error) {
521
526
  writeDiagnostic(
522
527
  '[crash-terminal] transport ' + (error && error.message ? error.message : String(error)),
523
528
  );
529
+ } finally {
530
+ clearTimeout(timer);
531
+ }
532
+ if (attempt < 3) {
533
+ await new Promise((resolveDelay) => setTimeout(resolveDelay, attempt * 1000));
524
534
  }
525
- await new Promise((resolveDelay) => setTimeout(resolveDelay, attempt * 1000));
526
535
  }
527
536
  writeDiagnostic('[crash-terminal] exhausted retries');
528
537
  }
@@ -937,6 +937,7 @@ export async function withRuntimeSchedulerClient<T>(
937
937
  throw error;
938
938
  }
939
939
  const admissionWaitMs = performance.now() - admissionStartedAt;
940
+ let unsampledAdmissionWaitMs = admissionWaitMs;
940
941
  let lastError: unknown = null;
941
942
  try {
942
943
  throwIfSchedulerAborted(signal);
@@ -996,7 +997,14 @@ export async function withRuntimeSchedulerClient<T>(
996
997
  entry.stats.peakTotalClients,
997
998
  entry.pool.totalCount,
998
999
  );
999
- pushSample(entry.stats.acquireWait, acquireWaitMs);
1000
+ // The admission gate owns the local queue before pg.Pool sees this
1001
+ // checkout. Include that wait once, on the operation's first acquired
1002
+ // client; retries retain the permit and only add their own connect wait.
1003
+ pushSample(
1004
+ entry.stats.acquireWait,
1005
+ unsampledAdmissionWaitMs + acquireWaitMs,
1006
+ );
1007
+ unsampledAdmissionWaitMs = 0;
1000
1008
 
1001
1009
  // A checked-out pg client emits 'error' (not via the pool) when its TCP
1002
1010
  // connection dies while idle — e.g. a worker holding a client across a
@@ -1255,6 +1263,7 @@ export type RuntimeSchedulerPoolStats = {
1255
1263
  idleCount: number;
1256
1264
  waitingCount: number;
1257
1265
  acquires: number;
1266
+ /** Successful checkout latency, including local admission once per operation. */
1258
1267
  acquireWaitP50Ms: number | null;
1259
1268
  acquireWaitP95Ms: number | null;
1260
1269
  saturationRejections: number;
@@ -1388,6 +1397,8 @@ export async function probeRuntimeSchedulerDirectSession(input: {
1388
1397
  connectionString: deriveDirectDatabaseUrl(input.url),
1389
1398
  application_name:
1390
1399
  input.applicationName ?? 'deepline-runtime-direct-session-preflight',
1400
+ connectionTimeoutMillis: RUNTIME_SCHEDULER_POOL_DEFAULTS.connectTimeoutMs,
1401
+ query_timeout: RUNTIME_SCHEDULER_POOL_DEFAULTS.queryTimeoutMs,
1391
1402
  });
1392
1403
  try {
1393
1404
  await client.connect();
@@ -1648,6 +1659,8 @@ export function createPgNotifyHub(input: {
1648
1659
  const next = (input.createClient ?? ((config) => new Client(config)))({
1649
1660
  connectionString: directUrl,
1650
1661
  application_name: input.applicationName ?? 'deepline-runtime-notify-hub',
1662
+ connectionTimeoutMillis: RUNTIME_SCHEDULER_POOL_DEFAULTS.connectTimeoutMs,
1663
+ query_timeout: RUNTIME_SCHEDULER_POOL_DEFAULTS.queryTimeoutMs,
1651
1664
  });
1652
1665
  try {
1653
1666
  await next.connect();
@@ -8453,6 +8453,80 @@ export async function readPostgresSchedulerLaunchForAttemptLease(
8453
8453
  return row ? parseLaunchJson(row.launch_json) : null;
8454
8454
  }
8455
8455
 
8456
+ /** Identity, signing authority, and origins needed to issue an attempt token. */
8457
+ const POSTGRES_SCHEDULER_ATTEMPT_AUTHORITY_FIELDS = [
8458
+ 'runId',
8459
+ 'orgId',
8460
+ 'playName',
8461
+ 'userId',
8462
+ 'userEmail',
8463
+ 'baseUrl',
8464
+ 'runtimeApiBaseUrl',
8465
+ 'runtimeTokenOrigin',
8466
+ 'runtimeBackend',
8467
+ 'runtimeAuthority',
8468
+ ] as const;
8469
+
8470
+ export type PostgresSchedulerAttemptAuthority = Pick<
8471
+ PlaySchedulerSubmitInput,
8472
+ (typeof POSTGRES_SCHEDULER_ATTEMPT_AUTHORITY_FIELDS)[number]
8473
+ >;
8474
+
8475
+ /**
8476
+ * Prove the same attempt lease as the full execution reader, returning only
8477
+ * the token issuer's authority. Input, graph, and artifact bytes never cross
8478
+ * this SQL seam or occupy a Vercel checkout during JSON decoding. The authority
8479
+ * descriptor is retained intact for the existing validator and deploy skew;
8480
+ * its admitted secrets and fixture configuration are not execution payloads.
8481
+ */
8482
+ export async function readPostgresSchedulerAttemptAuthorityForLease(
8483
+ client: PostgresSchedulerQueryClient,
8484
+ input: { runId: string; attempt: number; leaseToken: string },
8485
+ options?: Pick<PostgresSchedulerOptions, 'schema'>,
8486
+ ): Promise<PostgresSchedulerAttemptAuthority | null> {
8487
+ const fields = POSTGRES_SCHEDULER_ATTEMPT_AUTHORITY_FIELDS;
8488
+ // Keep JSON types intact. A text record column would coerce malformed launch
8489
+ // scalars into strings, bypassing the full reader's required-field checks.
8490
+ const columns = [...fields, 'playId', 'executorToken']
8491
+ .map((field) => `${quoteIdent(field)} jsonb`)
8492
+ .join(', ');
8493
+ const result = await client.query<
8494
+ PostgresSchedulerAttemptAuthority & {
8495
+ launch_required_fields_valid: boolean;
8496
+ }
8497
+ >(
8498
+ `
8499
+ SELECT ${fields.map((field) => `launch.${quoteIdent(field)}`).join(', ')},
8500
+ ${['runId', 'playId', 'playName', 'executorToken', 'baseUrl']
8501
+ .map(
8502
+ (field) =>
8503
+ `jsonb_typeof(launch.${quoteIdent(field)}) = 'string'`,
8504
+ )
8505
+ .join(' AND ')} AS launch_required_fields_valid
8506
+ FROM ${tableName('runs', options)} AS runs
8507
+ JOIN ${tableName('attempts', options)} AS attempts
8508
+ ON attempts.run_id = runs.run_id
8509
+ CROSS JOIN LATERAL jsonb_to_record(runs.launch_json) AS launch(${columns})
8510
+ WHERE runs.run_id = $1
8511
+ AND runs.status IN ('queued', 'running', 'waiting')
8512
+ AND attempts.attempt = $2
8513
+ AND attempts.lease_token = $3
8514
+ AND attempts.status IN ('claimed', 'running', 'waiting')
8515
+ LIMIT 1
8516
+ `,
8517
+ [input.runId, input.attempt, input.leaseToken],
8518
+ );
8519
+ const row = result.rows[0];
8520
+ if (!row) return null;
8521
+ const { launch_required_fields_valid, ...authority } = row;
8522
+ if (launch_required_fields_valid !== true) {
8523
+ throw new Error(
8524
+ 'Postgres scheduler launch_json is missing required fields.',
8525
+ );
8526
+ }
8527
+ return authority;
8528
+ }
8529
+
8456
8530
  /**
8457
8531
  * Absurd scheduler backend: persist the vendored engine's task id on the run
8458
8532
  * row after `spawn`. Idempotent (last write wins); a re-submit under the same
package/dist/cli/index.js CHANGED
@@ -3473,7 +3473,7 @@ var SDK_RELEASE = {
3473
3473
  // getters keep their established compatibility behavior.
3474
3474
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
3475
3475
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
3476
- version: "0.3.244",
3476
+ version: "0.3.245",
3477
3477
  updateSummary: "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.",
3478
3478
  packageCapabilities: {
3479
3479
  updatePreferences: 1
@@ -3468,7 +3468,7 @@ var SDK_RELEASE = {
3468
3468
  // getters keep their established compatibility behavior.
3469
3469
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
3470
3470
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
3471
- version: "0.3.244",
3471
+ version: "0.3.245",
3472
3472
  updateSummary: "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.",
3473
3473
  packageCapabilities: {
3474
3474
  updatePreferences: 1
package/dist/index.js CHANGED
@@ -1286,7 +1286,7 @@ var SDK_RELEASE = {
1286
1286
  // getters keep their established compatibility behavior.
1287
1287
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
1288
1288
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
1289
- version: "0.3.244",
1289
+ version: "0.3.245",
1290
1290
  updateSummary: "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.",
1291
1291
  packageCapabilities: {
1292
1292
  updatePreferences: 1
package/dist/index.mjs CHANGED
@@ -1190,7 +1190,7 @@ var SDK_RELEASE = {
1190
1190
  // getters keep their established compatibility behavior.
1191
1191
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
1192
1192
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
1193
- version: "0.3.244",
1193
+ version: "0.3.245",
1194
1194
  updateSummary: "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.",
1195
1195
  packageCapabilities: {
1196
1196
  updatePreferences: 1
@@ -149,7 +149,7 @@ type SdkRelease = {
149
149
  supportPolicy: SdkSupportPolicy;
150
150
  };
151
151
  declare const SDK_RELEASE: {
152
- readonly version: "0.3.244";
152
+ readonly version: "0.3.245";
153
153
  readonly updateSummary: "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.";
154
154
  readonly packageCapabilities: {
155
155
  readonly updatePreferences: 1;
package/dist/release.d.ts CHANGED
@@ -149,7 +149,7 @@ type SdkRelease = {
149
149
  supportPolicy: SdkSupportPolicy;
150
150
  };
151
151
  declare const SDK_RELEASE: {
152
- readonly version: "0.3.244";
152
+ readonly version: "0.3.245";
153
153
  readonly updateSummary: "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.";
154
154
  readonly packageCapabilities: {
155
155
  readonly updatePreferences: 1;
package/dist/release.js CHANGED
@@ -74,7 +74,7 @@ var SDK_RELEASE = {
74
74
  // getters keep their established compatibility behavior.
75
75
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
76
76
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
77
- version: "0.3.244",
77
+ version: "0.3.245",
78
78
  updateSummary: "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.",
79
79
  packageCapabilities: {
80
80
  updatePreferences: 1
package/dist/release.mjs CHANGED
@@ -48,7 +48,7 @@ var SDK_RELEASE = {
48
48
  // getters keep their established compatibility behavior.
49
49
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
50
50
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
51
- version: "0.3.244",
51
+ version: "0.3.245",
52
52
  updateSummary: "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.",
53
53
  packageCapabilities: {
54
54
  updatePreferences: 1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepline",
3
- "version": "0.3.244",
3
+ "version": "0.3.245",
4
4
  "description": "GTM data CLI and TypeScript SDK for coding agents",
5
5
  "license": "MIT",
6
6
  "homepage": "https://code.deepline.com",