@camstack/addon-pipeline 1.2.137 → 1.2.138

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 (38) hide show
  1. package/dist/audio-analyzer/index.js +5 -5
  2. package/dist/audio-analyzer/index.mjs +3 -3
  3. package/dist/detection-pipeline/index.js +12 -12
  4. package/dist/detection-pipeline/index.mjs +5 -5
  5. package/dist/{dist-4EMKvxCp.js → dist-BuIP0499.js} +40 -0
  6. package/dist/{dist-g0Or5_pR.mjs → dist-CmEYRK7G.mjs} +35 -1
  7. package/dist/{event-loop-stall-monitor-DDm07Ei6.js → event-loop-stall-monitor-Bef2jXMX.js} +1 -1
  8. package/dist/{event-loop-stall-monitor-CskL9Lgu.mjs → event-loop-stall-monitor-JGTFb0Uv.mjs} +1 -1
  9. package/dist/{lazy-sharp-BlA9PxWk.js → lazy-sharp-DH2eVehm.js} +1 -1
  10. package/dist/motion-wasm/index.js +2 -2
  11. package/dist/motion-wasm/index.mjs +1 -1
  12. package/dist/{node-BOHn8gpk.js → node-ChdX9lv7.js} +1 -1
  13. package/dist/{node-Bo1g8hLO.mjs → node-J07GBWT3.mjs} +1 -1
  14. package/dist/pipeline-runner/index.js +55 -12
  15. package/dist/pipeline-runner/index.mjs +54 -11
  16. package/dist/{process-memory-C3084DOt.js → process-memory-CJoZemF4.js} +1 -1
  17. package/dist/{process-memory-DmrHWybb.mjs → process-memory-DAKxUb9d.mjs} +1 -1
  18. package/dist/recorder/index.js +6 -6
  19. package/dist/recorder/index.mjs +3 -3
  20. package/dist/{segment-demux-js-BrQ_A0oi.js → segment-demux-js-BgXbXZnp.js} +1 -1
  21. package/dist/{segment-demux-js-C-a2pghM.mjs → segment-demux-js-Ck9ly4bX.mjs} +1 -1
  22. package/dist/session-decode/decode-worker-child.js +115 -5
  23. package/dist/session-decode/decode-worker-child.mjs +114 -4
  24. package/dist/stream-broker/_stub.js +1 -1
  25. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-AH6OJ3hJ.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-Cad8960O.mjs} +3 -3
  26. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-xdmO8wYp.mjs +26 -0
  27. package/dist/stream-broker/demux-worker-child.js +1 -1
  28. package/dist/stream-broker/demux-worker-child.mjs +1 -1
  29. package/dist/stream-broker/{hostInit-XNyn-FTM.mjs → hostInit-Gd3OcDIa.mjs} +3 -3
  30. package/dist/stream-broker/index.js +160 -23
  31. package/dist/stream-broker/index.mjs +160 -23
  32. package/dist/stream-broker/remoteEntry.js +1 -1
  33. package/dist/{worker-protocol-BLfaD5uC.js → worker-protocol-Bpz62eyB.js} +2 -1
  34. package/dist/{worker-protocol-vc8WWhjx.mjs → worker-protocol-wMS29PG9.mjs} +2 -1
  35. package/package.json +5 -3
  36. package/dist/addon-utils-C6b5Tnia.js +0 -625
  37. package/dist/addon-utils-C8KTuPdE.mjs +0 -583
  38. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CQyiEd0l.mjs +0 -26
@@ -2,13 +2,13 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-4EMKvxCp.js");
6
- const require_process_memory = require("../process-memory-C3084DOt.js");
7
- const require_addon_utils = require("../addon-utils-C6b5Tnia.js");
5
+ const require_dist = require("../dist-BuIP0499.js");
6
+ const require_process_memory = require("../process-memory-CJoZemF4.js");
8
7
  let node_fs = require("node:fs");
9
8
  node_fs = require_dist.__toESM(node_fs);
10
9
  let node_path = require("node:path");
11
10
  node_path = require_dist.__toESM(node_path);
11
+ let _camstack_system_addon_utils = require("@camstack/system/addon-utils");
12
12
  //#region src/audio-analyzer/audio-pipeline.ts
