@usherlabs/cex-broker 0.2.52 → 0.3.0

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 (144) hide show
  1. package/dist/commands/cli.js +364 -71
  2. package/dist/index.js +365 -72
  3. package/dist/index.js.map +14 -13
  4. package/package.json +5 -28
  5. package/dist/commands/cex-canonical-orderbook-export.d.ts +0 -23
  6. package/dist/commands/cex-canonical-orderbook-export.js +0 -34275
  7. package/dist/commands/cex-canonical-orderbook-export.js.map +0 -266
  8. package/dist/commands/market-data-vendor-backfill.d.ts +0 -24
  9. package/dist/commands/market-data-vendor-backfill.js +0 -34930
  10. package/dist/commands/market-data-vendor-backfill.js.map +0 -268
  11. package/dist/handlers/execute-action/context.d.ts +0 -50
  12. package/dist/handlers/execute-action/deposit.d.ts +0 -2
  13. package/dist/handlers/execute-action/handler.d.ts +0 -19
  14. package/dist/handlers/execute-action/index.d.ts +0 -10
  15. package/dist/handlers/execute-action/internal-transfer.d.ts +0 -2
  16. package/dist/handlers/execute-action/order-book-call.d.ts +0 -3
  17. package/dist/handlers/execute-action/orders.d.ts +0 -2
  18. package/dist/handlers/execute-action/pass-through.d.ts +0 -2
  19. package/dist/handlers/execute-action/perp-config.d.ts +0 -2
  20. package/dist/handlers/execute-action/registry.d.ts +0 -5
  21. package/dist/handlers/execute-action/treasury-call.d.ts +0 -2
  22. package/dist/handlers/execute-action/withdraw.d.ts +0 -2
  23. package/dist/handlers/subscribe/broker-lifecycle.d.ts +0 -13
  24. package/dist/handlers/subscribe/handler.d.ts +0 -20
  25. package/dist/handlers/subscribe/index.d.ts +0 -2
  26. package/dist/handlers/types.d.ts +0 -23
  27. package/dist/helpers/account-balance-archive-poller.d.ts +0 -19
  28. package/dist/helpers/auth.d.ts +0 -5
  29. package/dist/helpers/balance-update-archive-consumer.d.ts +0 -16
  30. package/dist/helpers/binance-user-data-normalization.d.ts +0 -3
  31. package/dist/helpers/binance-user-data-stream.d.ts +0 -58
  32. package/dist/helpers/broker-execution-archive/capture.d.ts +0 -41
  33. package/dist/helpers/broker-execution-archive/index.d.ts +0 -7
  34. package/dist/helpers/broker-execution-archive/journal-export.d.ts +0 -20
  35. package/dist/helpers/broker-execution-archive/loss-journal.d.ts +0 -36
  36. package/dist/helpers/broker-execution-archive/redact.d.ts +0 -7
  37. package/dist/helpers/broker-execution-archive/rows.d.ts +0 -134
  38. package/dist/helpers/broker-execution-archive/types.d.ts +0 -26
  39. package/dist/helpers/broker-execution-archive/withdrawal-observation-tracker.d.ts +0 -23
  40. package/dist/helpers/broker-execution-archive/writer.d.ts +0 -105
  41. package/dist/helpers/broker.d.ts +0 -38
  42. package/dist/helpers/canonical-orderbook-export/exact-selection.d.ts +0 -21
  43. package/dist/helpers/canonical-orderbook-export/exporter.d.ts +0 -26
  44. package/dist/helpers/canonical-orderbook-export/parquet-projection.d.ts +0 -19
  45. package/dist/helpers/constants.d.ts +0 -36
  46. package/dist/helpers/deposit-archive-poller.d.ts +0 -66
  47. package/dist/helpers/deposit.d.ts +0 -5
  48. package/dist/helpers/exchange-credentials.d.ts +0 -10
  49. package/dist/helpers/fill-archive-poller.d.ts +0 -42
  50. package/dist/helpers/grpc/broker.d.ts +0 -5
  51. package/dist/helpers/grpc/callbacks.d.ts +0 -9
  52. package/dist/helpers/grpc/payload.d.ts +0 -9
  53. package/dist/helpers/grpc/status.d.ts +0 -8
  54. package/dist/helpers/index.d.ts +0 -44
  55. package/dist/helpers/logger.d.ts +0 -13
  56. package/dist/helpers/market-data-archive/canonical-orderbook.d.ts +0 -20
  57. package/dist/helpers/market-data-archive/capture-context.d.ts +0 -53
  58. package/dist/helpers/market-data-archive/capture-contract.d.ts +0 -30
  59. package/dist/helpers/market-data-archive/capture.d.ts +0 -22
  60. package/dist/helpers/market-data-archive/index.d.ts +0 -13
  61. package/dist/helpers/market-data-archive/legacy-migration.d.ts +0 -37
  62. package/dist/helpers/market-data-archive/ohlcv-bar-tracker.d.ts +0 -11
  63. package/dist/helpers/market-data-archive/ohlcv-bootstrap.d.ts +0 -1
  64. package/dist/helpers/market-data-archive/ohlcv-history.d.ts +0 -8
  65. package/dist/helpers/market-data-archive/orderbook-depth.d.ts +0 -5
  66. package/dist/helpers/market-data-archive/orderbook-sampler.d.ts +0 -12
  67. package/dist/helpers/market-data-archive/parse-stream.d.ts +0 -26
  68. package/dist/helpers/market-data-archive/rows.d.ts +0 -14
  69. package/dist/helpers/market-data-archive/types.d.ts +0 -83
  70. package/dist/helpers/market-data-preparation/conformance-fixtures.d.ts +0 -128
  71. package/dist/helpers/market-data-preparation/contracts.d.ts +0 -2970
  72. package/dist/helpers/market-data-preparation/file-job.d.ts +0 -38
  73. package/dist/helpers/market-data-preparation/required-clock-qualification.d.ts +0 -43
  74. package/dist/helpers/market-data-preparation/source-tape-dependencies.d.ts +0 -19
  75. package/dist/helpers/market-data-preparation/source-tape-operation.d.ts +0 -109
  76. package/dist/helpers/market-data-source-forensics.d.ts +0 -400
  77. package/dist/helpers/market-data-vendor-backfill/archive-reader.d.ts +0 -26
  78. package/dist/helpers/market-data-vendor-backfill/batching.d.ts +0 -10
  79. package/dist/helpers/market-data-vendor-backfill/conformance-fixtures.d.ts +0 -78
  80. package/dist/helpers/market-data-vendor-backfill/contracts.d.ts +0 -358
  81. package/dist/helpers/market-data-vendor-backfill/core.d.ts +0 -101
  82. package/dist/helpers/market-data-vendor-backfill/cryptohftdata.d.ts +0 -118
  83. package/dist/helpers/market-data-vendor-backfill/forwarder-client.d.ts +0 -25
  84. package/dist/helpers/market-data-vendor-backfill/identity.d.ts +0 -10
  85. package/dist/helpers/market-data-vendor-backfill/manifests.d.ts +0 -61
  86. package/dist/helpers/market-data-vendor-backfill/promotion.d.ts +0 -10
  87. package/dist/helpers/market-data-vendor-backfill/qualification.d.ts +0 -20
  88. package/dist/helpers/market-data-vendor-backfill/selection.d.ts +0 -30
  89. package/dist/helpers/market-data-vendor-backfill/semantic-verification.d.ts +0 -25
  90. package/dist/helpers/market-type.d.ts +0 -16
  91. package/dist/helpers/order-activity-tracker.d.ts +0 -22
  92. package/dist/helpers/order-book.d.ts +0 -79
  93. package/dist/helpers/order-telemetry.d.ts +0 -50
  94. package/dist/helpers/otel.d.ts +0 -83
  95. package/dist/helpers/passive-order.d.ts +0 -8
  96. package/dist/helpers/public-market-data-feed/identity.d.ts +0 -12
  97. package/dist/helpers/public-market-data-feed/index.d.ts +0 -5
  98. package/dist/helpers/public-market-data-feed/orderbook-coalescing-evidence.d.ts +0 -79
  99. package/dist/helpers/public-market-data-feed/orderbook-profile.d.ts +0 -54
  100. package/dist/helpers/public-market-data-feed/subscriber-buffer.d.ts +0 -31
  101. package/dist/helpers/public-market-data-feed/supervisor.d.ts +0 -82
  102. package/dist/helpers/shared/errors.d.ts +0 -14
  103. package/dist/helpers/shared/guards.d.ts +0 -2
  104. package/dist/helpers/source-tape-sandbox.d.ts +0 -82
  105. package/dist/helpers/source-tape.d.ts +0 -165
  106. package/dist/helpers/stream-health-publisher.d.ts +0 -41
  107. package/dist/helpers/trace-context.d.ts +0 -8
  108. package/dist/helpers/transfer-network.d.ts +0 -12
  109. package/dist/helpers/travel-rule-deposit-reconciler.d.ts +0 -159
  110. package/dist/helpers/travel-rule.d.ts +0 -75
  111. package/dist/helpers/treasury-discovery.d.ts +0 -17
  112. package/dist/helpers/user-asset-archive-poller.d.ts +0 -19
  113. package/dist/helpers/user-data-stream-supervisor.d.ts +0 -27
  114. package/dist/helpers/verity.d.ts +0 -5
  115. package/dist/index.d.ts +0 -56
  116. package/dist/market-data-preparation/fixtures/conformance-v3.json +0 -621
  117. package/dist/market-data-preparation/policies/capability-policy.json +0 -39
  118. package/dist/market-data-preparation/policies/resource-policy.json +0 -16
  119. package/dist/market-data-preparation/policies/source-tape-capability-v1.json +0 -35
  120. package/dist/market-data-preparation/schema-manifest.json +0 -66
  121. package/dist/market-data-preparation/schemas/archive-selection-v1.schema.json +0 -224
  122. package/dist/market-data-preparation/schemas/backfill-request-v1.schema.json +0 -166
  123. package/dist/market-data-preparation/schemas/backfill-result-v2.schema.json +0 -212
  124. package/dist/market-data-preparation/schemas/canonical-orderbook-export-request-v1.schema.json +0 -61
  125. package/dist/market-data-preparation/schemas/canonical-orderbook-export-result-v2.schema.json +0 -252
  126. package/dist/market-data-preparation/schemas/order-book-depth-summary-parquet-projection-v1.schema.json +0 -256
  127. package/dist/market-data-preparation/schemas/order-book-levels-parquet-projection-v1.schema.json +0 -220
  128. package/dist/market-data-preparation/schemas/preparation-product-pin-v2.schema.json +0 -176
  129. package/dist/market-data-preparation/schemas/promotion-receipt-v1.schema.json +0 -175
  130. package/dist/market-data-preparation/schemas/required-clock-v1.schema.json +0 -47
  131. package/dist/market-data-preparation/schemas/source-forensics-ledger-v1.schema.json +0 -463
  132. package/dist/market-data-preparation/schemas/source-qualification-record-v1.schema.json +0 -394
  133. package/dist/market-data-preparation.d.ts +0 -11
  134. package/dist/market-data-preparation.js +0 -37488
  135. package/dist/market-data-preparation.js.map +0 -277
  136. package/dist/market-data-vendor-backfill.d.ts +0 -21
  137. package/dist/market-data-vendor-backfill.js +0 -22463
  138. package/dist/market-data-vendor-backfill.js.map +0 -199
  139. package/dist/proto/node.descriptor.d.ts +0 -127
  140. package/dist/proto-loader-options.d.ts +0 -7
  141. package/dist/proto-package-definition.d.ts +0 -2
  142. package/dist/schemas/action-payloads.d.ts +0 -88
  143. package/dist/server.d.ts +0 -10
  144. package/dist/types.d.ts +0 -100
