@adcp/sdk 15.9.0 → 15.9.2

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.
@@ -12,14 +12,21 @@ CREATE TABLE IF NOT EXISTS adcp_reporting_warehouse_sinks (
12
12
  planned_revisions JSONB,
13
13
  planned_rows_attempt INTEGER NOT NULL DEFAULT 0 CHECK (planned_rows_attempt >= 0),
14
14
  planned_revisions_attempt INTEGER NOT NULL DEFAULT 0 CHECK (planned_revisions_attempt >= 0),
15
+ planned_rows_timeouts INTEGER NOT NULL DEFAULT 0 CHECK (planned_rows_timeouts >= 0),
16
+ planned_revisions_timeouts INTEGER NOT NULL DEFAULT 0 CHECK (planned_revisions_timeouts >= 0),
15
17
  reset_generation INTEGER NOT NULL DEFAULT 0 CHECK (reset_generation >= 0),
16
18
  updated_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(),
17
19
  CHECK ((planned_to_cursor IS NULL) = (planned_revisions IS NULL))
18
20
  );
19
21
  ALTER TABLE adcp_reporting_warehouse_sinks
20
22
  ADD COLUMN IF NOT EXISTS reset_generation INTEGER NOT NULL DEFAULT 0 CHECK (reset_generation >= 0);