13
13
  /**
14
14
  * Create the appropriate audio pipeline.
@@ -83,7 +83,7 @@ var YamnetPythonPipeline = class {
83
83
  url: YAMNET_MODEL_URL,
84
84
  dest: modelPath
85
85
  } });
86
- await require_addon_utils.downloadFile(YAMNET_MODEL_URL, modelPath);
86
+ await (0, _camstack_system_addon_utils.downloadFile)(YAMNET_MODEL_URL, modelPath);
87
87
  this.log.info("YAMNet ONNX model downloaded", { meta: { sizeBytes: node_fs.statSync(modelPath).size } });
88
88
  }
89
89
  if (!node_fs.existsSync(labelsPath)) {
@@ -91,7 +91,7 @@ var YamnetPythonPipeline = class {
91
91
  url: YAMNET_LABELS_URL,
92
92
  dest: labelsPath
93
93
  } });
94
- await require_addon_utils.downloadFile(YAMNET_LABELS_URL, labelsPath);
94
+ await (0, _camstack_system_addon_utils.downloadFile)(YAMNET_LABELS_URL, labelsPath);
95
95
  }
96
96
  const pythonDir = resolveAudioPythonDir();
97
97
  if (this.installPythonRequirements) await this.installPythonRequirements(node_path.join(pythonDir, "requirements-audio.txt"));
@@ -1,9 +1,9 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { A as audioAnalysisCapability, Ct as errMsg, Pt as hydrateSchema, S as PoolMemoryWatchdog, gt as resolvePoolMemoryPolicy, j as audioAnalyzerCapability, kt as BaseAddon, n as AUDIO_BACKEND_CHOICES, s as DEFAULT_AUDIO_ANALYZER_CONFIG, tt as mapAudioLabelToMacro, v as HF_BASE_URL } from "../dist-g0Or5_pR.mjs";
3
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-DmrHWybb.mjs";
4
- import { i as downloadFile } from "../addon-utils-C8KTuPdE.mjs";
2
+ import { A as audioAnalysisCapability, At as BaseAddon, Ct as errMsg, Ft as hydrateSchema, S as PoolMemoryWatchdog, gt as resolvePoolMemoryPolicy, j as audioAnalyzerCapability, n as AUDIO_BACKEND_CHOICES, s as DEFAULT_AUDIO_ANALYZER_CONFIG, tt as mapAudioLabelToMacro, v as HF_BASE_URL } from "../dist-CmEYRK7G.mjs";
3
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-DAKxUb9d.mjs";
5
4
  import * as fs from "node:fs";
6
5
  import * as path$1 from "node:path";
6
+ import { downloadFile } from "@camstack/system/addon-utils";
7
7
  //#region src/audio-analyzer/audio-pipeline.ts
8
8
  /**
9
9
  * Create the appropriate audio pipeline.
@@ -2,12 +2,11 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-4EMKvxCp.js");
6
- const require_node = require("../node-BOHn8gpk.js");
7
- const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-DDm07Ei6.js");
8
- const require_lazy_sharp = require("../lazy-sharp-BlA9PxWk.js");
9
- const require_process_memory = require("../process-memory-C3084DOt.js");
10
- const require_addon_utils = require("../addon-utils-C6b5Tnia.js");
5
+ const require_dist = require("../dist-BuIP0499.js");
6
+ const require_node = require("../node-ChdX9lv7.js");
7
+ const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-Bef2jXMX.js");
8
+ const require_lazy_sharp = require("../lazy-sharp-DH2eVehm.js");
9
+ const require_process_memory = require("../process-memory-CJoZemF4.js");
11
10
  let node_fs = require("node:fs");
12
11
  node_fs = require_dist.__toESM(node_fs);
13
12
  let node_path = require("node:path");
@@ -17,6 +16,7 @@ let sharp = require("sharp");
17
16
  sharp = require_dist.__toESM(sharp);
18
17
  let node_os = require("node:os");
19
18
  node_os = require_dist.__toESM(node_os);
19
+ let _camstack_system_addon_utils = require("@camstack/system/addon-utils");
20
20
  //#region src/detection-pipeline/runtimes.ts
21
21
  var KNOWN_PLATFORMS = [
22
22
  "darwin",
@@ -6898,7 +6898,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
6898
6898
  if (!step.enabled) continue;
6899
6899
  const modelEntry = await this.resolveModelEntry(step.addonId, step.modelId);
6900
6900
  if (!modelEntry) continue;
6901
- if (require_addon_utils.isModelDownloaded(this.modelsDir, modelEntry, format)) continue;
6901
+ if ((0, _camstack_system_addon_utils.isModelDownloaded)(this.modelsDir, modelEntry, format)) continue;
6902
6902
  await this.downloadWithRetry(modelEntry, format, 3);
6903
6903
  }
6904
6904
  }
@@ -7275,7 +7275,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
7275
7275
  const formats = {};
7276
7276
  for (const [formatKey, entry] of Object.entries(m.formats)) {
7277
7277
  if (!entry) continue;
7278
- const downloaded = require_addon_utils.isModelDownloaded(this.modelsDir, m, formatKey);
7278
+ const downloaded = (0, _camstack_system_addon_utils.isModelDownloaded)(this.modelsDir, m, formatKey);
7279
7279
  formats[formatKey] = {
7280
7280
  url: entry.url,
7281
7281
  sizeMB: entry.sizeMB,
@@ -7398,7 +7398,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
7398
7398
  const { modelId, format, addonId } = input;
7399
7399
  const modelEntry = await this.resolveModelEntry(addonId, modelId);
7400
7400
  if (!modelEntry) throw new Error(`Model "${modelId}" not found in step "${addonId}" catalog`);
7401
- if (!require_addon_utils.deleteModelFromDisk(this.modelsDir, modelEntry, format)) throw new Error(`Model "${modelId}" (${format}) is not downloaded — nothing to delete`);
7401
+ if (!(0, _camstack_system_addon_utils.deleteModelFromDisk)(this.modelsDir, modelEntry, format)) throw new Error(`Model "${modelId}" (${format}) is not downloaded — nothing to delete`);
7402
7402
  this.log.info("Model deleted from disk", { meta: {
7403
7403
  modelId,
7404
7404
  format
@@ -8215,7 +8215,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
8215
8215
  const work = (async () => {
8216
8216
  for (const step of needed) {
8217
8217
  const modelEntry = await this.resolveModelEntry(step.addonId, step.modelId);
8218
- if (modelEntry && !require_addon_utils.isModelDownloaded(this.modelsDir, modelEntry, format)) {
8218
+ if (modelEntry && !(0, _camstack_system_addon_utils.isModelDownloaded)(this.modelsDir, modelEntry, format)) {
8219
8219
  if (modelEntry.formats[format] === void 0) throw new Error(`Model "${modelEntry.id}" has no ${format} format build (available: ${Object.keys(modelEntry.formats).join(", ") || "none"}) — not retrying a permanent format mismatch`);
8220
8220
  if (modelEntry.formats[format]?.url.startsWith("camstack-local://") === true) throw new Error(`Custom model "${modelEntry.id}" (${format}) is not present in this node's models directory — distribute it to this node from Model Studio before selecting it here`);
8221
8221
  this.log.info("Downloading model for step", { meta: {
@@ -8242,7 +8242,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
8242
8242
  /** Download a model with retry + exponential backoff */