package/dist/index.js CHANGED
@@ -291352,6 +291352,22 @@ import {
291352
291352
  import { basename, dirname } from "node:path";
291353
291353
  var EXPORT_CHUNK_BYTES = 8 * 1024 * 1024;
291354
291354
  var SHA256_RECEIPT_PATTERN = /^([0-9a-f]{64}) {2}(.+)\n$/;
291355
+ function sha256File(path) {
291356
+ const hash4 = createHash3("sha256");
291357
+ const fd2 = openSync(path, "r");
291358
+ try {
291359
+ const chunk = Buffer.alloc(EXPORT_CHUNK_BYTES);
291360
+ for (;; ) {
291361
+ const read = readSync(fd2, chunk, 0, chunk.length, null);
291362
+ if (read === 0)
291363
+ break;
291364
+ hash4.update(chunk.subarray(0, read));
291365
+ }
291366
+ } finally {
291367
+ closeSync(fd2);
291368
+ }
291369
+ return hash4.digest("hex");
291370
+ }
291355
291371
 
291356
291372
  class DeadLetterJournalExportError extends Error {
291357
291373
  constructor(message, options) {
@@ -291385,6 +291401,9 @@ function exportDeadLetterJournal(journalPath, exportPath) {
291385
291401
  if (match?.[1] === undefined || match[2] !== basename(exportPath)) {
291386
291402
  throw new Error("export receipt is malformed");
291387
291403
  }
291404
+ if (sha256File(exportPath) !== match[1]) {
291405
+ throw new Error("export digest does not match receipt");
291406
+ }
291388
291407
  } catch (error) {
291389
291408
  throw new DeadLetterJournalExportError("Dead-letter journal export target is incomplete or unverifiable", { cause: error });
291390
291409
  }
@@ -293292,10 +293311,7 @@ import { createHash as createHash4 } from "node:crypto";
293292
293311
  var MARKET_CAPTURE_SCHEMA_VERSION = "1.0.0";
293293
293312
  var CHECKSUM_ALGORITHM = "sha256-canonical-json-v1";
293294
293313
  var ARCHIVE_SOURCES = ["broker_read", "broker_write"];
293295
- var MARKET_ARCHIVE_SOURCES = [
293296
- ...ARCHIVE_SOURCES,
293297
- "external_backfill"
293298
- ];
293314
+ var MARKET_ARCHIVE_SOURCES = ARCHIVE_SOURCES;
293299
293315
  var CAPTURE_FEEDS = [
293300
293316
  "ORDERBOOK",
293301
293317
  "TICKER",
@@ -293309,15 +293325,12 @@ var SOURCE_MODES = [
293309
293325
  "broker_bootstrap_fetch_v1",
293310
293326
  "external_ccxt_fallback_v1",
293311
293327
  "external_hummingbot_fallback_v1",
293312
- "legacy_migration_v1",
293313
- "historical_vendor_orderbook_v1",
293314
- "vendor_historical_backfill_v1"
293328
+ "legacy_migration_v1"
293315
293329
  ];
293316
293330
  var RAW_CAPTURE_SCOPES = [
293317
293331
  "ccxt_normalized_object",
293318
293332
  "broker_visible_payload",
293319
- "exchange_wire_frame",
293320
- "vendor_normalized_dataset_file"
293333
+ "exchange_wire_frame"
293321
293334
  ];
293322
293335
  var CHECKSUM_FIELDS = new Set([
293323
293336
  "normalized_row_checksum",
@@ -293506,6 +293519,9 @@ function createRawCapture(context2, input) {
293506
293519
  checksumAlgorithm: context2.checksumAlgorithm
293507
293520
  };
293508
293521
  }
293522
+ function projectRawCapturePayload(rawCapture, redactedPayload) {
293523
+ return { ...rawCapture, redactedPayload };
293524
+ }
293509
293525
  function captureCoreFields(context2, rawCapture) {
293510
293526
  assertCaptureContext(context2);
293511
293527
  return {
@@ -294082,14 +294098,20 @@ function resolveConservativeOrderBookAcquisitionProfile(input) {
294082
294098
  id: `${exchange}:conservative:default`,
294083
294099
  upstreamLimit: undefined,
294084
294100
  guaranteedRetainedDepth: undefined,
294085
- coalescingSupported: false
294101
+ coalescingSupported: false,
294102
+ bidExhaustionEvidence: false,
294103
+ askExhaustionEvidence: false,
294104
+ exhaustionEvidenceValidated: true
294086
294105
  };
294087
294106
  }
294088
294107
  return {
294089
294108
  id: `${exchange}:conservative:limit:${input.requestedDepth}`,
294090
294109
  upstreamLimit: input.requestedDepth,
294091
294110
  guaranteedRetainedDepth: input.requestedDepth,
294092
- coalescingSupported: false
294111
+ coalescingSupported: false,
294112
+ bidExhaustionEvidence: false,
294113
+ askExhaustionEvidence: false,
294114
+ exhaustionEvidenceValidated: true
294093
294115
  };
294094
294116
  }
294095
294117
  function resolveOrderBookAcquisitionProfile(input) {
@@ -294101,7 +294123,10 @@ function resolveOrderBookAcquisitionProfile(input) {
294101
294123
  id: candidateProfileId,
294102
294124
  upstreamLimit: VERIFIED_PROFILE_DEPTH,
294103
294125
  guaranteedRetainedDepth: VERIFIED_PROFILE_DEPTH,
294104
- coalescingSupported: true
294126
+ coalescingSupported: true,
294127
+ bidExhaustionEvidence: false,
294128
+ askExhaustionEvidence: false,
294129
+ exhaustionEvidenceValidated: true
294105
294130
  };
294106
294131
  }
294107
294132
  return resolveConservativeOrderBookAcquisitionProfile(input);
@@ -294251,7 +294276,63 @@ class PublicFeedSubscriberBuffer {
294251
294276
  this.#bytes = 0;
294252
294277
  }
294253
294278
  }
294279
+ // src/helpers/market-data-archive/orderbook-depth.ts
294280
+ var DEFAULT_ORDERBOOK_ARCHIVE_DEPTH_LIMIT = 25;
294281
+ var MAX_ORDERBOOK_ARCHIVE_DEPTH_LIMIT = 500;
294282
+ var MAX_ORDERBOOK_MEASUREMENT_BANDS = 64;
294283
+ var MAX_ORDERBOOK_MEASUREMENT_BAND_BPS = 1e4;
294284
+ var DEFAULT_ORDERBOOK_MEASUREMENT_BANDS_BPS = [10, 25, 50, 100];
294285
+ function parseBoundedDepth(raw, field) {
294286
+ if (!/^[1-9]\d*$/.test(raw)) {
294287
+ throw new Error(`${field} must be an integer between 1 and 500`);
294288
+ }
294289
+ const parsed = Number(raw);
294290
+ if (!Number.isSafeInteger(parsed) || parsed > MAX_ORDERBOOK_ARCHIVE_DEPTH_LIMIT) {
294291
+ throw new Error(`${field} must be an integer between 1 and 500`);
294292
+ }
294293
+ return parsed;
294294
+ }
294295
+ function getOrderbookArchiveDepthLimit() {
294296
+ const raw = process.env.CEX_BROKER_ORDERBOOK_ARCHIVE_DEPTH_LIMIT?.trim();
294297
+ if (!raw) {
294298
+ return DEFAULT_ORDERBOOK_ARCHIVE_DEPTH_LIMIT;
294299
+ }
294300
+ return parseBoundedDepth(raw, "CEX_BROKER_ORDERBOOK_ARCHIVE_DEPTH_LIMIT");
294301
+ }
294302
+ function normalizeOrderbookMeasurementBandsBps(input) {
294303
+ const bands = input ?? DEFAULT_ORDERBOOK_MEASUREMENT_BANDS_BPS;
294304
+ if (bands.length === 0) {
294305
+ throw new Error("ORDERBOOK measurement bands must not be empty");
294306
+ }
294307
+ if (bands.length > MAX_ORDERBOOK_MEASUREMENT_BANDS) {
294308
+ throw new Error(`ORDERBOOK measurement bands must contain at most ${MAX_ORDERBOOK_MEASUREMENT_BANDS} entries`);
294309
+ }
294310
+ for (const band of bands) {
294311
+ if (!Number.isSafeInteger(band) || band <= 0 || band > MAX_ORDERBOOK_MEASUREMENT_BAND_BPS) {
294312
+ throw new Error("ORDERBOOK measurement bands must be integer basis points in 1..10000");
294313
+ }
294314
+ }
294315
+ const normalized = [...new Set(bands)].sort((left, right) => left - right);
294316
+ if (normalized.length > MAX_ORDERBOOK_MEASUREMENT_BANDS) {
294317
+ throw new Error(`ORDERBOOK measurement bands must contain at most ${MAX_ORDERBOOK_MEASUREMENT_BANDS} unique entries`);
294318
+ }
294319
+ return normalized;
294320
+ }
294321
+ function getOrderbookMeasurementBandsBps() {
294322
+ const raw = process.env.CEX_BROKER_ORDERBOOK_MEASUREMENT_BANDS_BPS?.trim();
294323
+ if (!raw) {
294324
+ return [...DEFAULT_ORDERBOOK_MEASUREMENT_BANDS_BPS];
294325
+ }
294326
+ const parts = raw.split(",").map((entry) => entry.trim());
294327
+ if (parts.some((entry) => !/^[1-9]\d*$/.test(entry))) {
294328
+ throw new Error("CEX_BROKER_ORDERBOOK_MEASUREMENT_BANDS_BPS must be a comma-separated list of positive integers");
294329
+ }
294330
+ return normalizeOrderbookMeasurementBandsBps(parts.map(Number));
294331
+ }
294332
+
294254
294333
  // src/helpers/market-data-archive/canonical-orderbook.ts
294334
+ var ORDERBOOK_SUMMARY_SCHEMA_VERSION = "2.0.0";
294335
+
294255
294336
  class OrderBookValidationError extends Error {
294256
294337
  reason;
294257
294338
  constructor(reason) {
@@ -294277,38 +294358,70 @@ function parseSequence(value) {
294277
294358
  }
294278
294359
  return parsed.toString(10);
294279
294360
  }
294280
- function validateSide(side, levels, depthLimit) {
294361
+ function validatePositiveInteger(value, field, maximum = Number.MAX_SAFE_INTEGER) {
294362
+ if (!Number.isSafeInteger(value) || value <= 0 || value > maximum) {
294363
+ throw new OrderBookValidationError(`${field} must be a positive integer${maximum === 500 ? " between 1 and 500" : ""}`);
294364
+ }
294365
+ }
294366
+ function validateSide(side, levels) {
294281
294367
  if (levels.length === 0) {
294282
294368
  throw new OrderBookValidationError(`${side} side is missing`);
294283
294369
  }
294284
- const retained = levels.slice(0, depthLimit);
294285
- for (let index2 = 0;index2 < retained.length; index2 += 1) {
294286
- const entry = retained[index2];
294370
+ const validated = [];
294371
+ for (let index2 = 0;index2 < levels.length; index2 += 1) {
294372
+ const entry = levels[index2];
294287
294373
  const price = entry?.[0];
294288
294374
  const amount = entry?.[1];
294289
294375
  if (!Array.isArray(entry) || entry.length < 2 || price === undefined || amount === undefined || !Number.isFinite(price) || !Number.isFinite(amount) || price <= 0 || amount <= 0) {
294290
294376
  throw new OrderBookValidationError(`${side} level ${index2} has a non-positive or non-finite price/amount`);
294291
294377
  }
294292
294378
  if (index2 > 0) {
294293
- const previous = retained[index2 - 1]?.[0];
294379
+ const previous = validated[index2 - 1]?.price;
294294
294380
  if (previous === undefined || (side === "bid" ? price >= previous : price <= previous)) {
294295
294381
  throw new OrderBookValidationError(`${side} levels are not strictly ${side === "bid" ? "descending" : "ascending"}`);
294296
294382
  }
294297
294383
  }
294384
+ validated.push({ price, amount });
294298
294385
  }
294299
- return retained.map(([price, amount]) => ({
294300
- price,
294301
- amount
294302
- }));
294386
+ return validated;
294303
294387
  }
294304
- function normalizedBands(input) {
294305
- const bands = input ?? [10, 25, 50, 100];
294306
- for (const band of bands) {
294307
- if (!Number.isFinite(band) || band <= 0 || !Number.isInteger(band)) {
294308
- throw new OrderBookValidationError("measurement bands must be positive integer basis points");
294388
+ function validateMetadata(metadata, observedBids, observedAsks) {
294389
+ if (!metadata.captureProfileId.trim()) {
294390
+ throw new OrderBookValidationError("capture_profile_id must not be empty");
294391
+ }
294392
+ validatePositiveInteger(metadata.effectiveCadenceMs, "effective_cadence_ms");
294393
+ if (metadata.requestedUpstreamDepth !== null) {
294394
+ validatePositiveInteger(metadata.requestedUpstreamDepth, "requested_upstream_depth", 500);
294395
+ }
294396
+ validatePositiveInteger(metadata.observedBidCount, "observed_bid_count");
294397
+ validatePositiveInteger(metadata.observedAskCount, "observed_ask_count");
294398
+ if (metadata.observedBidCount !== observedBids.length) {
294399
+ throw new OrderBookValidationError("observed_bid_count does not match the complete observation");
294400
+ }
294401
+ if (metadata.observedAskCount !== observedAsks.length) {
294402
+ throw new OrderBookValidationError("observed_ask_count does not match the complete observation");
294403
+ }
294404
+ const farthestBid = observedBids.at(-1)?.price;
294405
+ const farthestAsk = observedAsks.at(-1)?.price;
294406
+ if (!Number.isFinite(metadata.observedFarthestBid) || metadata.observedFarthestBid <= 0 || metadata.observedFarthestBid !== farthestBid) {
294407
+ throw new OrderBookValidationError("observed_farthest_bid does not match the complete observation");
294408
+ }
294409
+ if (!Number.isFinite(metadata.observedFarthestAsk) || metadata.observedFarthestAsk <= 0 || metadata.observedFarthestAsk !== farthestAsk) {
294410
+ throw new OrderBookValidationError("observed_farthest_ask does not match the complete observation");
294411
+ }
294412
+ for (const [side, evidence] of [
294413
+ ["bid", metadata.exhaustionEvidence.bid],
294414
+ ["ask", metadata.exhaustionEvidence.ask]
294415
+ ]) {
294416
+ if (evidence.validated !== true || typeof evidence.exhausted !== "boolean" || !evidence.source.trim()) {
294417
+ throw new OrderBookValidationError(`${side} exhaustion evidence must be validated and source-bound`);
294309
294418
  }
294310
294419
  }
294311
- return [...new Set(bands)].sort((left, right) => left - right);
294420
+ try {
294421
+ return normalizeOrderbookMeasurementBandsBps(metadata.measurementBandsBps);
294422
+ } catch (error) {
294423
+ throw new OrderBookValidationError(error instanceof Error ? error.message : "invalid measurement bands");
294424
+ }
294312
294425
  }
294313
294426
  function checksumRow(row) {
294314
294427
  return { ...row, normalized_row_checksum: sha256Canonical(row) };
@@ -294319,20 +294432,33 @@ function commonEvidenceFields(context2, rawCapture, input) {
294319
294432
  source_time_ms: input.eventTimeMs,
294320
294433
  received_time_ms: input.receivedTimeMs,
294321
294434
  snapshot_id: input.snapshotId,
294322
- construction_mode: input.constructionMode,
294435
+ construction_mode: "sampled_top_n_snapshot",
294323
294436
  gap_policy: "record_gap",
294324
294437
  depth_limit: input.depthLimit,
294325
294438
  sequence: input.sequence,
294326
294439
  exact_l2_reconstruction_complete: 0
294327
294440
  };
294328
294441
  }
294442
+ function sideBandEvidence(input) {
294443
+ const farthest = input.levels.at(-1)?.price;
294444
+ const depths = input.boundaries.map((boundary) => input.levels.filter(({ price }) => input.side === "bid" ? price >= boundary : price <= boundary).reduce((sum3, { amount }) => sum3 + amount, 0));
294445
+ const statuses = input.boundaries.map((boundary) => {
294446
+ const boundaryReached = input.side === "bid" ? farthest <= boundary : farthest >= boundary;
294447
+ return boundaryReached || input.exhausted ? "exact" : "censored";
294448
+ });
294449
+ return { depths, statuses };
294450
+ }
294329
294451
  function buildCanonicalOrderBookRows(input) {
294330
- if (!Number.isSafeInteger(input.depthLimit) || input.depthLimit <= 0 || input.depthLimit > 500) {
294331
- throw new OrderBookValidationError("depth limit must be an integer between 1 and 500");
294332
- }
294452
+ validatePositiveInteger(input.depthLimit, "depth limit", 500);
294333
294453
  if (input.context.feed !== "ORDERBOOK") {
294334
294454
  throw new OrderBookValidationError("capture context feed is not ORDERBOOK");
294335
294455
  }
294456
+ if (input.context.schemaVersion !== "1.0.0") {
294457
+ throw new OrderBookValidationError("ORDERBOOK raw and level capture schema must be 1.0.0");
294458
+ }
294459
+ if (!input.context.provenanceComplete) {
294460
+ throw new OrderBookValidationError("summary v2 requires complete live provenance");
294461
+ }
294336
294462
  if (input.constructionMode === "exact_l2_reconstruction") {
294337
294463
  throw new OrderBookValidationError("exact L2 requires a complete continuity proof and is unsupported");
294338
294464
  }
@@ -294347,13 +294473,18 @@ function buildCanonicalOrderBookRows(input) {
294347
294473
  if (receivedTimeMs < eventTimeMs) {
294348
294474
  throw new OrderBookValidationError("received timestamp precedes source timestamp");
294349
294475
  }
294350
- const bids = validateSide("bid", input.snapshot.bids, input.depthLimit);
294351
- const asks = validateSide("ask", input.snapshot.asks, input.depthLimit);
294352
- const bestBid = bids[0];
294353
- const bestAsk = asks[0];
294476
+ const observedBids = validateSide("bid", input.snapshot.bids);
294477
+ const observedAsks = validateSide("ask", input.snapshot.asks);
294478
+ const bestBid = observedBids[0];
294479
+ const bestAsk = observedAsks[0];
294354
294480
  if (bestBid.price >= bestAsk.price) {
294355
294481
  throw new OrderBookValidationError("book is crossed or locked");
294356
294482
  }
294483
+ const bands = validateMetadata(input.archiveMetadata, observedBids, observedAsks);
294484
+ const bids = observedBids.slice(0, input.depthLimit);
294485
+ const asks = observedAsks.slice(0, input.depthLimit);
294486
+ const retainedFarthestBid = bids.at(-1);
294487
+ const retainedFarthestAsk = asks.at(-1);
294357
294488
  const sequence = parseSequence(input.snapshot.sequence);
294358
294489
  const midPrice = (bestBid.price + bestAsk.price) / 2;
294359
294490
  const spread2 = bestAsk.price - bestBid.price;
@@ -294373,8 +294504,7 @@ function buildCanonicalOrderBookRows(input) {
294373
294504
  sequence,
294374
294505
  depthLimit: input.depthLimit,
294375
294506
  eventTimeMs,
294376
- receivedTimeMs,
294377
- constructionMode: input.constructionMode ?? "sampled_top_n_snapshot"
294507
+ receivedTimeMs
294378
294508
  });
294379
294509
  const levels = [
294380
294510
  ["bid", bids],
@@ -294392,17 +294522,34 @@ function buildCanonicalOrderBookRows(input) {
294392
294522
  });
294393
294523
  return { table: "market_data.cex_order_book_levels", row };
294394
294524
  }));
294395
- const bands = normalizedBands(input.measurementBandsBps);
294396
- const bidDepth = bands.map((band) => {
294397
- const minimumPrice = bestBid.price * (1 - band / 1e4);
294398
- return bids.filter(({ price }) => price >= minimumPrice).reduce((sum3, { amount }) => sum3 + amount, 0);
294525
+ const bidBoundaries = bands.map((band) => midPrice * (1 - band / 1e4));
294526
+ const askBoundaries = bands.map((band) => midPrice * (1 + band / 1e4));
294527
+ const bidEvidence = sideBandEvidence({
294528
+ levels: observedBids,
294529
+ boundaries: bidBoundaries,
294530
+ side: "bid",
294531
+ exhausted: input.archiveMetadata.exhaustionEvidence.bid.exhausted
294399
294532
  });
294400
- const askDepth = bands.map((band) => {
294401
- const maximumPrice = bestAsk.price * (1 + band / 1e4);
294402
- return asks.filter(({ price }) => price <= maximumPrice).reduce((sum3, { amount }) => sum3 + amount, 0);
294533
+ const askEvidence = sideBandEvidence({
294534
+ levels: observedAsks,
294535
+ boundaries: askBoundaries,
294536
+ side: "ask",
294537
+ exhausted: input.archiveMetadata.exhaustionEvidence.ask.exhausted
294403
294538
  });
294404
294539
  const summaryRow = checksumRow({
294405
294540
  ...common,
294541
+ schema_version: ORDERBOOK_SUMMARY_SCHEMA_VERSION,
294542
+ capture_profile_id: input.archiveMetadata.captureProfileId,
294543
+ effective_cadence_ms: input.archiveMetadata.effectiveCadenceMs,
294544
+ requested_upstream_depth: input.archiveMetadata.requestedUpstreamDepth,
294545
+ observed_bid_count: input.archiveMetadata.observedBidCount,
294546
+ observed_ask_count: input.archiveMetadata.observedAskCount,
294547
+ observed_farthest_bid: input.archiveMetadata.observedFarthestBid,
294548
+ observed_farthest_ask: input.archiveMetadata.observedFarthestAsk,
294549
+ retained_farthest_bid: retainedFarthestBid.price,
294550
+ retained_farthest_ask: retainedFarthestAsk.price,
294551
+ bid_exhausted: input.archiveMetadata.exhaustionEvidence.bid.exhausted ? 1 : 0,
294552
+ ask_exhausted: input.archiveMetadata.exhaustionEvidence.ask.exhausted ? 1 : 0,
294406
294553
  best_bid: bestBid.price,
294407
294554
  best_ask: bestAsk.price,
294408
294555
  best_bid_amount: bestBid.amount,
@@ -294414,8 +294561,12 @@ function buildCanonicalOrderBookRows(input) {
294414
294561
  bid_level_count: bids.length,
294415
294562
  ask_level_count: asks.length,
294416
294563
  measurement_bands_bps: bands,
294417
- bid_depth_by_band: bidDepth,
294418
- ask_depth_by_band: askDepth
294564
+ bid_boundary_price_by_band: bidBoundaries,
294565
+ ask_boundary_price_by_band: askBoundaries,
294566
+ bid_depth_by_band: bidEvidence.depths,
294567
+ ask_depth_by_band: askEvidence.depths,
294568
+ bid_status_by_band: bidEvidence.statuses,
294569
+ ask_status_by_band: askEvidence.statuses
294419
294570
  });
294420
294571
  return {
294421
294572
  snapshotId,
@@ -294545,21 +294696,6 @@ class OhlcvBarTracker {
294545
294696
  }
294546
294697
  }
294547
294698
 
294548
- // src/helpers/market-data-archive/orderbook-depth.ts
294549
- var DEFAULT_ORDERBOOK_ARCHIVE_DEPTH_LIMIT = 25;
294550
- var MAX_ORDERBOOK_ARCHIVE_DEPTH_LIMIT = 500;
294551
- function getOrderbookArchiveDepthLimit() {
294552
- const raw = process.env.CEX_BROKER_ORDERBOOK_ARCHIVE_DEPTH_LIMIT;
294553
- if (!raw) {
294554
- return DEFAULT_ORDERBOOK_ARCHIVE_DEPTH_LIMIT;
294555
- }
294556
- const parsed = Number.parseInt(raw, 10);
294557
- if (!Number.isFinite(parsed) || parsed <= 0) {
294558
- return DEFAULT_ORDERBOOK_ARCHIVE_DEPTH_LIMIT;
294559
- }
294560
- return Math.min(parsed, MAX_ORDERBOOK_ARCHIVE_DEPTH_LIMIT);
294561
- }
294562
-
294563
294699
  // src/helpers/market-data-archive/parse-stream.ts
294564
294700
  function isFiniteNumber2(value) {
294565
294701
  return typeof value === "number" && Number.isFinite(value);
@@ -294683,13 +294819,17 @@ function legacyMarketFields(context2, rawCapture) {
294683
294819
  function legacyDecimal8(value) {
294684
294820
  return value === undefined ? undefined : Number(value.toFixed(8));
294685
294821
  }
294686
- function buildCanonicalCexStreamEventRow(context2, rawCapture) {
294822
+ function buildCanonicalCexStreamEventRow(context2, rawCapture, options) {
294823
+ const payloadEncoding = options?.payloadEncoding ?? "canonical_json_v1";
294824
+ if (payloadEncoding === "orderbook_metadata_only_v1" && context2.feed !== "ORDERBOOK") {
294825
+ throw new Error("Metadata-only raw encoding requires an ORDERBOOK context");
294826
+ }
294687
294827
  const row = withNormalizedChecksum({
294688
294828
  ...captureCoreFields(context2, rawCapture),
294689
294829
  ...legacyMarketFields(context2, rawCapture),
294690
294830
  stream_type: context2.feed,
294691
294831
  event_time_ms: rawCapture.eventTimeMs,
294692
- payload_encoding: "canonical_json_v1",
294832
+ payload_encoding: payloadEncoding,
294693
294833
  payload_json: canonicalSerialize(rawCapture.redactedPayload)
294694
294834
  });
294695
294835
  return { table: "market_data.cex_stream_events", row };
@@ -294833,7 +294973,13 @@ function archiveOrderbookInBackground(archiver, otelMetrics, input, options) {
294833
294973
  queueMicrotask(() => {
294834
294974
  try {
294835
294975
  const context2 = resolveCaptureContext(archiver, input, "ORDERBOOK", options?.sourceMode ?? "broker_live_sampling_v1");
294836
- const rawCapture = createRawCapture(context2, {
294976
+ const depthLimit = options?.depthLimit ?? getOrderbookArchiveDepthLimit();
294977
+ const measurementBandsBps = normalizeOrderbookMeasurementBandsBps(input.archiveMetadata.measurementBandsBps);
294978
+ const archiveMetadata = {
294979
+ ...input.archiveMetadata,
294980
+ measurementBandsBps
294981
+ };
294982
+ const completeRawCapture = createRawCapture(context2, {
294837
294983
  payload: input.snapshot,
294838
294984
  eventTimeMs: input.snapshot.timestamp,
294839
294985
  receivedTimeMs: input.snapshot.receivedTimestamp,
@@ -294842,10 +294988,29 @@ function archiveOrderbookInBackground(archiver, otelMetrics, input, options) {
294842
294988
  const canonical = buildCanonicalOrderBookRows({
294843
294989
  context: context2,
294844
294990
  snapshot: input.snapshot,
294845
- rawCapture,
294846
- depthLimit: options?.depthLimit ?? getOrderbookArchiveDepthLimit()
294991
+ rawCapture: completeRawCapture,
294992
+ depthLimit,
294993
+ archiveMetadata
294847
294994
  });
294848
- archiver.enqueue(buildCanonicalCexStreamEventRow(context2, rawCapture));
294995
+ const rawMetadata = {
294996
+ capture_profile_id: archiveMetadata.captureProfileId,
294997
+ effective_cadence_ms: archiveMetadata.effectiveCadenceMs,
294998
+ requested_upstream_depth: archiveMetadata.requestedUpstreamDepth,
294999
+ archive_depth_limit: depthLimit,
295000
+ observed_bid_count: archiveMetadata.observedBidCount,
295001
+ observed_ask_count: archiveMetadata.observedAskCount,
295002
+ observed_farthest_bid: canonicalDecimal(archiveMetadata.observedFarthestBid),
295003
+ observed_farthest_ask: canonicalDecimal(archiveMetadata.observedFarthestAsk),
295004
+ bid_exhausted: archiveMetadata.exhaustionEvidence.bid.exhausted,
295005
+ ask_exhausted: archiveMetadata.exhaustionEvidence.ask.exhausted,
295006
+ retained_bid_count: canonical.levels.filter(({ row }) => row.side === "bid").length,
295007
+ retained_ask_count: canonical.levels.filter(({ row }) => row.side === "ask").length,
295008
+ measurement_bands_bps: measurementBandsBps
295009
+ };
295010
+ const storedRawCapture = projectRawCapturePayload(completeRawCapture, rawMetadata);
295011
+ archiver.enqueue(buildCanonicalCexStreamEventRow(context2, storedRawCapture, {
295012
+ payloadEncoding: "orderbook_metadata_only_v1"
295013
+ }));
294849
295014
  for (const row of canonical.levels)
294850
295015
  archiver.enqueue(row);
294851
295016
  archiver.enqueue(canonical.summary);
@@ -294967,6 +295132,9 @@ function archiveTickerInBackground(archiver, otelMetrics, input) {
294967
295132
  });
294968
295133
  }
294969
295134
  function archiveCexStreamEventInBackground(archiver, otelMetrics, input) {
295135
+ if (input.streamType === "ORDERBOOK") {
295136
+ throw new Error("Generic ORDERBOOK archive events are unsupported; use archiveOrderbookInBackground");
295137
+ }
294970
295138
  archiveMarketRowsInBackground(archiver, otelMetrics, "stream", input, input.streamType, () => [
294971
295139
  buildCexStreamEventRow({
294972
295140
  ...input,
@@ -294991,6 +295159,82 @@ function resolveOhlcvBootstrapLimit(optionValue) {
294991
295159
  }
294992
295160
  return Math.min(parsed, MAX_OHLCV_BOOTSTRAP_LIMIT);
294993
295161
  }
295162
+ // src/helpers/market-data-archive/summary-v2-conformance.ts
295163
+ var ORDERBOOK_SUMMARY_V2_SUPPORTED_VIEW_FIELDS = [
295164
+ ["source", "String", false],
295165
+ ["deployment_id", "String", false],
295166
+ ["capture_bundle_id", "String", false],
295167
+ ["exchange", "String", false],
295168
+ ["symbol", "String", false],
295169
+ ["trading_pair", "String", false],
295170
+ ["source_symbol", "String", false],
295171
+ ["asset_type", "String", false],
295172
+ ["feed", "String", false],
295173
+ ["provider", "String", false],
295174
+ ["source_mode", "String", false],
295175
+ ["source_time_ms", "UInt64", false],
295176
+ ["received_time_ms", "UInt64", false],
295177
+ ["raw_capture_id", "String", false],
295178
+ ["raw_capture_scope", "String", false],
295179
+ ["schema_version", "String", false],
295180
+ ["checksum_algorithm", "String", false],
295181
+ ["raw_checksum", "String", false],
295182
+ ["provenance_complete", "UInt8", false],
295183
+ ["snapshot_id", "String", false],
295184
+ ["construction_mode", "String", false],
295185
+ ["gap_policy", "String", false],
295186
+ ["depth_limit", "UInt16", false],
295187
+ ["sequence", "UInt64", true],
295188
+ ["exact_l2_reconstruction_complete", "UInt8", false],
295189
+ ["capture_profile_id", "String", false],
295190
+ ["effective_cadence_ms", "UInt32", false],
295191
+ ["requested_upstream_depth", "UInt16", true],
295192
+ ["observed_bid_count", "UInt32", false],
295193
+ ["observed_ask_count", "UInt32", false],
295194
+ ["observed_farthest_bid", "Decimal(38,18)", false],
295195
+ ["observed_farthest_ask", "Decimal(38,18)", false],
295196
+ ["retained_farthest_bid", "Decimal(38,18)", false],
295197
+ ["retained_farthest_ask", "Decimal(38,18)", false],
295198
+ ["bid_exhausted", "UInt8", false],
295199
+ ["ask_exhausted", "UInt8", false],
295200
+ ["best_bid", "Decimal(38,18)", false],
295201
+ ["best_ask", "Decimal(38,18)", false],
295202
+ ["best_bid_amount", "Decimal(38,18)", false],
295203
+ ["best_ask_amount", "Decimal(38,18)", false],
295204
+ ["mid_price", "Decimal(38,18)", false],
295205
+ ["spread", "Decimal(38,18)", false],
295206
+ ["spread_bps", "Float64", false],
295207
+ ["staleness_ms", "UInt64", false],
295208
+ ["bid_level_count", "UInt16", false],
295209
+ ["ask_level_count", "UInt16", false],
295210
+ ["measurement_bands_bps", "Array(UInt32)", false],
295211
+ ["bid_boundary_price_by_band", "Array(Decimal(38,18))", false],
295212
+ ["ask_boundary_price_by_band", "Array(Decimal(38,18))", false],
295213
+ ["bid_depth_by_band", "Array(Decimal(38,18))", false],
295214
+ ["ask_depth_by_band", "Array(Decimal(38,18))", false],
295215
+ ["bid_status_by_band", "Array(Enum8('exact'=1,'censored'=2))", false],
295216
+ ["ask_status_by_band", "Array(Enum8('exact'=1,'censored'=2))", false],
295217
+ ["normalized_row_checksum", "String", false]
295218
+ ];
295219
+ var ORDERBOOK_SUMMARY_V2_SUPPORTED_VIEW_FIELD_NAMES = ORDERBOOK_SUMMARY_V2_SUPPORTED_VIEW_FIELDS.map(([name]) => name);
295220
+ var DECIMAL_38_18_FIELDS = new Set([
295221
+ "observed_farthest_bid",
295222
+ "observed_farthest_ask",
295223
+ "retained_farthest_bid",
295224
+ "retained_farthest_ask",
295225
+ "best_bid",
295226
+ "best_ask",
295227
+ "best_bid_amount",
295228
+ "best_ask_amount",
295229
+ "mid_price",
295230
+ "spread"
295231
+ ]);
295232
+ var DECIMAL_38_18_ARRAY_FIELDS = new Set([
295233
+ "bid_boundary_price_by_band",
295234
+ "ask_boundary_price_by_band",
295235
+ "bid_depth_by_band",
295236
+ "ask_depth_by_band"
295237
+ ]);
294994
295238
  // src/helpers/order-book.ts
294995
295239
  var ORDER_BOOK_CALL_METHODS = {
294996
295240
  FETCH_CAPABILITY: "fetch_order_book_capability",
@@ -295342,7 +295586,7 @@ class PublicFeedWorker {
295342
295586
  if (this.options.profile) {
295343
295587
  this.options.metrics?.recordCounter("public_feed_acquisition_profiles_total", 1, {
295344
295588
  ...this.#metricLabels(),
295345
- profile: this.options.profile.id
295589
+ profile_class: this.options.profile.coalescingSupported ? "coalesced" : "conservative"
295346
295590
  });
295347
295591
  }
295348
295592
  this.#run = this.#watchLoop();
@@ -295410,7 +295654,34 @@ class PublicFeedWorker {
295410
295654
  depthLimit: retainedDepth,
295411
295655
  receivedTimestamp
295412
295656
  });
295413
- this.options.archiveSink.orderbook({ ...context2, snapshot }, { sampledOut: !this.#sampler.shouldEmit(receivedTimestamp) });
295657
+ const observedBidCount = snapshot.bids.length;
295658
+ const observedAskCount = snapshot.asks.length;
295659
+ this.options.archiveSink.orderbook({
295660
+ ...context2,
295661
+ snapshot,
295662
+ archiveMetadata: {
295663
+ captureProfileId: this.options.profile?.id ?? `${this.options.exchangeName}:conservative:default`,
295664
+ effectiveCadenceMs: getOrderbookIntervalMs(),
295665
+ requestedUpstreamDepth: this.options.profile?.upstreamLimit ?? null,
295666
+ observedBidCount,
295667
+ observedAskCount,
295668
+ observedFarthestBid: snapshot.bids.at(-1)?.[0] ?? Number.NaN,
295669
+ observedFarthestAsk: snapshot.asks.at(-1)?.[0] ?? Number.NaN,
295670
+ exhaustionEvidence: {
295671
+ bid: {
295672
+ exhausted: this.options.profile?.bidExhaustionEvidence ?? false,
295673
+ validated: this.options.profile?.exhaustionEvidenceValidated ?? true,
295674
+ source: this.options.profile?.id ?? "broker:conservative"
295675
+ },
295676
+ ask: {
295677
+ exhausted: this.options.profile?.askExhaustionEvidence ?? false,
295678
+ validated: this.options.profile?.exhaustionEvidenceValidated ?? true,
295679
+ source: this.options.profile?.id ?? "broker:conservative"
295680
+ }
295681
+ },
295682
+ measurementBandsBps: getOrderbookMeasurementBandsBps()
295683
+ }
295684
+ }, { sampledOut: !this.#sampler.shouldEmit(receivedTimestamp) });
295414
295685
  this.#recordCounter("public_feed_archive_decisions_total");
295415
295686
  this.options.observer?.archiveDecision?.(this.#observation());
295416
295687
  this.#fanout((subscriber) => this.#frame(projectOrderBookSnapshot(snapshot, subscriber.depthLimit), receivedTimestamp));
@@ -295583,7 +295854,7 @@ class PublicFeedWorker {
295583
295854
  }
295584
295855
  #metricLabels() {
295585
295856
  return {
295586
- exchange: this.options.exchangeName,
295857
+ exchange_bucket: this.options.exchangeOwned ? "dynamic" : "configured",
295587
295858
  feed: this.options.feed,
295588
295859
  market_type: this.options.marketType
295589
295860
  };
@@ -310950,7 +311221,29 @@ async function handleOrderBookCall(ctx) {
310950
311221
  assetType: "spot",
310951
311222
  accountSelector: ctx.selectedBrokerAccount?.label,
310952
311223
  deploymentId: ctx.brokerArchiver?.getDeploymentId() ?? "unarchived",
310953
- snapshot
311224
+ snapshot,
311225
+ archiveMetadata: {
311226
+ captureProfileId: `${orderBookPayload.exchange.trim().toLowerCase()}:current-snapshot:requested:${orderBookPayload.depthLimit}`,
311227
+ effectiveCadenceMs: 1,
311228
+ requestedUpstreamDepth: orderBookPayload.depthLimit,
311229
+ observedBidCount: snapshot.bids.length,
311230
+ observedAskCount: snapshot.asks.length,
311231
+ observedFarthestBid: snapshot.bids.at(-1)?.[0] ?? Number.NaN,
311232
+ observedFarthestAsk: snapshot.asks.at(-1)?.[0] ?? Number.NaN,
311233
+ exhaustionEvidence: {
311234
+ bid: {
311235
+ exhausted: false,
311236
+ validated: true,
311237
+ source: "broker:current-snapshot"
311238
+ },
311239
+ ask: {
311240
+ exhausted: false,
311241
+ validated: true,
311242
+ source: "broker:current-snapshot"
311243
+ }
311244
+ },
311245
+ measurementBandsBps: getOrderbookMeasurementBandsBps()
311246
+ }
310954
311247
  }, {
310955
311248
  sourceMode: "broker_current_snapshot_v1",
310956
311249
  depthLimit: orderBookPayload.depthLimit
@@ -313539,4 +313832,4 @@ export {
313539
313832
  CEXBroker as default
313540
313833
  };
313541
313834
 
313542
- //# debugId=72C8C3614857C3F664756E2164756E21
313835
+ //# debugId=46EFCE207D029E0F64756E2164756E21