23
+ ALTER TABLE adcp_reporting_warehouse_sinks
24
+ ADD COLUMN IF NOT EXISTS planned_rows_timeouts INTEGER NOT NULL DEFAULT 0 CHECK (planned_rows_timeouts >= 0);
25
+ ALTER TABLE adcp_reporting_warehouse_sinks
26
+ ADD COLUMN IF NOT EXISTS planned_revisions_timeouts INTEGER NOT NULL DEFAULT 0 CHECK (planned_revisions_timeouts >= 0);
21
27
  `.trim();
22
28
  const MAX_LOAD_TIMEOUT = 6 * 36e5;
29
+ const MAX_TIMEOUT_DOUBLINGS = 16;
23
30
  let warnedLabelsIgnored = false;
24
31
  const PROJECT = /^[a-z][a-z0-9-]{4,61}[a-z0-9]$/;
25
32
  const DATASET_OR_TABLE = /^[A-Za-z_][A-Za-z0-9_]{0,1023}$/;
@@ -72,51 +79,104 @@ function createBigQueryReportingWarehouseSinkV1(options) {
72
79
  ...options.projectId ? { projectId: options.projectId } : {},
73
80
  ...options.location ? { location: options.location } : {}
74
81
  } : void 0;
75
- async function cancelLoad(jobId, signal) {
82
+ const uploads = /* @__PURE__ */ new Map();
83
+ function startUpload(tableId, jobId, lines) {
84
+ const entry = {
85
+ startedAt: Date.now(),
86
+ done: Promise.resolve()
87
+ };
88
+ const cleanup = async () => {
89
+ if (uploads.get(jobId) === entry) uploads.delete(jobId);
90
+ if (entry.directory) await fs.rm(entry.directory, { recursive: true, force: true }).catch(() => {
91
+ });
92
+ };
93
+ entry.done = (async () => {
94
+ const directory = await fs.mkdtemp(path.join(tmpdir(), "adcp-warehouse-"));
95
+ entry.directory = directory;
96
+ const file = path.join(directory, `${jobId}.ndjson`);
97
+ await fs.writeFile(file, lines.length ? lines.join("\n") + "\n" : "", { mode: 384 });
98
+ return dataset.table(tableId).load(file, {
99
+ jobId,
100
+ sourceFormat: "NEWLINE_DELIMITED_JSON",
101
+ writeDisposition: "WRITE_APPEND",
102
+ ...options.location ? { location: options.location } : {}
103
+ });
104
+ })();
105
+ const replaced = uploads.get(jobId);
106
+ uploads.set(jobId, entry);
107
+ void entry.done.then(cleanup, cleanup);
108
+ if (replaced?.directory) void fs.rm(replaced.directory, { recursive: true, force: true }).catch(() => {
109
+ });
110
+ return entry.done;
111
+ }
112
+ async function jobStatus(jobId, signal, boundMilliseconds = loadTimeout, context) {
113
+ let metadata;
76
114
  try {
77
- const job = options.bigquery.job(jobId, jobOptions);
78
- if (typeof job.cancel !== "function") return;
79
- const cancel = job.cancel.bind(job);
80
- await withinDeadline(cancel, Math.min(loadTimeout, 3e4), signal);
81
- } catch (error) {
82
- const code = error?.code;
83
- if (code === 404 || signal?.aborted) return;
84
- process.emitWarning(
85
- `Cancelling BigQuery load job ${jobId} failed (${typeof code === "number" || typeof code === "string" ? code : "no status code"}); the job may still be running`,
86
- { code: "ADCP_BIGQUERY_SINK_CANCEL_FAILED" }
115
+ metadata = await withinDeadline(
116
+ () => options.bigquery.job(jobId, jobOptions).getMetadata(),
117
+ boundMilliseconds,
118
+ signal,
119
+ context
87
120
  );
121
+ } catch (error) {
122
+ if (error?.code === 404) return "missing";
123
+ throw error;
88
124
  }
125
+ const record = Array.isArray(metadata) ? metadata[0] : metadata;
126
+ if (record?.status?.state !== "DONE") return "running";
127
+ if (record.status.errorResult) {
128
+ const failure = new Error("A BigQuery load job for this batch failed; it will be retried as a new attempt");
129
+ Object.defineProperty(failure, "adcpJobFailed", { value: true });
130
+ throw failure;
131
+ }
132
+ return "done";
89
133
  }
90
- async function loadOnce(tableId, jobId, lines, attempt, signal) {
91
- const loadDeadline = Math.min(loadTimeout * 2 ** Math.min(attempt, 16), MAX_LOAD_TIMEOUT);
134
+ async function loadOnce(role, tableId, jobId, lines, timeouts, signal) {
92
135
  signal?.throwIfAborted();
93
- const directory = await fs.mkdtemp(path.join(tmpdir(), "adcp-warehouse-"));
94
- const file = path.join(directory, `${jobId}.ndjson`);
95
- try {
96
- await fs.writeFile(file, lines.length ? lines.join("\n") + "\n" : "", { mode: 384 });
136
+ const table = `the ${role} table "${tableId}" (timeout count ${timeouts})`;
137
+ let status = await jobStatus(jobId, signal, loadTimeout, table);
138
+ if (status === "done") return;
139
+ const loadDeadline = reportingWarehouseLoadDeadlineV1(loadTimeout, timeouts);
140
+ const deadlineAt = Date.now() + loadDeadline;
141
+ const timedOut = (what) => {
142
+ const error = new Error(
143
+ `${what} exceeded this run's ${loadDeadline} ms deadline for ${table}; the next run checks the job again`
144
+ );
145
+ Object.defineProperty(error, "adcpDeadlineExceeded", { value: true });
146
+ Object.defineProperty(error, "adcpLoadTimedOut", { value: true });
147
+ return error;
148
+ };
149
+ if (status === "missing") {
97
150
  try {
98
- await withinDeadline(
99
- () => dataset.table(tableId).load(file, {
100
- jobId,
101
- sourceFormat: "NEWLINE_DELIMITED_JSON",
102
- writeDisposition: "WRITE_APPEND",
103
- ...options.location ? { location: options.location } : {}
104
- }),
105
- loadDeadline,
106
- signal
107
- );
151
+ const running = uploads.get(jobId);
152
+ const upload = running && Date.now() - running.startedAt < MAX_LOAD_TIMEOUT ? running.done : startUpload(tableId, jobId, lines);
153
+ await withinDeadline(() => upload, Math.max(deadlineAt - Date.now(), 1), signal);
154
+ return;
108
155
  } catch (error) {
109
- if (isDeadlineExceeded(error)) await cancelLoad(jobId, signal);
156
+ if (isDeadlineExceeded(error)) throw timedOut("Uploading the load");
110
157
  if (!isAlreadyExists(error)) throw error;
111
- const metadata = await withinDeadline(
112
- () => options.bigquery.job(jobId, jobOptions).getMetadata(),
113
- loadTimeout,
114
- signal
115
- );
116
- assertJobSucceeded(metadata);
158
+ status = await jobStatus(jobId, signal, loadTimeout, table);
159
+ if (status === "missing") {
160
+ throw new Error(
161
+ "BigQuery refused the load job ID as already existing, but the job cannot be found. Check that projectId and location match the dataset (location is required for datasets outside the US and EU multi-regions)",
162
+ { cause: error }
163
+ );
164
+ }
117
165
  }
118
- } finally {
119
- await fs.rm(directory, { recursive: true, force: true });
166
+ }
167
+ const pollMilliseconds = Math.min(5e3, Math.max(250, Math.floor(loadDeadline / 10)));
168
+ while (status !== "done") {
169
+ const remaining = deadlineAt - Date.now();
170
+ if (remaining <= 0) throw timedOut("Waiting for the running load job");
171
+ await sleep(Math.min(pollMilliseconds, remaining), signal);
172
+ const bound = Math.max(Math.min(loadTimeout, deadlineAt - Date.now()), 1);
173
+ try {
174
+ status = await jobStatus(jobId, signal, bound, table);
175
+ } catch (error) {
176
+ if (isDeadlineExceeded(error) && bound < loadTimeout) throw timedOut("Waiting for the running load job");
177
+ throw error;
178
+ }
179
+ if (status === "missing") throw new Error("A BigQuery load job for this batch disappeared while it was awaited");
120
180
  }