8243
8243
  async downloadWithRetry(entry, format, maxRetries, onProgress) {
8244
8244
  for (let attempt = 1; attempt <= maxRetries; attempt++) try {
8245
- await require_addon_utils.ensureModel(this.modelsDir, entry, format, onProgress);
8245
+ await (0, _camstack_system_addon_utils.ensureModel)(this.modelsDir, entry, format, onProgress);
8246
8246
  this.log.info("Model downloaded successfully", { meta: { modelId: entry.id } });
8247
8247
  return;
8248
8248
  } catch (err) {
@@ -9237,7 +9237,7 @@ function buildSchemaSlots(formats, modelsDir, customByStep) {
9237
9237
  id: m.id,
9238
9238
  name: m.name,
9239
9239
  formats: Object.fromEntries(Object.entries(m.formats).map(([f, entry]) => [f, {
9240
- downloaded: require_addon_utils.isModelDownloaded(modelsDir, m, f),
9240
+ downloaded: (0, _camstack_system_addon_utils.isModelDownloaded)(modelsDir, m, f),
9241
9241
  sizeMB: entry.sizeMB
9242
9242
  }])),
9243
9243
  ...m.group ? { group: m.group } : {},
@@ -1,15 +1,15 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { $ as loadContributionCapability, $t as union, Ct as errMsg, Ht as sleep, Nt as createEvent, O as YAMNET_TO_MACRO, Pt as hydrateSchema, Qt as string, Rt as nodePin, S as PoolMemoryWatchdog, W as detectionPipelineCapability, Wt as array, Xt as object, Y as evaluateZoneRules, Z as inferModelProvider, c as DEFAULT_CLUSTER_STEP_MODELS, en as EventCategory, gt as resolvePoolMemoryPolicy, it as overlayClusterStepSettings, kt as BaseAddon, l as DEFAULT_CLUSTER_STEP_SETTINGS, m as DEVICE_BACKEND_TO_FORMAT, mt as resolveClusterStepModelId, ot as pickClusterStepModels, q as enumerateInferenceDevices, st as pickClusterStepSettings, t as APPLE_SA_TO_MACRO, ut as pipelineExecutorCapability, vt as runtimeDevices$1, xt as supportedRuntimes$1, z as defaultDeviceFor$1, zt as parseJsonUnknown } from "../dist-g0Or5_pR.mjs";
3
- import { a as readProcessCost } from "../node-Bo1g8hLO.mjs";
4
- import { a as ALL_PIPELINE_STEPS, c as getDefaultModelForFormatFromDef, d as resolveModelForFormat, f as landmarkPrecisionVerdict, l as getStep, n as startEventLoopStallMonitor, o as ALL_STEPS, r as localFrameRegistry, s as getDefaultModelForFormat, u as getStepDefinition } from "../event-loop-stall-monitor-CskL9Lgu.mjs";
2
+ import { $ as loadContributionCapability, $t as string, At as BaseAddon, Bt as parseJsonUnknown, Ct as errMsg, Ft as hydrateSchema, Gt as array, O as YAMNET_TO_MACRO, Pt as createEvent, S as PoolMemoryWatchdog, Ut as sleep, W as detectionPipelineCapability, Y as evaluateZoneRules, Z as inferModelProvider, Zt as object, c as DEFAULT_CLUSTER_STEP_MODELS, en as union, gt as resolvePoolMemoryPolicy, it as overlayClusterStepSettings, l as DEFAULT_CLUSTER_STEP_SETTINGS, m as DEVICE_BACKEND_TO_FORMAT, mt as resolveClusterStepModelId, ot as pickClusterStepModels, q as enumerateInferenceDevices, st as pickClusterStepSettings, t as APPLE_SA_TO_MACRO, tn as EventCategory, ut as pipelineExecutorCapability, vt as runtimeDevices$1, xt as supportedRuntimes$1, z as defaultDeviceFor$1, zt as nodePin } from "../dist-CmEYRK7G.mjs";
3
+ import { a as readProcessCost } from "../node-J07GBWT3.mjs";
4
+ import { a as ALL_PIPELINE_STEPS, c as getDefaultModelForFormatFromDef, d as resolveModelForFormat, f as landmarkPrecisionVerdict, l as getStep, n as startEventLoopStallMonitor, o as ALL_STEPS, r as localFrameRegistry, s as getDefaultModelForFormat, u as getStepDefinition } from "../event-loop-stall-monitor-JGTFb0Uv.mjs";
5
5
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
6
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-DmrHWybb.mjs";
7
- import { a as ensureModel, o as isModelDownloaded, r as deleteModelFromDisk } from "../addon-utils-C8KTuPdE.mjs";
6
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-DAKxUb9d.mjs";
8
7
  import * as fs from "node:fs";
9
8
  import * as path$1 from "node:path";
10
9
  import { spawn } from "node:child_process";
11
10
  import sharp from "sharp";
12
11
  import * as os from "node:os";
12
+ import { deleteModelFromDisk, ensureModel, isModelDownloaded } from "@camstack/system/addon-utils";
13
13
  //#region src/detection-pipeline/runtimes.ts
14
14
  var KNOWN_PLATFORMS = [
15
15
  "darwin",
@@ -7196,6 +7196,40 @@ method(object({ deviceId: number() }), array(StreamSourceEntrySchema)), method(o
7196
7196
  input: unknown()
7197
7197
  }), unknown(), { kind: "mutation" }), method(object({ deviceId: number() }), _void(), { kind: "mutation" }), method(object({ deviceId: number() }), unknown().nullable()), method(object({ deviceId: number() }), RawStateResultSchema.nullable(), { auth: "protected" });
7198
7198
  /**
7199
+ * The ONE retry schedule for work that can fail simply because the node was
7200
+ * still booting.
7201
+ *
7202
+ * The measured failure (docs/design/boot-to-usable-camera.md, item E): a hub
7203
+ * boot that serialised its addon graph starved every driver dial on it. Fifteen
7204
+ * Hikvision devices logged `Initial probe did not complete — scheduling retry
7205
+ * chain {firstRetryMs=300000}` and then sat unprobed for five minutes, long
7206
+ * after the condition that caused the failure had gone. The Tailscale addon's
7207
+ * auto-rejoin carried a byte-identical schedule, armed from `initialize()`, for
7208
+ * the same reason.
7209
+ *
7210
+ * The shape that fixes it: **two cheap attempts first, then the long tail.**
7211
+ *
7212
+ * - 15 s / 60 s — the boot window. Anything that failed because the node was
7213
+ * busy is recovered here, before an operator can open the UI and see a
7214
+ * camera that is wrong about itself.
7215
+ * - 5 m → 90 m — the genuinely-offline case. A battery cam that is asleep, a
7216
+ * VLAN that is down, a peer that has not come back. Unchanged in intent from
7217
+ * the schedule this replaces (~3 h 30 m of coverage): here ~3 h 21 m, then
7218
+ * the chain ends and manual re-arm (reprobe / restart) is the only path.
7219
+ *
7220
+ * Bounded on purpose — see D6. A chain that never gives up is a busy loop with
7221
+ * extra steps.
7222
+ */
7223
+ var BOOT_RECOVERY_BACKOFF_MS = [
7224
+ 15e3,
7225
+ 6e4,
7226
+ 5 * 6e4,
7227
+ 15 * 6e4,
7228
+ 30 * 6e4,
7229
+ 60 * 6e4,
7230
+ 90 * 6e4
7231
+ ];
7232
+ /**
7199
7233
  * Type-safe JSON parsing helpers.
7200
7234
  *
7201
7235
  * `JSON.parse` is typed as `any` in lib.es5.d.ts, which triggers
@@ -39758,6 +39792,12 @@ Object.defineProperty(exports, "AUDIO_PRESETS", {
39758
39792
  return AUDIO_PRESETS;
39759
39793
  }
39760
39794
  });
39795
+ Object.defineProperty(exports, "BOOT_RECOVERY_BACKOFF_MS", {
39796
+ enumerable: true,
39797
+ get: function() {
39798
+ return BOOT_RECOVERY_BACKOFF_MS;
39799
+ }
39800
+ });
39761
39801
  Object.defineProperty(exports, "BaseAddon", {
39762
39802
  enumerable: true,
39763
39803
  get: function() {
@@ -7173,6 +7173,40 @@ method(object({ deviceId: number() }), array(StreamSourceEntrySchema)), method(o
7173
7173
  input: unknown()
7174
7174
  }), unknown(), { kind: "mutation" }), method(object({ deviceId: number() }), _void(), { kind: "mutation" }), method(object({ deviceId: number() }), unknown().nullable()), method(object({ deviceId: number() }), RawStateResultSchema.nullable(), { auth: "protected" });
7175
7175
  /**
7176
+ * The ONE retry schedule for work that can fail simply because the node was
7177
+ * still booting.
7178
+ *
7179
+ * The measured failure (docs/design/boot-to-usable-camera.md, item E): a hub
7180
+ * boot that serialised its addon graph starved every driver dial on it. Fifteen
7181
+ * Hikvision devices logged `Initial probe did not complete — scheduling retry
7182
+ * chain {firstRetryMs=300000}` and then sat unprobed for five minutes, long
7183
+ * after the condition that caused the failure had gone. The Tailscale addon's
7184
+ * auto-rejoin carried a byte-identical schedule, armed from `initialize()`, for
7185
+ * the same reason.
7186
+ *
7187
+ * The shape that fixes it: **two cheap attempts first, then the long tail.**
7188
+ *
7189
+ * - 15 s / 60 s — the boot window. Anything that failed because the node was
7190
+ * busy is recovered here, before an operator can open the UI and see a
7191
+ * camera that is wrong about itself.
7192
+ * - 5 m → 90 m — the genuinely-offline case. A battery cam that is asleep, a
7193
+ * VLAN that is down, a peer that has not come back. Unchanged in intent from
7194
+ * the schedule this replaces (~3 h 30 m of coverage): here ~3 h 21 m, then
7195
+ * the chain ends and manual re-arm (reprobe / restart) is the only path.
7196
+ *
7197
+ * Bounded on purpose — see D6. A chain that never gives up is a busy loop with
7198
+ * extra steps.
7199
+ */
7200
+ var BOOT_RECOVERY_BACKOFF_MS = [
7201
+ 15e3,
7202
+ 6e4,
7203
+ 5 * 6e4,
7204
+ 15 * 6e4,
7205
+ 30 * 6e4,
7206
+ 60 * 6e4,
7207
+ 90 * 6e4
7208
+ ];
7209
+ /**
7176
7210
  * Type-safe JSON parsing helpers.
7177
7211
  *
7178
7212
  * `JSON.parse` is typed as `any` in lib.es5.d.ts, which triggers
@@ -39711,4 +39745,4 @@ function enumerateInferenceDevices(hw) {
39711
39745
  return out;
39712
39746
  }
39713
39747
  //#endregion
39714
- export { loadContributionCapability as $, union as $t, audioAnalysisCapability as A, CAM_PROFILE_ORDER as At, defineCustomActions as B, parseProfileBrokerId as Bt, RATE_CONTROL_RELAXED as C, errMsg as Ct, RingBuffer as D, invocationFromEncodeProfile as Dt, RecordingConfigSchema as E, buildFfmpegArgs as Et, createHwAccelCache as F, isEvent as Ft, egressTranscodeSharingKey as G, boolean as Gt, deriveDetailCropRect as H, sleep as Ht, createLogChannelsProvider as I, makeProfileBrokerId as It, evaluateSensorEdge as J, literal as Jt, egressTransportFromRequest as K, discriminatedUnion as Kt, customAction as L, makeSourceBrokerId as Lt, audioKindId as M, DeviceType as Mt, batteryCapability as N, createEvent as Nt, YAMNET_TO_MACRO as O, isSoftwareDecode as Ot, cameraStreamsCapability as P, hydrateSchema as Pt, isFirstLevelMacroClass as Q, string as Qt, declareLogChannel as R, nodePin as Rt, PoolMemoryWatchdog as S, webrtcSessionCapability as St, RECORDING_EXPORT_MAX_READ_BYTES as T, Fmp4BoxSplitter as Tt, deriveRecordingMode as U, _enum as Ut, deriveBatteryPresence as V, selectAssignedProfileSlots as Vt, detectionPipelineCapability as W, array as Wt, hfModelUrl as X, object as Xt, evaluateZoneRules as Y, number as Yt, inferModelProvider as Z, record as Zt, ExportRecordSchema as _, resolveRecordingProfiles as _t, COCO_80_LABELS as a, parseProcStatus as at, NativeLeaseSettingsSchema as b, streamBrokerCapability as bt, DEFAULT_CLUSTER_STEP_MODELS as c, pickDetailCropConvention as ct, DEFAULT_EVENTS_BAND_BUFFER_SEC as d, pipelineRunnerCapability as dt, EventCategory as en, logChannelsCapability as et, DEFAULT_FIRST_SIGHTING_FRESHNESS_MS as f, recordingCapability as ft, EncodeProfileSchema as g, resolvePoolMemoryPolicy as gt, EVENT_PAD_MS as h, resolveEgressDecodeHwAccel as ht, BatteryStatusSchema as i, overlayClusterStepSettings as it, audioAnalyzerCapability as j, DeviceFeature as jt, addonWidgetsSourceCapability as k, BaseAddon as kt, DEFAULT_CLUSTER_STEP_SETTINGS as l, pickNativeLeaseOverride as lt, DEVICE_BACKEND_TO_FORMAT as m, resolveClusterStepModelId as mt, AUDIO_BACKEND_CHOICES as n, maskUrlCredentials as nt, COCO_TO_MACRO as o, pickClusterStepModels as ot, DEFAULT_NATIVE_LEASE_SETTINGS as p, recordingExportCapability as pt, enumerateInferenceDevices as q, lazy as qt, AUDIO_MACRO_LABELS as r, motionDetectionCapability as rt, DEFAULT_AUDIO_ANALYZER_CONFIG as s, pickClusterStepSettings as st, APPLE_SA_TO_MACRO as t, mapAudioLabelToMacro as tt, DEFAULT_DETAIL_CROP_CONVENTION as u, pipelineExecutorCapability as ut, HF_BASE_URL as v, runtimeDevices as vt, RATE_CONTROL_TIGHT as w, AUDIO_PRESETS as wt, OpsLogEntrySchema as x, supportedRuntimes as xt, NativeLeaseAdmissionSchema as y, storageEvictableCapability as yt, defaultDeviceFor as z, parseJsonUnknown as zt };
39748
+ export { loadContributionCapability as $, string as $t, audioAnalysisCapability as A, BaseAddon as At, defineCustomActions as B, parseJsonUnknown as Bt, RATE_CONTROL_RELAXED as C, errMsg as Ct, RingBuffer as D, invocationFromEncodeProfile as Dt, RecordingConfigSchema as E, buildFfmpegArgs as Et, createHwAccelCache as F, hydrateSchema as Ft, egressTranscodeSharingKey as G, array as Gt, deriveDetailCropRect as H, selectAssignedProfileSlots as Ht, createLogChannelsProvider as I, isEvent as It, evaluateSensorEdge as J, lazy as Jt, egressTransportFromRequest as K, boolean as Kt, customAction as L, makeProfileBrokerId as Lt, audioKindId as M, DeviceFeature as Mt, batteryCapability as N, DeviceType as Nt, YAMNET_TO_MACRO as O, isSoftwareDecode as Ot, cameraStreamsCapability as P, createEvent as Pt, isFirstLevelMacroClass as Q, record as Qt, declareLogChannel as R, makeSourceBrokerId as Rt, PoolMemoryWatchdog as S, webrtcSessionCapability as St, RECORDING_EXPORT_MAX_READ_BYTES as T, Fmp4BoxSplitter as Tt, deriveRecordingMode as U, sleep as Ut, deriveBatteryPresence as V, parseProfileBrokerId as Vt, detectionPipelineCapability as W, _enum as Wt, hfModelUrl as X, number as Xt, evaluateZoneRules as Y, literal as Yt, inferModelProvider as Z, object as Zt, ExportRecordSchema as _, resolveRecordingProfiles as _t, COCO_80_LABELS as a, parseProcStatus as at, NativeLeaseSettingsSchema as b, streamBrokerCapability as bt, DEFAULT_CLUSTER_STEP_MODELS as c, pickDetailCropConvention as ct, DEFAULT_EVENTS_BAND_BUFFER_SEC as d, pipelineRunnerCapability as dt, union as en, logChannelsCapability as et, DEFAULT_FIRST_SIGHTING_FRESHNESS_MS as f, recordingCapability as ft, EncodeProfileSchema as g, resolvePoolMemoryPolicy as gt, EVENT_PAD_MS as h, resolveEgressDecodeHwAccel as ht, BatteryStatusSchema as i, overlayClusterStepSettings as it, audioAnalyzerCapability as j, CAM_PROFILE_ORDER as jt, addonWidgetsSourceCapability as k, BOOT_RECOVERY_BACKOFF_MS as kt, DEFAULT_CLUSTER_STEP_SETTINGS as l, pickNativeLeaseOverride as lt, DEVICE_BACKEND_TO_FORMAT as m, resolveClusterStepModelId as mt, AUDIO_BACKEND_CHOICES as n, maskUrlCredentials as nt, COCO_TO_MACRO as o, pickClusterStepModels as ot, DEFAULT_NATIVE_LEASE_SETTINGS as p, recordingExportCapability as pt, enumerateInferenceDevices as q, discriminatedUnion as qt, AUDIO_MACRO_LABELS as r, motionDetectionCapability as rt, DEFAULT_AUDIO_ANALYZER_CONFIG as s, pickClusterStepSettings as st, APPLE_SA_TO_MACRO as t, EventCategory as tn, mapAudioLabelToMacro as tt, DEFAULT_DETAIL_CROP_CONVENTION as u, pipelineExecutorCapability as ut, HF_BASE_URL as v, runtimeDevices as vt, RATE_CONTROL_TIGHT as w, AUDIO_PRESETS as wt, OpsLogEntrySchema as x, supportedRuntimes as xt, NativeLeaseAdmissionSchema as y, storageEvictableCapability as yt, defaultDeviceFor as z, nodePin as zt };
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-4EMKvxCp.js");
1
+ const require_dist = require("./dist-BuIP0499.js");
2
2
  let node_crypto = require("node:crypto");
3
3
  let node_perf_hooks = require("node:perf_hooks");
4
4
  //#region src/detection-pipeline/registry/model-catalogs.ts
@@ -1,4 +1,4 @@
1
- import { M as audioKindId, X as hfModelUrl, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS } from "./dist-g0Or5_pR.mjs";
1
+ import { M as audioKindId, X as hfModelUrl, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS } from "./dist-CmEYRK7G.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { PerformanceObserver } from "node:perf_hooks";
4
4
  //#region src/detection-pipeline/registry/model-catalogs.ts
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-4EMKvxCp.js");
1
+ const require_dist = require("./dist-BuIP0499.js");
2
2
  let node_path = require("node:path");
3
3
  node_path = require_dist.__toESM(node_path);
4
4
  let node_url = require("node:url");
@@ -2,8 +2,8 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-4EMKvxCp.js");
6
- const require_lazy_sharp = require("../lazy-sharp-BlA9PxWk.js");
5
+ const require_dist = require("../dist-BuIP0499.js");
6
+ const require_lazy_sharp = require("../lazy-sharp-DH2eVehm.js");
7
7
  let node_fs = require("node:fs");
8
8
  let node_path = require("node:path");
9
9
  //#region src/motion-wasm/wasm-motion-detector.ts
@@ -1,4 +1,4 @@
1
- import { Mt as DeviceType, Pt as hydrateSchema, Y as evaluateZoneRules, kt as BaseAddon, rt as motionDetectionCapability } from "../dist-g0Or5_pR.mjs";
1
+ import { At as BaseAddon, Ft as hydrateSchema, Nt as DeviceType, Y as evaluateZoneRules, rt as motionDetectionCapability } from "../dist-CmEYRK7G.mjs";
2
2
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
3
3
  import { readFileSync } from "node:fs";
4
4
  import { join } from "node:path";
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-4EMKvxCp.js");
1
+ const require_dist = require("./dist-BuIP0499.js");
2
2
  let node_crypto = require("node:crypto");
3
3
  let node_fs = require("node:fs");
4
4
  node_fs = require_dist.__toESM(node_fs, 1);
@@ -1,4 +1,4 @@
1
- import { Ct as errMsg, Et as buildFfmpegArgs, Ot as isSoftwareDecode, Tt as Fmp4BoxSplitter } from "./dist-g0Or5_pR.mjs";
1
+ import { Ct as errMsg, Et as buildFfmpegArgs, Ot as isSoftwareDecode, Tt as Fmp4BoxSplitter } from "./dist-CmEYRK7G.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import "node:fs";
4
4
  import "node:path";
@@ -2,12 +2,12 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-4EMKvxCp.js");
6
- const require_node = require("../node-BOHn8gpk.js");
7
- const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-DDm07Ei6.js");
8
- const require_worker_protocol = require("../worker-protocol-BLfaD5uC.js");
5
+ const require_dist = require("../dist-BuIP0499.js");
6
+ const require_node = require("../node-ChdX9lv7.js");
7
+ const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-Bef2jXMX.js");
8
+ const require_worker_protocol = require("../worker-protocol-Bpz62eyB.js");
9
9
  const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
10
- const require_lazy_sharp = require("../lazy-sharp-BlA9PxWk.js");
10
+ const require_lazy_sharp = require("../lazy-sharp-DH2eVehm.js");
11
11
  const require_restream_intent = require("../restream-intent-Cv9x3jmu.js");
12
12
  const require_remote_restream = require("../remote-restream-CO36Sr30.js");
13
13
  let node_child_process = require("node:child_process");
@@ -891,10 +891,29 @@ var DEFAULT_FIRST_FRAME_TIMEOUT_MS = 2e4;
891
891
  *
892
892
  * The first decodable frame is not a fixed cost: it is one IDR interval plus
893
893
  * every GOP the decoder has to discard. Measured on device 618 (2560x1440
894
- * h264, 8.0 s IDR interval, `Invalid NAL unit` / `corrupt decoded frame` in its
895
- * bitstream), dial → first decoded frame over the broker's own muted restream
896
- * was 1.8 / 6.5 / 7.0 / 7.2 / 9.2 / 10.0 / 10.8 / 12.9 / 14.9 / 20.0 / 30.3 /
897
- * >40 s across 12 trials — against a healthy 587's 2.0 s ± 0.02.
894
+ * h264, `Invalid NAL unit` / `corrupt decoded frame` in its bitstream), dial →
895
+ * first decoded frame over the broker's own muted restream was 1.8 / 6.5 / 7.0
896
+ * / 7.2 / 9.2 / 10.0 / 10.8 / 12.9 / 14.9 / 20.0 / 30.3 / >40 s across 12
897
+ * trials — against a healthy 587's 2.0 s ± 0.02.
898
+ *
899
+ * **The "8.0 s IDR interval" this used to attribute 618's spread to was wrong,
900
+ * and is corrected here rather than deleted** (2026-08-28): a stated number
901
+ * nobody re-derived reads as verification, and this one was used to argue that
902
+ * 618 was an encoder outlier. The fleet runs 100-frame GOPs at 25 fps — a
903
+ * **4 000 ms** IDR interval — and two independent readings of 6 h of live logs
904
+ * agree with the operator rather than with this docblock. First, the join-burst
905
+ * span logged on `restream prime (lat-probe)` is the time since the last IDR,
906
+ * uniform in `[0, IDR]` and censored at `PRIME_MAX_SPAN_MS`: its median is
907
+ * ~1 000 ms on eleven cameras, which is what `uniform[0, 4000]` conditioned on
908
+ * `≤2000` predicts. Second, `detectionIntentServed` over detection dials puts
909
+ * the SERVED fraction at 44-61 % on the bulk of the fleet, i.e. the ~50 %
910
+ * `P(span > 2000)` a 4 000 ms interval implies. 618 measures 51 %, which is the
911
+ * fleet norm. The genuine long-GOP outlier is **637** at 30 % served (⇒ ~6.7 s).
912
+ *
913
+ * So the spread is not this camera's encoder. It is D57's fixed 2 000 ms bound
914
+ * withholding the join burst WHOLE on roughly half of every 4 s-GOP camera's
915
+ * dials — see `join-burst-bound.ts`, which states the arithmetic, and
916
+ * `docs/architecture/load-ledger.md` (2026-08-28) for the measurement.
898
917
  *
899
918
  * Abandoning at 20 s was therefore not a timeout, it was a coin flip, and the
900
919
  * recovery made it worse: ending the session RE-DIALS, which throws the
@@ -930,6 +949,7 @@ var SessionDecodeSession = class {
930
949
  firstFrameTimeoutMs;
931
950
  frameTimeoutMs;
932
951
  firstFrameMaxWaitMs;
952
+ onDialTiming;
933
953
  pendingPull = null;
934
954
  pendingToBuffers = /* @__PURE__ */ new Map();
935
955
  /** Outstanding `nativeCrop` requests, keyed by the monotonic `requestId`. */
@@ -943,13 +963,14 @@ var SessionDecodeSession = class {
943
963
  firstFrameReceived = false;
944
964
  /** `Date.now()` of the FIRST `pull` — the origin of the cold-start ceiling. */
945
965
  firstPullAt = 0;
946
- constructor(child, logger, deviceId, firstFrameTimeoutMs, frameTimeoutMs, firstFrameMaxWaitMs) {
966
+ constructor(child, logger, deviceId, firstFrameTimeoutMs, frameTimeoutMs, firstFrameMaxWaitMs, onDialTiming) {
947
967
  this.child = child;
948
968
  this.logger = logger;
949
969
  this.deviceId = deviceId;
950
970
  this.firstFrameTimeoutMs = firstFrameTimeoutMs;
951
971
  this.frameTimeoutMs = frameTimeoutMs;
952
972
  this.firstFrameMaxWaitMs = firstFrameMaxWaitMs;
973
+ this.onDialTiming = onDialTiming;
953
974
  this.child.on("message", (m) => this.handleMessage(m));
954
975
  this.child.on("exit", (m) => this.handleExit(toWorkerExitInfo(m)));
955
976
  }
@@ -1125,6 +1146,15 @@ var SessionDecodeSession = class {
1125
1146
  case "log":
1126
1147
  this.logger[raw.level](raw.message);
1127
1148
  return;
1149
+ case "dialTiming":
1150
+ this.onDialTiming?.({
1151
+ hwContextMs: raw.hwContextMs,
1152
+ demuxerOpenMs: raw.demuxerOpenMs,
1153
+ decoderCreateMs: raw.decoderCreateMs,
1154
+ firstDecodeMs: raw.firstDecodeMs,
1155
+ streamInfoProbed: raw.streamInfoProbed
1156
+ });
1157
+ return;
1128
1158
  }
1129
1159
  }
1130
1160
  handleExit(info) {
@@ -1349,7 +1379,7 @@ function createSessionDecodeCoordinator(deps) {
1349
1379
  const frameTimeoutMs = deps.frameTimeoutMs ?? DEFAULT_FRAME_TIMEOUT_MS;
1350
1380
  const firstFrameMaxWaitMs = Math.max(deps.firstFrameMaxWaitMs ?? DEFAULT_FIRST_FRAME_MAX_WAIT_MS, firstFrameTimeoutMs);
1351
1381
  return { async *generateVideoFrames(source, opts) {
1352
- const session = new SessionDecodeSession(deps.fork(source), deps.logger, source.deviceId, firstFrameTimeoutMs, frameTimeoutMs, firstFrameMaxWaitMs);
1382
+ const session = new SessionDecodeSession(deps.fork(source), deps.logger, source.deviceId, firstFrameTimeoutMs, frameTimeoutMs, firstFrameMaxWaitMs, deps.onDialTiming);
1353
1383
  session.start(source, opts);
1354
1384
  try {
1355
1385
  while (true) {
@@ -1403,9 +1433,13 @@ async function toDecodedFrame(frame, format, viewSpec) {
1403
1433
  */
1404
1434
  function startSessionDecodePump(deps) {
1405
1435
  const format = deps.opts.format ?? "rgb";
1436
+ let dialTiming = null;
1406
1437
  const iterator = createSessionDecodeCoordinator({
1407
1438
  fork: deps.fork,
1408
1439
  logger: deps.logger,
1440
+ onDialTiming: (timing) => {
1441
+ dialTiming = timing;
1442
+ },
1409
1443
  ...deps.firstFrameTimeoutMs !== void 0 ? { firstFrameTimeoutMs: deps.firstFrameTimeoutMs } : {},
1410
1444
  ...deps.frameTimeoutMs !== void 0 ? { frameTimeoutMs: deps.frameTimeoutMs } : {}
1411
1445
  }).generateVideoFrames(deps.source, deps.opts);
@@ -1436,9 +1470,11 @@ function startSessionDecodePump(deps) {
1436
1470
  if (!firstFrameSeen) {
1437
1471
  firstFrameSeen = true;
1438
1472
  releaseSpawnSlotOnce();
1473
+ const dial = dialTiming;
1439
1474
  deps.onFirstFrame?.({
1440
1475
  spawnWaitMs: spawnGrantedAt - pumpStartedAt,
1441
- forkToFrameMs: Date.now() - spawnGrantedAt
1476
+ forkToFrameMs: Date.now() - spawnGrantedAt,
1477
+ ...dial !== null ? { dial } : {}
1442
1478
  });
1443
1479
  }
1444
1480
  if (stopped) {
@@ -7346,6 +7382,13 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
7346
7382
  dialMs,
7347
7383
  spawnWaitMs: timing.spawnWaitMs,
7348
7384
  forkToFrameMs: timing.forkToFrameMs,
7385
+ ...timing.dial ? {
7386
+ hwContextMs: timing.dial.hwContextMs,
7387
+ demuxerOpenMs: timing.dial.demuxerOpenMs,
7388
+ decoderCreateMs: timing.dial.decoderCreateMs,
7389
+ firstDecodeMs: timing.dial.firstDecodeMs,
7390
+ streamInfoProbed: timing.dial.streamInfoProbed
7391
+ } : {},
7349
7392
  firstFrameMs: Date.now() - requestedAt,
7350
7393
  ...phaseActiveAt !== void 0 ? { sincePhaseActiveMs: Date.now() - phaseActiveAt } : {}
7351
7394
  }
@@ -1,7 +1,7 @@
1
- import { $ as loadContributionCapability, B as defineCustomActions, Ct as errMsg, Gt as boolean, H as deriveDetailCropRect, Jt as literal, L as customAction, Nt as createEvent, Qt as string, Rt as nodePin, Ut as _enum, Wt as array, Xt as object, Yt as number, ct as pickDetailCropConvention, dt as pipelineRunnerCapability, en as EventCategory, kt as BaseAddon, lt as pickNativeLeaseOverride, m as DEVICE_BACKEND_TO_FORMAT, p as DEFAULT_NATIVE_LEASE_SETTINGS, qt as lazy, u as DEFAULT_DETAIL_CROP_CONVENTION } from "../dist-g0Or5_pR.mjs";
2
- import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-Bo1g8hLO.mjs";
3
- import { i as resolveFrameViewGeometry, r as localFrameRegistry, t as attributeStall, u as getStepDefinition } from "../event-loop-stall-monitor-CskL9Lgu.mjs";
4
- import { a as nativeLeaseSettingEnv, t as isWorkerReply } from "../worker-protocol-vc8WWhjx.mjs";
1
+ import { $ as loadContributionCapability, $t as string, At as BaseAddon, B as defineCustomActions, Ct as errMsg, Gt as array, H as deriveDetailCropRect, Jt as lazy, Kt as boolean, L as customAction, Pt as createEvent, Wt as _enum, Xt as number, Yt as literal, Zt as object, ct as pickDetailCropConvention, dt as pipelineRunnerCapability, lt as pickNativeLeaseOverride, m as DEVICE_BACKEND_TO_FORMAT, p as DEFAULT_NATIVE_LEASE_SETTINGS, tn as EventCategory, u as DEFAULT_DETAIL_CROP_CONVENTION, zt as nodePin } from "../dist-CmEYRK7G.mjs";
2
+ import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-J07GBWT3.mjs";
3
+ import { i as resolveFrameViewGeometry, r as localFrameRegistry, t as attributeStall, u as getStepDefinition } from "../event-loop-stall-monitor-JGTFb0Uv.mjs";
4
+ import { a as nativeLeaseSettingEnv, t as isWorkerReply } from "../worker-protocol-wMS29PG9.mjs";
5
5
  import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
6
6
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
7
7
  import { n as withDetectionIntent } from "../restream-intent-B4BXZra7.mjs";
@@ -885,10 +885,29 @@ var DEFAULT_FIRST_FRAME_TIMEOUT_MS = 2e4;
885
885
  *
886
886
  * The first decodable frame is not a fixed cost: it is one IDR interval plus
887
887
  * every GOP the decoder has to discard. Measured on device 618 (2560x1440
888
- * h264, 8.0 s IDR interval, `Invalid NAL unit` / `corrupt decoded frame` in its
889
- * bitstream), dial → first decoded frame over the broker's own muted restream
890
- * was 1.8 / 6.5 / 7.0 / 7.2 / 9.2 / 10.0 / 10.8 / 12.9 / 14.9 / 20.0 / 30.3 /
891
- * >40 s across 12 trials — against a healthy 587's 2.0 s ± 0.02.
888
+ * h264, `Invalid NAL unit` / `corrupt decoded frame` in its bitstream), dial →
889
+ * first decoded frame over the broker's own muted restream was 1.8 / 6.5 / 7.0
890
+ * / 7.2 / 9.2 / 10.0 / 10.8 / 12.9 / 14.9 / 20.0 / 30.3 / >40 s across 12
891
+ * trials — against a healthy 587's 2.0 s ± 0.02.
892
+ *
893
+ * **The "8.0 s IDR interval" this used to attribute 618's spread to was wrong,
894
+ * and is corrected here rather than deleted** (2026-08-28): a stated number
895
+ * nobody re-derived reads as verification, and this one was used to argue that
896
+ * 618 was an encoder outlier. The fleet runs 100-frame GOPs at 25 fps — a
897
+ * **4 000 ms** IDR interval — and two independent readings of 6 h of live logs
898
+ * agree with the operator rather than with this docblock. First, the join-burst
899
+ * span logged on `restream prime (lat-probe)` is the time since the last IDR,
900
+ * uniform in `[0, IDR]` and censored at `PRIME_MAX_SPAN_MS`: its median is
901
+ * ~1 000 ms on eleven cameras, which is what `uniform[0, 4000]` conditioned on
902
+ * `≤2000` predicts. Second, `detectionIntentServed` over detection dials puts
903
+ * the SERVED fraction at 44-61 % on the bulk of the fleet, i.e. the ~50 %
904
+ * `P(span > 2000)` a 4 000 ms interval implies. 618 measures 51 %, which is the
905
+ * fleet norm. The genuine long-GOP outlier is **637** at 30 % served (⇒ ~6.7 s).
906
+ *
907
+ * So the spread is not this camera's encoder. It is D57's fixed 2 000 ms bound
908
+ * withholding the join burst WHOLE on roughly half of every 4 s-GOP camera's
909
+ * dials — see `join-burst-bound.ts`, which states the arithmetic, and
910
+ * `docs/architecture/load-ledger.md` (2026-08-28) for the measurement.
892
911
  *
893
912
  * Abandoning at 20 s was therefore not a timeout, it was a coin flip, and the
894
913
  * recovery made it worse: ending the session RE-DIALS, which throws the
@@ -924,6 +943,7 @@ var SessionDecodeSession = class {
924
943
  firstFrameTimeoutMs;
925
944
  frameTimeoutMs;
926
945
  firstFrameMaxWaitMs;
946
+ onDialTiming;
927
947
  pendingPull = null;
928
948
  pendingToBuffers = /* @__PURE__ */ new Map();
929
949
  /** Outstanding `nativeCrop` requests, keyed by the monotonic `requestId`. */
@@ -937,13 +957,14 @@ var SessionDecodeSession = class {
937
957
  firstFrameReceived = false;
938
958
  /** `Date.now()` of the FIRST `pull` — the origin of the cold-start ceiling. */
939
959
  firstPullAt = 0;
940
- constructor(child, logger, deviceId, firstFrameTimeoutMs, frameTimeoutMs, firstFrameMaxWaitMs) {
960
+ constructor(child, logger, deviceId, firstFrameTimeoutMs, frameTimeoutMs, firstFrameMaxWaitMs, onDialTiming) {
941
961
  this.child = child;
942
962
  this.logger = logger;
943
963
  this.deviceId = deviceId;
944
964
  this.firstFrameTimeoutMs = firstFrameTimeoutMs;
945
965
  this.frameTimeoutMs = frameTimeoutMs;
946
966
  this.firstFrameMaxWaitMs = firstFrameMaxWaitMs;
967
+ this.onDialTiming = onDialTiming;
947
968
  this.child.on("message", (m) => this.handleMessage(m));
948
969
  this.child.on("exit", (m) => this.handleExit(toWorkerExitInfo(m)));
949
970
  }
@@ -1119,6 +1140,15 @@ var SessionDecodeSession = class {
1119
1140
  case "log":
1120
1141
  this.logger[raw.level](raw.message);
1121
1142
  return;
1143
+ case "dialTiming":
1144
+ this.onDialTiming?.({
1145
+ hwContextMs: raw.hwContextMs,
1146
+ demuxerOpenMs: raw.demuxerOpenMs,
1147
+ decoderCreateMs: raw.decoderCreateMs,
1148
+ firstDecodeMs: raw.firstDecodeMs,
1149
+ streamInfoProbed: raw.streamInfoProbed
1150
+ });
1151
+ return;
1122
1152
  }
1123
1153
  }
1124
1154
  handleExit(info) {
@@ -1343,7 +1373,7 @@ function createSessionDecodeCoordinator(deps) {
1343
1373
  const frameTimeoutMs = deps.frameTimeoutMs ?? DEFAULT_FRAME_TIMEOUT_MS;
1344
1374
  const firstFrameMaxWaitMs = Math.max(deps.firstFrameMaxWaitMs ?? DEFAULT_FIRST_FRAME_MAX_WAIT_MS, firstFrameTimeoutMs);
1345
1375
  return { async *generateVideoFrames(source, opts) {
1346
- const session = new SessionDecodeSession(deps.fork(source), deps.logger, source.deviceId, firstFrameTimeoutMs, frameTimeoutMs, firstFrameMaxWaitMs);
1376
+ const session = new SessionDecodeSession(deps.fork(source), deps.logger, source.deviceId, firstFrameTimeoutMs, frameTimeoutMs, firstFrameMaxWaitMs, deps.onDialTiming);
1347
1377
  session.start(source, opts);
1348
1378
  try {
1349
1379
  while (true) {
@@ -1397,9 +1427,13 @@ async function toDecodedFrame(frame, format, viewSpec) {
1397
1427
  */
1398
1428
  function startSessionDecodePump(deps) {
1399
1429
  const format = deps.opts.format ?? "rgb";
1430
+ let dialTiming = null;
1400
1431
  const iterator = createSessionDecodeCoordinator({
1401
1432
  fork: deps.fork,
1402
1433
  logger: deps.logger,
1434
+ onDialTiming: (timing) => {
1435
+ dialTiming = timing;
1436
+ },
1403
1437
  ...deps.firstFrameTimeoutMs !== void 0 ? { firstFrameTimeoutMs: deps.firstFrameTimeoutMs } : {},
1404
1438
  ...deps.frameTimeoutMs !== void 0 ? { frameTimeoutMs: deps.frameTimeoutMs } : {}
1405
1439
  }).generateVideoFrames(deps.source, deps.opts);
@@ -1430,9 +1464,11 @@ function startSessionDecodePump(deps) {
1430
1464
  if (!firstFrameSeen) {
1431
1465
  firstFrameSeen = true;
1432
1466
  releaseSpawnSlotOnce();
1467
+ const dial = dialTiming;
1433
1468
  deps.onFirstFrame?.({
1434
1469
  spawnWaitMs: spawnGrantedAt - pumpStartedAt,
1435
- forkToFrameMs: Date.now() - spawnGrantedAt
1470
+ forkToFrameMs: Date.now() - spawnGrantedAt,
1471
+ ...dial !== null ? { dial } : {}
1436
1472
  });
1437
1473
  }
1438
1474
  if (stopped) {
@@ -7339,6 +7375,13 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
7339
7375
  dialMs,
7340
7376
  spawnWaitMs: timing.spawnWaitMs,
7341
7377
  forkToFrameMs: timing.forkToFrameMs,
7378
+ ...timing.dial ? {
7379
+ hwContextMs: timing.dial.hwContextMs,
7380
+ demuxerOpenMs: timing.dial.demuxerOpenMs,
7381
+ decoderCreateMs: timing.dial.decoderCreateMs,
7382
+ firstDecodeMs: timing.dial.firstDecodeMs,
7383
+ streamInfoProbed: timing.dial.streamInfoProbed
7384
+ } : {},
7342
7385
  firstFrameMs: Date.now() - requestedAt,
7343
7386
  ...phaseActiveAt !== void 0 ? { sincePhaseActiveMs: Date.now() - phaseActiveAt } : {}
7344
7387
  }
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-4EMKvxCp.js");
1
+ const require_dist = require("./dist-BuIP0499.js");
2
2
  let node_fs = require("node:fs");
3
3
  node_fs = require_dist.__toESM(node_fs);
4
4
  let node_child_process = require("node:child_process");
@@ -1,4 +1,4 @@
1
- import { at as parseProcStatus } from "./dist-g0Or5_pR.mjs";
1
+ import { at as parseProcStatus } from "./dist-CmEYRK7G.mjs";
2
2
  import * as fs from "node:fs";
3
3
  import { execFile } from "node:child_process";
4
4
  //#region src/shared/node-topology-platform.ts