121
181
  }
122
182
  return {
@@ -131,6 +191,7 @@ function createBigQueryReportingWarehouseSinkV1(options) {
131
191
  `UPDATE adcp_reporting_warehouse_sinks
132
192
  SET committed_cursor = NULL, planned_from_cursor = NULL, planned_to_cursor = NULL,
133
193
  planned_revisions = NULL, planned_rows_attempt = 0, planned_revisions_attempt = 0,
194
+ planned_rows_timeouts = 0, planned_revisions_timeouts = 0,
134
195
  reset_generation = reset_generation + 1, updated_at = clock_timestamp()
135
196
  WHERE sink_name = $1 AND ($2::boolean OR planned_to_cursor IS NULL)
136
197
  RETURNING sink_name`,
@@ -164,7 +225,8 @@ function createBigQueryReportingWarehouseSinkV1(options) {
164
225
  );
165
226
  const state = (await options.db.query(
166
227
  `SELECT committed_cursor, planned_from_cursor, planned_to_cursor, planned_revisions,
167
- planned_rows_attempt, planned_revisions_attempt, reset_generation
228
+ planned_rows_attempt, planned_revisions_attempt,
229
+ planned_rows_timeouts, planned_revisions_timeouts, reset_generation
168
230
  FROM adcp_reporting_warehouse_sinks WHERE sink_name = $1`,
169
231
  [options.name]
170
232
  ).catch(missingMigration)).rows[0];
@@ -183,7 +245,9 @@ function createBigQueryReportingWarehouseSinkV1(options) {
183
245
  to: state.planned_to_cursor,
184
246
  revisions: state.planned_revisions,
185
247
  rowsAttempt: state.planned_rows_attempt,
186
- revisionsAttempt: state.planned_revisions_attempt
248
+ revisionsAttempt: state.planned_revisions_attempt,
249
+ rowsTimeouts: state.planned_rows_timeouts,
250
+ revisionsTimeouts: state.planned_revisions_timeouts
187
251
  } : void 0;
188
252
  if (!plan) {
189
253
  const position = {
@@ -232,12 +296,15 @@ function createBigQueryReportingWarehouseSinkV1(options) {
232
296
  to: page.cursor,
233
297
  revisions: page.records.filter((record) => record.kind === "revision").map((record) => ({ id: record.record_id, account_id: record.account_id })),
234
298
  rowsAttempt: 0,
235
- revisionsAttempt: 0
299
+ revisionsAttempt: 0,
300
+ rowsTimeouts: 0,
301
+ revisionsTimeouts: 0
236
302
  };
237
303
  const claimed = await options.db.query(
238
304
  `UPDATE adcp_reporting_warehouse_sinks
239
305
  SET planned_from_cursor = $2, planned_to_cursor = $3, planned_revisions = $4::jsonb,
240
- planned_rows_attempt = 0, planned_revisions_attempt = 0, updated_at = clock_timestamp()
306
+ planned_rows_attempt = 0, planned_revisions_attempt = 0,
307
+ planned_rows_timeouts = 0, planned_revisions_timeouts = 0, updated_at = clock_timestamp()
241
308
  WHERE sink_name = $1 AND committed_cursor IS NOT DISTINCT FROM $2
242
309
  AND planned_to_cursor IS NULL AND planned_revisions IS NULL AND reset_generation = $5
243
310
  RETURNING sink_name`,
@@ -310,27 +377,52 @@ function createBigQueryReportingWarehouseSinkV1(options) {
310
377
  const baseJobId = reportingWarehouseJobIdV1(options.name, plan.from, plan.to, state.reset_generation);
311
378
  const suffix = (attempt) => attempt ? `_a${attempt}` : "";
312
379
  const steps = [
313
- { table: options.rowsTableId, kind: "rows", lines: rowLines, attempt: plan.rowsAttempt },
314
- { table: options.revisionsTableId, kind: "revs", lines: revisionLines, attempt: plan.revisionsAttempt }
380
+ {
381
+ table: options.rowsTableId,
382
+ role: "rows",
383
+ kind: "rows",
384
+ lines: rowLines,
385
+ attempt: plan.rowsAttempt,
386
+ timeouts: plan.rowsTimeouts,
387
+ timeoutColumn: "planned_rows_timeouts",
388
+ attemptColumn: "planned_rows_attempt"
389
+ },
390
+ {
391
+ table: options.revisionsTableId,
392
+ role: "revisions",
393
+ kind: "revs",
394
+ lines: revisionLines,
395
+ attempt: plan.revisionsAttempt,
396
+ timeouts: plan.revisionsTimeouts,
397
+ timeoutColumn: "planned_revisions_timeouts",
398
+ attemptColumn: "planned_revisions_attempt"
399
+ }
315
400
  ];
316
401
  for (const step of steps) {
317
402
  if (!step.lines.length) continue;
318
403
  try {
319
404
  await loadOnce(
405
+ step.role,
320
406
  step.table,
321
407
  `${baseJobId}_${step.kind}${suffix(step.attempt)}`,
322
408
  [...step.lines],
323
- step.attempt,
409
+ step.timeouts,
324
410
  signal
325
411
  );
326
412
  } catch (error) {
327
413
  if (isFinishedWithError(error)) {
328
- const column = step.kind === "rows" ? "planned_rows_attempt" : "planned_revisions_attempt";
329
414
  await options.db.query(
330
- `UPDATE adcp_reporting_warehouse_sinks SET ${column} = ${column} + 1,
415
+ `UPDATE adcp_reporting_warehouse_sinks SET ${step.attemptColumn} = ${step.attemptColumn} + 1,
331
416
  updated_at = clock_timestamp() ${matchesPlan}`,
332
417
  planValues
333
418
  );
419
+ } else if (isLoadTimedOut(error)) {
420
+ await options.db.query(
421
+ `UPDATE adcp_reporting_warehouse_sinks
422
+ SET ${step.timeoutColumn} = $8::integer + 1, updated_at = clock_timestamp()
423
+ ${matchesPlan} AND ${step.timeoutColumn} = $8::integer`,
424
+ [...planValues, step.timeouts]
425
+ );
334
426
  }
335
427
  throw error;
336
428
  }
@@ -339,7 +431,7 @@ function createBigQueryReportingWarehouseSinkV1(options) {
339
431
  `UPDATE adcp_reporting_warehouse_sinks
340
432
  SET committed_cursor = $3, planned_from_cursor = NULL, planned_to_cursor = NULL,
341
433
  planned_revisions = NULL, planned_rows_attempt = 0, planned_revisions_attempt = 0,
342
- updated_at = clock_timestamp()
434
+ planned_rows_timeouts = 0, planned_revisions_timeouts = 0, updated_at = clock_timestamp()
343
435
  ${matchesPlan} RETURNING sink_name`,
344
436
  planValues
345
437
  );
@@ -358,6 +450,9 @@ function missingMigration(error) {
358
450
  }
359
451
  throw error;
360
452
  }
453
+ function reportingWarehouseLoadDeadlineV1(baseMilliseconds, timeouts) {
454
+ return Math.min(baseMilliseconds * 2 ** Math.min(Math.max(timeouts, 0), MAX_TIMEOUT_DOUBLINGS), MAX_LOAD_TIMEOUT);
455
+ }
361
456
  function reportingWarehouseJobIdV1(name, from, to, generation = 0) {
362
457
  return `adcp_rr_${createHash("sha256").update(JSON.stringify(generation > 0 ? [name, from, to, generation] : [name, from, to])).digest("hex").slice(0, 40)}`;
363
458
  }
@@ -430,7 +525,7 @@ function sourceLocalDate(start, timeZone) {
430
525
  return instant.toISOString().slice(0, 10);
431
526
  }
432
527
  }
433
- async function withinDeadline(operation, milliseconds, signal) {
528
+ async function withinDeadline(operation, milliseconds, signal, context) {
434
529
  signal?.throwIfAborted();
435
530
  let timer;
436
531
  let onAbort;
@@ -439,7 +534,9 @@ async function withinDeadline(operation, milliseconds, signal) {
439
534
  operation(),
440
535
  new Promise((_, reject) => {
441
536
  timer = setTimeout(() => {
442
- const error = new Error("BigQuery call exceeded its deadline; the batch will be retried");
537
+ const error = new Error(
538
+ `BigQuery call exceeded its deadline${context ? ` of ${milliseconds} ms for ${context}` : ""}; the batch will be retried`
539
+ );
443
540
  Object.defineProperty(error, "adcpDeadlineExceeded", { value: true });
444
541
  reject(error);
445
542
  }, milliseconds);
@@ -461,24 +558,31 @@ function isAlreadyExists(error) {
461
558
  const record = error;
462
559
  return record?.code === 409 || !!record?.errors?.some((entry) => entry.reason === "duplicate");
463
560
  }
561
+ function isLoadTimedOut(error) {
562
+ return error?.adcpLoadTimedOut === true;
563
+ }
564
+ function sleep(milliseconds, signal) {
565
+ signal?.throwIfAborted();
566
+ return new Promise((resolve, reject) => {
567
+ const onAbort = () => {
568
+ clearTimeout(timer);
569
+ reject(signal?.reason ?? new Error("aborted"));
570
+ };
571
+ const timer = setTimeout(() => {
572
+ signal?.removeEventListener("abort", onAbort);
573
+ resolve();
574
+ }, milliseconds);
575
+ signal?.addEventListener("abort", onAbort, { once: true });
576
+ });
577
+ }
464
578
  function isFinishedWithError(error) {
465
579
  return error?.adcpJobFailed === true;
466
580
  }
467
- function assertJobSucceeded(metadata) {
468
- const record = Array.isArray(metadata) ? metadata[0] : metadata;
469
- if (record?.status?.state !== "DONE") {
470
- throw new Error("A BigQuery load job for this batch is still running; retry later");
471
- }
472
- if (record.status.errorResult) {
473
- const failure = new Error("A BigQuery load job for this batch failed; it will be retried as a new attempt");
474
- Object.defineProperty(failure, "adcpJobFailed", { value: true });
475
- throw failure;
476
- }
477
- }
478
581
  export {
479
582
  REPORTING_WAREHOUSE_SINK_MIGRATION,
480
583
  createBigQueryReportingWarehouseSinkV1,
481
584
  reportingWarehouseCurrentRowsViewSqlV1,
482
585
  reportingWarehouseDefaultTablesSqlV1,
483
- reportingWarehouseJobIdV1
586
+ reportingWarehouseJobIdV1,
587
+ reportingWarehouseLoadDeadlineV1
484
588
  };
@@ -4,5 +4,5 @@
4
4
  "source_sha": "4e553ad955f83b49c7d221ab5c3ff78237ad02e3",
5
5
  "source_tarball_sha256": "580656d6466ef9f0d1119985e6726c2efea718dc671e2ad30957fcb2fd54af0f",
6
6
  "upstream_adcp_version": "2.5.3",
7
- "synced_at": "2026-10-13T02:34:34.174Z"
7
+ "synced_at": "2026-10-15T19:50:31.412Z"
8
8
  }
@@ -50,6 +50,7 @@ var import_ssrf_fetch = require('../net/ssrf-fetch.js');
50
50
  var import_version = require('../version.js');
51
51
  var import_node_crypto = require("node:crypto");
52
52
  var import_client_hooks = require('../validation/client-hooks.js');
53
+ var import_schema_loader = require('../validation/schema-loader.js');
53
54
  var import_error_extraction = require('../utils/error-extraction.js');
54
55
  var import_client = require('../signing/client.js');
55
56
  var import_storage_registry = require('../auth/oauth/storage-registry.js');
@@ -418,7 +419,7 @@ async function discoverAgentProfile(client, signal, schemaAdcpVersion) {
418
419
  caps.data,
419
420
  "strict",
420
421
  void 0,
421
- schemaAdcpVersion ?? client.getAdcpVersion()
422
+ (0, import_schema_loader.resolveServedValidationVersion)(caps.data, schemaAdcpVersion ?? client.getAdcpVersion())
422
423
  );
423
424
  if (!validation.valid) {
424
425
  profile.capabilities_schema_issues = validation.issues.map((issue) => ({
@@ -10,6 +10,7 @@ import { SsrfRefusedError } from "../net/ssrf-fetch.mjs";
10
10
  import { ADCP_VERSION, toReleasePrecisionVersion } from "../version.mjs";
11
11
  import { createHmac, hkdfSync, randomBytes } from "node:crypto";
12
12
  import { validateIncomingResponse } from "../validation/client-hooks.mjs";
13
+ import { resolveServedValidationVersion } from "../validation/schema-loader.mjs";
13
14
  import { extractVersionUnsupportedDetails } from "../utils/error-extraction.mjs";
14
15
  import { buildAgentSigningContext } from "../signing/client.mjs";
15
16
  import { bindAgentStorage } from "../auth/oauth/storage-registry.mjs";
@@ -378,7 +379,7 @@ async function discoverAgentProfile(client, signal, schemaAdcpVersion) {
378
379
  caps.data,
379
380
  "strict",
380
381
  void 0,
381
- schemaAdcpVersion ?? client.getAdcpVersion()
382
+ resolveServedValidationVersion(caps.data, schemaAdcpVersion ?? client.getAdcpVersion())
382
383
  );
383
384
  if (!validation.valid) {
384
385
  profile.capabilities_schema_issues = validation.issues.map((issue) => ({
@@ -239,7 +239,7 @@ function crossValidateProtocolsAndTools(capabilities, tools) {
239
239
  creative: import_capabilities.CREATIVE_TOOLS,
240
240
  sponsored_intelligence: import_capabilities.SPONSORED_INTELLIGENCE_TOOLS,
241
241
  trusted_match: import_capabilities.TRUSTED_MATCH_TOOLS,
242
- compliance: import_capabilities.COMPLIANCE_TOOLS
242
+ compliance_testing: import_capabilities.COMPLIANCE_TOOLS
243
243
  };
244
244
  const perProtocolDiffs = {};
245
245
  for (const protocol of capabilities.protocols) {
@@ -225,7 +225,7 @@ function crossValidateProtocolsAndTools(capabilities, tools) {
225
225
  creative: CREATIVE_TOOLS,
226
226
  sponsored_intelligence: SPONSORED_INTELLIGENCE_TOOLS,
227
227
  trusted_match: TRUSTED_MATCH_TOOLS,
228
- compliance: COMPLIANCE_TOOLS
228
+ compliance_testing: COMPLIANCE_TOOLS
229
229
  };
230
230
  const perProtocolDiffs = {};
231
231
  for (const protocol of capabilities.protocols) {
@@ -197,7 +197,7 @@ export interface UpstreamTrafficQueryResult {
197
197
  */
198
198
  export declare function runValidations(validations: StoryboardValidation[], context: ValidationContext): ValidationResult[];
199
199
  /** Capability semver emitted in run summaries and used for advisory expiry. */
200
- export declare const RUNNER_CAPABILITY_VERSION = "15.9.0";
200
+ export declare const RUNNER_CAPABILITY_VERSION = "15.9.2";
201
201
  /** True when a failed validation contributes to the owning step's grade. */
202
202
  export declare function validationFailsStep(result: ValidationResult): boolean;
203
203
  /**
@@ -197,7 +197,7 @@ export interface UpstreamTrafficQueryResult {
197
197
  */
198
198
  export declare function runValidations(validations: StoryboardValidation[], context: ValidationContext): ValidationResult[];
199
199
  /** Capability semver emitted in run summaries and used for advisory expiry. */
200
- export declare const RUNNER_CAPABILITY_VERSION = "15.9.0";
200
+ export declare const RUNNER_CAPABILITY_VERSION = "15.9.2";
201
201
  /** True when a failed validation contributes to the owning step's grade. */
202
202
  export declare function validationFailsStep(result: ValidationResult): boolean;
203
203
  /**
@@ -46,6 +46,7 @@ __export(schema_loader_exports, {
46
46
  listValidatorKeys: () => listValidatorKeys,
47
47
  registerExternalSchemaRoot: () => registerExternalSchemaRoot,
48
48
  resolveBundleKey: () => resolveBundleKey,
49
+ resolveServedValidationVersion: () => resolveServedValidationVersion,
49
50
  schemaAllowsTopLevelField: () => schemaAllowsTopLevelField,
50
51
  toReleasePrecisionWire: () => toReleasePrecisionWire,
51
52
  unregisterExternalSchemaRoot: () => unregisterExternalSchemaRoot,
@@ -718,6 +719,29 @@ function hasSchemaBundle(version) {
718
719
  return false;
719
720
  }
720
721
  }
722
+ const SERVED_RELEASE_MAJOR = /^(\d+)\.\d+(?:-[a-zA-Z0-9.-]+)?$/;
723
+ const NUMERIC_PIN_MAJOR = /^(\d+)\.\d+/;
724
+ function resolveServedValidationVersion(response, pinnedVersion) {
725
+ const pinMajor = NUMERIC_PIN_MAJOR.exec(pinnedVersion)?.[1];
726
+ if (pinMajor === void 0) return pinnedVersion;
727
+ try {
728
+ if (isExternalSchemaRootActive(pinnedVersion)) return pinnedVersion;
729
+ } catch {
730
+ return pinnedVersion;
731
+ }
732
+ const echoed = response !== null && typeof response === "object" ? response.adcp_version : void 0;
733
+ if (typeof echoed !== "string") return pinnedVersion;
734
+ const echoMajor = SERVED_RELEASE_MAJOR.exec(echoed)?.[1];
735
+ if (echoMajor === void 0 || echoMajor !== pinMajor) return pinnedVersion;
736
+ let pinnedRelease;
737
+ try {
738
+ pinnedRelease = toReleasePrecisionWire(pinnedVersion);
739
+ } catch {
740
+ return pinnedVersion;
741
+ }
742
+ if (echoed === pinnedRelease) return pinnedVersion;
743
+ return hasSchemaBundle(echoed) ? echoed : pinnedVersion;
744
+ }
721
745
  const mcpToolSchemaCache = /* @__PURE__ */ new Map();
722
746
  const mcpToolSummaryCache = /* @__PURE__ */ new Map();
723
747
  function boundedMcpToolSummary(value) {
@@ -981,6 +1005,7 @@ function cloneJsonValue(value) {
981
1005
  listValidatorKeys,
982
1006
  registerExternalSchemaRoot,
983
1007
  resolveBundleKey,
1008
+ resolveServedValidationVersion,
984
1009
  schemaAllowsTopLevelField,
985
1010
  toReleasePrecisionWire,
986
1011
  unregisterExternalSchemaRoot,
@@ -668,6 +668,29 @@ function hasSchemaBundle(version) {
668
668
  return false;
669
669
  }
670
670
  }
671
+ const SERVED_RELEASE_MAJOR = /^(\d+)\.\d+(?:-[a-zA-Z0-9.-]+)?$/;
672
+ const NUMERIC_PIN_MAJOR = /^(\d+)\.\d+/;
673
+ function resolveServedValidationVersion(response, pinnedVersion) {
674
+ const pinMajor = NUMERIC_PIN_MAJOR.exec(pinnedVersion)?.[1];
675
+ if (pinMajor === void 0) return pinnedVersion;
676
+ try {
677
+ if (isExternalSchemaRootActive(pinnedVersion)) return pinnedVersion;
678
+ } catch {
679
+ return pinnedVersion;
680
+ }
681
+ const echoed = response !== null && typeof response === "object" ? response.adcp_version : void 0;
682
+ if (typeof echoed !== "string") return pinnedVersion;
683
+ const echoMajor = SERVED_RELEASE_MAJOR.exec(echoed)?.[1];
684
+ if (echoMajor === void 0 || echoMajor !== pinMajor) return pinnedVersion;
685
+ let pinnedRelease;
686
+ try {
687
+ pinnedRelease = toReleasePrecisionWire(pinnedVersion);
688
+ } catch {
689
+ return pinnedVersion;
690
+ }
691
+ if (echoed === pinnedRelease) return pinnedVersion;
692
+ return hasSchemaBundle(echoed) ? echoed : pinnedVersion;
693
+ }
671
694
  const mcpToolSchemaCache = /* @__PURE__ */ new Map();
672
695
  const mcpToolSummaryCache = /* @__PURE__ */ new Map();
673
696
  function boundedMcpToolSummary(value) {
@@ -930,6 +953,7 @@ export {
930
953
  listValidatorKeys,
931
954
  registerExternalSchemaRoot,
932
955
  resolveBundleKey,
956
+ resolveServedValidationVersion,
933
957
  schemaAllowsTopLevelField,
934
958
  toReleasePrecisionWire,
935
959
  unregisterExternalSchemaRoot,
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * AdCP SDK library version
3
3
  */
4
- export declare const LIBRARY_VERSION = "15.9.0";
4
+ export declare const LIBRARY_VERSION = "15.9.2";
5
5
  /**
6
6
  * AdCP specification version this library is built for
7
7
  */
@@ -33,10 +33,10 @@ export type AdcpVersion = (typeof COMPATIBLE_ADCP_VERSIONS)[number];
33
33
  * Full version information
34
34
  */
35
35
  export declare const VERSION_INFO: {
36
- readonly library: "15.9.0";
36
+ readonly library: "15.9.2";
37
37
  readonly adcp: "3.2.4";
38
38
  readonly compatibleVersions: readonly ["v2.5", "v2.6", "v3", "3.0.0", "3.0", "3.0.1", "3.0.2", "3.0.3", "3.0.4", "3.0.5", "3.0.6", "3.0.7", "3.0.8", "3.0.9", "3.0.10", "3.0.11", "3.0.12", "3.0.13", "3.0.14", "3.0.15", "3.0.16", "3.0.17", "3.0.18", "3.0.19", "3.0.20", "3.0.21", "3.0.22", "3.0.23", "3.0.24", "3.0.25", "3.1.0", "3.1", "3.1.1", "3.1.2", "3.1.3", "3.1.4", "3.1.5", "3.1.6", "3.1.7", "3.1.8", "3.1.9", "3.1.10", "3.1.11", "3.1.12", "3.1.13", "3.1.14", "3.1.15", "3.1.16", "3.1.17", "3.1.18", "3.1.19", "3.1.20", "3.1.21", "3.1.22", "3.1.23", "3.1.24", "3.2.1", "3.2", "3.2.2", "3.2.3", "3.2.4"];
39
- readonly generatedAt: "2026-10-13T01:26:11.275Z";
39
+ readonly generatedAt: "2026-10-15T19:20:29.059Z";
40
40
  };
41
41
  /**
42
42
  * Get the AdCP specification version this library is built for
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * AdCP SDK library version
3
3
  */
4
- export declare const LIBRARY_VERSION = "15.9.0";
4
+ export declare const LIBRARY_VERSION = "15.9.2";
5
5
  /**
6
6
  * AdCP specification version this library is built for
7
7
  */
@@ -33,10 +33,10 @@ export type AdcpVersion = (typeof COMPATIBLE_ADCP_VERSIONS)[number];
33
33
  * Full version information
34
34
  */
35
35
  export declare const VERSION_INFO: {
36
- readonly library: "15.9.0";
36
+ readonly library: "15.9.2";
37
37
  readonly adcp: "3.2.4";
38
38
  readonly compatibleVersions: readonly ["v2.5", "v2.6", "v3", "3.0.0", "3.0", "3.0.1", "3.0.2", "3.0.3", "3.0.4", "3.0.5", "3.0.6", "3.0.7", "3.0.8", "3.0.9", "3.0.10", "3.0.11", "3.0.12", "3.0.13", "3.0.14", "3.0.15", "3.0.16", "3.0.17", "3.0.18", "3.0.19", "3.0.20", "3.0.21", "3.0.22", "3.0.23", "3.0.24", "3.0.25", "3.1.0", "3.1", "3.1.1", "3.1.2", "3.1.3", "3.1.4", "3.1.5", "3.1.6", "3.1.7", "3.1.8", "3.1.9", "3.1.10", "3.1.11", "3.1.12", "3.1.13", "3.1.14", "3.1.15", "3.1.16", "3.1.17", "3.1.18", "3.1.19", "3.1.20", "3.1.21", "3.1.22", "3.1.23", "3.1.24", "3.2.1", "3.2", "3.2.2", "3.2.3", "3.2.4"];
39
- readonly generatedAt: "2026-10-13T01:26:11.275Z";
39
+ readonly generatedAt: "2026-10-15T19:20:29.059Z";
40
40
  };
41
41
  /**
42
42
  * Get the AdCP specification version this library is built for
@@ -31,7 +31,7 @@ __export(version_exports, {
31
31
  toReleasePrecisionVersion: () => toReleasePrecisionVersion
32
32
  });
33
33
  module.exports = __toCommonJS(version_exports);
34
- const LIBRARY_VERSION = "15.9.0";
34
+ const LIBRARY_VERSION = "15.9.2";
35
35
  const ADCP_VERSION = "3.2.4";
36
36
  const ADCP_MAJOR_VERSION = 3;
37
37
  const COMPATIBLE_ADCP_VERSIONS = [
@@ -98,10 +98,10 @@ const COMPATIBLE_ADCP_VERSIONS = [
98
98
  "3.2.4"
99
99
  ];
100
100
  const VERSION_INFO = {
101
- library: "15.9.0",
101
+ library: "15.9.2",
102
102
  adcp: "3.2.4",
103
103
  compatibleVersions: COMPATIBLE_ADCP_VERSIONS,
104
- generatedAt: "2026-10-13T01:26:11.275Z"
104
+ generatedAt: "2026-10-15T19:20:29.059Z"
105
105
  };
106
106
  function getAdcpVersion() {
107
107
  return ADCP_VERSION;
@@ -1,4 +1,4 @@
1
- const LIBRARY_VERSION = "15.9.0";
1
+ const LIBRARY_VERSION = "15.9.2";
2
2
  const ADCP_VERSION = "3.2.4";
3
3
  const ADCP_MAJOR_VERSION = 3;
4
4
  const COMPATIBLE_ADCP_VERSIONS = [
@@ -65,10 +65,10 @@ const COMPATIBLE_ADCP_VERSIONS = [
65
65
  "3.2.4"
66
66
  ];
67
67
  const VERSION_INFO = {
68
- library: "15.9.0",
68
+ library: "15.9.2",
69
69
  adcp: "3.2.4",
70
70
  compatibleVersions: COMPATIBLE_ADCP_VERSIONS,
71
- generatedAt: "2026-10-13T01:26:11.275Z"
71
+ generatedAt: "2026-10-15T19:20:29.059Z"
72
72
  };
73
73
  function getAdcpVersion() {
74
74
  return ADCP_VERSION;
@@ -1,7 +1,7 @@
1
1
  # AdCP Type Summary
2
2
 
3
- > Generated at: 2026-10-13
4
- > @adcp/sdk v15.9.0
3
+ > Generated at: 2026-10-15
4
+ > @adcp/sdk v15.9.2
5
5
 
6
6
  Curated reference of the types that matter for using the AdCP client. For full generated types see `src/lib/types/tools.generated.ts` and `src/lib/types/core.generated.ts`.
7
7