@camstack/addon-pipeline-orchestrator 1.2.207 → 1.2.208

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.
package/dist/index.mjs CHANGED
@@ -5363,7 +5363,7 @@ var ZodIssueCode = {
5363
5363
  var ZodFirstPartyTypeKind;
5364
5364
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5365
5365
  //#endregion
5366
- //#region ../types/dist/sleep-e0RweZzn.mjs
5366
+ //#region ../types/dist/sleep-BDR76Ykr.mjs
5367
5367
  /**
5368
5368
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5369
5369
  * window to float samples (D455).
@@ -7901,7 +7901,7 @@ import { errMsg } from '@camstack/types'
7901
7901
  * Extract a human-readable message from an unknown error value.
7902
7902
  * Replaces the ubiquitous `errMsg(err)` pattern.
7903
7903
  */
7904
- function errMsg(err) {
7904
+ function errMsg$1(err) {
7905
7905
  if (err instanceof Error) return err.message;
7906
7906
  if (typeof err === "string") return err;
7907
7907
  return String(err);
@@ -18761,6 +18761,48 @@ var NcAlarmConfigSchema = object({
18761
18761
  settings: NcAlarmSettingsSchema,
18762
18762
  coverage: array(NcAlarmModeCoverageSchema)
18763
18763
  });
18764
+ /**
18765
+ * ONE rule's demand on ONE camera's clip ring.
18766
+ *
18767
+ * A rule, not a camera: the broker takes the MAX over the asks that reach a
18768
+ * camera, so the answer stays a faithful description of the rules and the
18769
+ * bounding (the byte budget, the broker's own ceiling) stays where the cost
18770
+ * lives. A camera that appears in no ask is being told **nothing** — which is
18771
+ * a different thing from never having been told, and only the envelope
18772
+ * (`rulesLoaded`) can tell those apart.
18773
+ */
18774
+ var NcClipRetentionAskSchema = object({
18775
+ /**
18776
+ * The camera this ask is about. **Absent = every camera**, which is what a
18777
+ * rule with no `conditions.devices` means: it can fire anywhere, so it is
18778
+ * asking everywhere.
18779
+ */
18780
+ deviceId: number().int().nonnegative().optional(),
18781
+ /** Seconds of history the rule needs held for it. Never zero — a rule that
18782
+ * needs nothing produces no ask at all. */
18783
+ seconds: number().min(0).max(60),
18784
+ /** The profile the rule cuts from, when it named one. Absent = the cheapest
18785
+ * assigned, which is what the cut defaults to. */
18786
+ profile: CamProfileSchema.optional(),
18787
+ /** Who is asking — so a retention the operator did not expect names a rule. */
18788
+ ruleId: string(),
18789
+ ruleName: string(),
18790
+ /** Why this many seconds: the rule's own window, or the occupancy ceiling. */
18791
+ reason: _enum(["window", "occupancy"])
18792
+ });
18793
+ /**
18794
+ * The whole answer, with the one bit that keeps absence from reading as zero.
18795
+ *
18796
+ * `rulesLoaded` is false until the rule ledger has completed a load at least
18797
+ * once. A centre that is up but has not read its rules yet answers with an
18798
+ * empty ask list that means nothing at all — applying it would drop every
18799
+ * camera's ring to zero for the first events after a restart, which is the
18800
+ * footage this mechanism exists to keep.
18801
+ */
18802
+ var NcClipRetentionPlanSchema = object({
18803
+ rulesLoaded: boolean(),
18804
+ asks: array(NcClipRetentionAskSchema).readonly()
18805
+ });
18764
18806
  method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), method(object({ ruleId: string() }), object({ rule: NcRuleSchema.nullable() }), { auth: "admin" }), method(object({ rule: NcRuleInputSchema }), object({ rule: NcRuleSchema }), {
18765
18807
  kind: "mutation",
18766
18808
  auth: "admin",
@@ -18781,7 +18823,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
18781
18823
  }), object({ success: literal(true) }), {
18782
18824
  kind: "mutation",
18783
18825
  auth: "admin"
18784
- }), method(object({}), object({ mutedDeviceIds: array(number().int()).readonly() }), { auth: "admin" }), method(object({
18826
+ }), method(object({}), NcClipRetentionPlanSchema, { auth: "admin" }), method(object({}), object({ mutedDeviceIds: array(number().int()).readonly() }), { auth: "admin" }), method(object({
18785
18827
  deviceId: number().int(),
18786
18828
  muted: boolean()
18787
18829
  }), object({ success: literal(true) }), {
@@ -35867,6 +35909,12 @@ Object.freeze({
35867
35909
  addonId: null,
35868
35910
  access: "view"
35869
35911
  },
35912
+ "notificationRules.getClipRetentionAsks": {
35913
+ capName: "notification-rules",
35914
+ capScope: "system",
35915
+ addonId: null,
35916
+ access: "view"
35917
+ },
35870
35918
  "notificationRules.getConditionCatalog": {
35871
35919
  capName: "notification-rules",
35872
35920
  capScope: "system",
@@ -42026,7 +42074,7 @@ var AudioSubscriptionController = class {
42026
42074
  } catch (err) {
42027
42075
  this.deps.logger.error("audio re-attach failed", {
42028
42076
  tags: { deviceId },
42029
- meta: { error: errMsg(err) }
42077
+ meta: { error: errMsg$1(err) }
42030
42078
  });
42031
42079
  }
42032
42080
  }
@@ -42137,7 +42185,7 @@ var AudioSubscriptionController = class {
42137
42185
  this.closeMotionAudioWindow(deviceId, "motion-cooldown-elapsed").catch((err) => {
42138
42186
  this.deps.logger.warn("lazy audio: cooldown teardown failed", {
42139
42187
  tags: { deviceId },
42140
- meta: { error: errMsg(err) }
42188
+ meta: { error: errMsg$1(err) }
42141
42189
  });
42142
42190
  });
42143
42191
  }, cooldownMs);
@@ -42156,7 +42204,7 @@ var AudioSubscriptionController = class {
42156
42204
  this.closeMotionAudioWindow(deviceId, "quiet-window-elapsed").catch((err) => {
42157
42205
  this.deps.logger.warn("lazy audio: quiet-window teardown failed", {
42158
42206
  tags: { deviceId },
42159
- meta: { error: errMsg(err) }
42207
+ meta: { error: errMsg$1(err) }
42160
42208
  });
42161
42209
  });
42162
42210
  }, windowMs);
@@ -42327,7 +42375,7 @@ var AudioSubscriptionController = class {
42327
42375
  meta: {
42328
42376
  audioNodeId,
42329
42377
  brokerId: audioBrokerId,
42330
- error: errMsg(err)
42378
+ error: errMsg$1(err)
42331
42379
  }
42332
42380
  });
42333
42381
  });
@@ -43347,7 +43395,7 @@ var LoadShedController = class LoadShedController {
43347
43395
  if (await this.tryClusterRelocate(deviceId).catch((err) => {
43348
43396
  this.deps.logger.warn("Load management: cluster relocate failed", {
43349
43397
  tags: { deviceId },
43350
- meta: { error: errMsg(err) }
43398
+ meta: { error: errMsg$1(err) }
43351
43399
  });
43352
43400
  return false;
43353
43401
  })) {
@@ -43361,7 +43409,7 @@ var LoadShedController = class LoadShedController {
43361
43409
  this.deps.api()?.pipelineRunner.detachCamera.mutate({ deviceId }).catch((err) => {
43362
43410
  this.deps.logger.warn("Load management: detachCamera failed", {
43363
43411
  tags: { deviceId },
43364
- meta: { error: errMsg(err) }
43412
+ meta: { error: errMsg$1(err) }
43365
43413
  });
43366
43414
  });
43367
43415
  this.ensureLoadShedResumeTimer();
@@ -43393,7 +43441,7 @@ var LoadShedController = class LoadShedController {
43393
43441
  tags: { deviceId },
43394
43442
  meta: {
43395
43443
  from: currentNode,
43396
- error: errMsg(err)
43444
+ error: errMsg$1(err)
43397
43445
  }
43398
43446
  });
43399
43447
  });
@@ -43436,7 +43484,7 @@ var LoadShedController = class LoadShedController {
43436
43484
  this.deps.redispatchSingleCamera(deviceId).catch((err) => {
43437
43485
  this.deps.logger.warn("Load management: auto-resume dispatch failed", {
43438
43486
  tags: { deviceId },
43439
- meta: { error: errMsg(err) }
43487
+ meta: { error: errMsg$1(err) }
43440
43488
  });
43441
43489
  });
43442
43490
  }
@@ -43597,7 +43645,7 @@ var AgentLoadService = class AgentLoadService {
43597
43645
  ms,
43598
43646
  outcome: "failed",
43599
43647
  load: null,
43600
- error: errMsg(outcome.error)
43648
+ error: errMsg$1(outcome.error)
43601
43649
  };
43602
43650
  return {
43603
43651
  nodeId,
@@ -44601,7 +44649,7 @@ function warnSampled(deps, deviceId, source, message, meta) {
44601
44649
  function warnUnreachable(deps, deviceId, source, err) {
44602
44650
  warnSampled(deps, deviceId, source, UNREACHABLE_MESSAGE, {
44603
44651
  source,
44604
- error: errMsg(err)
44652
+ error: errMsg$1(err)
44605
44653
  });
44606
44654
  }
44607
44655
  /**
@@ -45846,6 +45894,89 @@ function sameFeatures(a, b) {
45846
45894
  return b.every((f) => held.has(f));
45847
45895
  }
45848
45896
  //#endregion
45897
+ //#region src/onboard-forwarding-reconcile.ts
45898
+ /** The `detectionSources` member that means "this camera's own firmware". */
45899
+ var ONBOARD_DETECTION_SOURCE = "onboard";
45900
+ /**
45901
+ * What an ABSENT `detectionSources` means. `CameraDetectionConfig` declares the
45902
+ * field optional and its own contract as "absent is `['pipeline']` all the way
45903
+ * down" — the resolver always fills it, so this only covers the hand-built
45904
+ * configs, and it reads them the same way the runner does.
45905
+ */
45906
+ var DETECTION_SOURCES_WHEN_ABSENT = ["pipeline"];
45907
+ function errMsg(err) {
45908
+ return err instanceof Error ? err.message : String(err);
45909
+ }
45910
+ /**
45911
+ * Put the vendor forwarding flag back where `detectionSources` says it belongs.
45912
+ * Never throws — a camera's attach is not failed by a mechanism that could not
45913
+ * be reached, it is reported.
45914
+ */
45915
+ async function reconcileOnboardForwarding(input, deps) {
45916
+ const { deviceId, detectionSources } = input;
45917
+ const wantsOnboard = detectionSources.includes(ONBOARD_DETECTION_SOURCE);
45918
+ const log = deps.logger.withTags({ deviceId });
45919
+ let hasCap;
45920
+ try {
45921
+ hasCap = await deps.hasNativeObjectDetectionCap(deviceId);
45922
+ } catch (err) {
45923
+ log.warn("onboard forwarding not reconciled — could not tell whether the camera has the cap", { meta: {
45924
+ wantsOnboard,
45925
+ detectionSources: [...detectionSources],
45926
+ error: errMsg(err)
45927
+ } });
45928
+ return {
45929
+ kind: "read-failed",
45930
+ wantsOnboard
45931
+ };
45932
+ }
45933
+ if (!hasCap) return {
45934
+ kind: "no-cap",
45935
+ wantsOnboard
45936
+ };
45937
+ let current;
45938
+ try {
45939
+ current = await deps.readForwardingEnabled(deviceId);
45940
+ } catch (err) {
45941
+ log.warn("onboard forwarding not reconciled — the vendor flag could not be read", { meta: {
45942
+ wantsOnboard,
45943
+ detectionSources: [...detectionSources],
45944
+ error: errMsg(err)
45945
+ } });
45946
+ return {
45947
+ kind: "read-failed",
45948
+ wantsOnboard
45949
+ };
45950
+ }
45951
+ if (current === wantsOnboard) return {
45952
+ kind: "aligned",
45953
+ wantsOnboard
45954
+ };
45955
+ try {
45956
+ await deps.writeForwardingEnabled(deviceId, wantsOnboard);
45957
+ } catch (err) {
45958
+ log.warn("onboard forwarding drifted and the repair failed", { meta: {
45959
+ was: current,
45960
+ wanted: wantsOnboard,
45961
+ detectionSources: [...detectionSources],
45962
+ error: errMsg(err)
45963
+ } });
45964
+ return {
45965
+ kind: "write-failed",
45966
+ wantsOnboard
45967
+ };
45968
+ }
45969
+ log.info("onboard forwarding flag put back to match the camera pick", { meta: {
45970
+ was: current,
45971
+ now: wantsOnboard,
45972
+ detectionSources: [...detectionSources]
45973
+ } });
45974
+ return {
45975
+ kind: "repaired",
45976
+ wantsOnboard
45977
+ };
45978
+ }
45979
+ //#endregion
45849
45980
  //#region src/watchdog-camera.ts
45850
45981
  /**
45851
45982
  * Derive the watchdog camera descriptor from a runner config. Captures which
@@ -46015,7 +46146,7 @@ var DetectionWiringController = class {
46015
46146
  try {
46016
46147
  raw = await this.deps.ctx().settings.readDeviceStore(deviceId);
46017
46148
  } catch (err) {
46018
- const msg = errMsg(err);
46149
+ const msg = errMsg$1(err);
46019
46150
  this.deps.logger.error("resolveDeviceDetectionSettings failed", {
46020
46151
  tags: { deviceId },
46021
46152
  meta: { error: msg }
@@ -46046,7 +46177,7 @@ var DetectionWiringController = class {
46046
46177
  motionDetectionEnabled
46047
46178
  });
46048
46179
  } catch (err) {
46049
- const msg = errMsg(err);
46180
+ const msg = errMsg$1(err);
46050
46181
  this.deps.logger.error("resolveDeviceDetectionSettings narrowing failed", {
46051
46182
  tags: { deviceId },
46052
46183
  meta: { error: msg }
@@ -46076,7 +46207,7 @@ var DetectionWiringController = class {
46076
46207
  } catch (err) {
46077
46208
  this.deps.logger.debug("fetchAssignedProfiles: slot read failed (transient) — treating as unknown", {
46078
46209
  tags: { deviceId },
46079
- meta: { error: errMsg(err) }
46210
+ meta: { error: errMsg$1(err) }
46080
46211
  });
46081
46212
  return null;
46082
46213
  }
@@ -46096,6 +46227,41 @@ var DetectionWiringController = class {
46096
46227
  return buildDetectionConfigFromInputs(resolved, assigned);
46097
46228
  }
46098
46229
  /**
46230
+ * Make the vendor's onboard-AI forwarding flag agree with this camera's
46231
+ * `detectionSources` pick — in both directions. See
46232
+ * `onboard-forwarding-reconcile.ts` for why the save-time write is not
46233
+ * enough (the flag is device state and a provider restart re-seeds it OFF,
46234
+ * measured on all seven Reolink cameras of the live hub).
46235
+ *
46236
+ * Never throws: a mechanism that could not be reached is reported, it does
46237
+ * not fail the camera's attach.
46238
+ */
46239
+ async reconcileOnboardForwarding(deviceId, detectionSources) {
46240
+ return reconcileOnboardForwarding({
46241
+ deviceId,
46242
+ detectionSources
46243
+ }, {
46244
+ hasNativeObjectDetectionCap: (id) => this.deps.deviceHasNativeObjectDetectionCap(id),
46245
+ readForwardingEnabled: async (id) => {
46246
+ const api = this.deps.api();
46247
+ if (!api) throw new Error("orchestrator: no api — cannot read the onboard forwarding flag");
46248
+ const raw = await api.nativeObjectDetection.getStatus.query({ deviceId: id });
46249
+ const parsed = NativeObjectDetectionStatusSchema.safeParse(raw);
46250
+ if (!parsed.success) throw new Error(`orchestrator: nativeObjectDetection.getStatus returned an unusable status — ${parsed.error.message}`);
46251
+ return parsed.data.enabled;
46252
+ },
46253
+ writeForwardingEnabled: async (id, enabled) => {
46254
+ const api = this.deps.api();
46255
+ if (!api) throw new Error("orchestrator: no api — cannot write the onboard forwarding flag");
46256
+ await api.nativeObjectDetection.setEnabled.mutate({
46257
+ deviceId: id,
46258
+ enabled
46259
+ });
46260
+ },
46261
+ logger: this.deps.logger
46262
+ });
46263
+ }
46264
+ /**
46099
46265
  * Start detection for a camera: dispatch to runner via the orchestrator
46100
46266
  * local path and subscribe to the audio broker if audio is enabled.
46101
46267
  */
@@ -46107,6 +46273,7 @@ var DetectionWiringController = class {
46107
46273
  await this.stopDetection(deviceId);
46108
46274
  }
46109
46275
  this.activeDetections.set(deviceId, config);
46276
+ await this.reconcileOnboardForwarding(deviceId, config.detectionSources ?? DETECTION_SOURCES_WHEN_ABSENT);
46110
46277
  if (!config.pipelineEnabled || config.detectionMode === "disabled") if (!config.pipelineEnabled) log.info("object detection switched off — no attach, no decode session", { meta: { detectionMode: config.detectionMode } });
46111
46278
  else log.info("detection mode disabled — no standing attach, no decode session", { meta: {
46112
46279
  detectionMode: config.detectionMode,
@@ -46116,7 +46283,7 @@ var DetectionWiringController = class {
46116
46283
  if (config.motionSources.includes("analyzer")) try {
46117
46284
  await this.deps.session.ensureMotionWatch(deviceId, config);
46118
46285
  } catch (err) {
46119
- log.error("ensureMotionWatch failed", { meta: { error: errMsg(err) } });
46286
+ log.error("ensureMotionWatch failed", { meta: { error: errMsg$1(err) } });
46120
46287
  }
46121
46288
  log.info("detection armed (session-time) — watching for motion", { meta: { motion: config.motionSources.join("+") } });
46122
46289
  } else {
@@ -46135,7 +46302,7 @@ var DetectionWiringController = class {
46135
46302
  const result = await this.deps.placement.dispatchCamera(runnerConfig);
46136
46303
  if (result.kind === "assigned") dispatchedNodeId = result.agentNodeId;
46137
46304
  } catch (err) {
46138
- const msg = errMsg(err);
46305
+ const msg = errMsg$1(err);
46139
46306
  log.error("dispatchCamera failed", { meta: { error: msg } });
46140
46307
  }
46141
46308
  if (dispatchedNodeId && (dispatchedNodeId !== hydrateNodeId || (runnerConfig.steps?.length ?? 0) === 0)) try {
@@ -46164,13 +46331,13 @@ var DetectionWiringController = class {
46164
46331
  });
46165
46332
  }
46166
46333
  } catch (err) {
46167
- log.warn("startDetection: post-dispatch re-resolve failed", { meta: { error: errMsg(err) } });
46334
+ log.warn("startDetection: post-dispatch re-resolve failed", { meta: { error: errMsg$1(err) } });
46168
46335
  }
46169
46336
  }
46170
46337
  try {
46171
46338
  await this.deps.audio.resubscribe(deviceId, config);
46172
46339
  } catch (err) {
46173
- const msg = errMsg(err);
46340
+ const msg = errMsg$1(err);
46174
46341
  log.error("subscribeAudioStream failed", { meta: { error: msg } });
46175
46342
  }
46176
46343
  if (config.detectionMode !== "on-motion") log.info("Detection dispatched", { meta: {
@@ -46186,7 +46353,7 @@ var DetectionWiringController = class {
46186
46353
  try {
46187
46354
  await this.deps.placement.releaseCamera({ deviceId });
46188
46355
  } catch (err) {
46189
- const msg = errMsg(err);
46356
+ const msg = errMsg$1(err);
46190
46357
  this.deps.logger.error("releaseCamera failed", {
46191
46358
  tags: { deviceId },
46192
46359
  meta: { error: msg }
@@ -46212,7 +46379,7 @@ var DetectionWiringController = class {
46212
46379
  } catch (err) {
46213
46380
  this.deps.logger.warn("failed to clear per-device orchestrator settings on removal", {
46214
46381
  tags: { deviceId },
46215
- meta: { error: errMsg(err) }
46382
+ meta: { error: errMsg$1(err) }
46216
46383
  });
46217
46384
  }
46218
46385
  this.deps.logger.info("Purged pipeline config for removed device", { tags: { deviceId } });
@@ -46236,7 +46403,7 @@ var DetectionWiringController = class {
46236
46403
  } catch (err) {
46237
46404
  this.deps.logger.debug("device existence check failed — proceeding as before", {
46238
46405
  tags: { deviceId },
46239
- meta: { error: errMsg(err) }
46406
+ meta: { error: errMsg$1(err) }
46240
46407
  });
46241
46408
  return false;
46242
46409
  }
@@ -46353,7 +46520,7 @@ var DetectionWiringController = class {
46353
46520
  await this.deps.attachOn(assignment.agentNodeId, nextConfig);
46354
46521
  log.info("pipeline.camera-updated: hot-reloaded", { tags: { nodeId: assignment.agentNodeId } });
46355
46522
  } catch (err) {
46356
- const msg = errMsg(err);
46523
+ const msg = errMsg$1(err);
46357
46524
  log.error("pipeline.camera-updated: attachOn failed", {
46358
46525
  tags: { nodeId: assignment.agentNodeId },
46359
46526
  meta: { error: msg }
@@ -46429,7 +46596,7 @@ var DetectionWiringController = class {
46429
46596
  this.deps.audio.resubscribe(deviceId, audioCfg).catch((err) => {
46430
46597
  this.deps.logger.warn("watchdog audio re-subscribe failed", {
46431
46598
  tags: { deviceId },
46432
- meta: { error: errMsg(err) }
46599
+ meta: { error: errMsg$1(err) }
46433
46600
  });
46434
46601
  });
46435
46602
  }
@@ -46628,7 +46795,7 @@ var DeviceConfigContributions = class {
46628
46795
  issue: configIssue
46629
46796
  } });
46630
46797
  this.deps.topology.refreshNodeCapabilities().then(() => this.deps.redispatchAllActiveCameras("ingest-owner-changed")).catch((err) => {
46631
- this.deps.ctx().logger.warn("ingest-owner-changed re-dispatch failed", { meta: { error: errMsg(err) } });
46798
+ this.deps.ctx().logger.warn("ingest-owner-changed re-dispatch failed", { meta: { error: errMsg$1(err) } });
46632
46799
  });
46633
46800
  }
46634
46801
  this.deps.clearOnSettingsChange();
@@ -47368,7 +47535,7 @@ var PlacementService = class {
47368
47535
  async releaseCamera(input) {
47369
47536
  const current = this.deps.ledger.getAssignment(input.deviceId);
47370
47537
  if (current) await this.detachOn(current.agentNodeId, input.deviceId).catch((err) => {
47371
- const msg = errMsg(err);
47538
+ const msg = errMsg$1(err);
47372
47539
  this.deps.ctx().logger.debug("releaseCamera detach failed", {
47373
47540
  tags: { deviceId: input.deviceId },
47374
47541
  meta: { error: msg }
@@ -47396,7 +47563,7 @@ var PlacementService = class {
47396
47563
  pipelineNodeId: input.agentNodeId,
47397
47564
  [PREFERRED_AGENT_SETTING]: null
47398
47565
  }).catch((err) => {
47399
- const msg = errMsg(err);
47566
+ const msg = errMsg$1(err);
47400
47567
  ctx.logger.warn("assignPipeline: failed to persist pin", {
47401
47568
  tags: { deviceId: input.deviceId },
47402
47569
  meta: { error: msg }
@@ -47428,7 +47595,7 @@ var PlacementService = class {
47428
47595
  }
47429
47596
  const current = this.deps.ledger.getAssignment(input.deviceId);
47430
47597
  if (current && current.agentNodeId !== input.agentNodeId) await this.detachOn(current.agentNodeId, input.deviceId).catch((err) => {
47431
- const msg = errMsg(err);
47598
+ const msg = errMsg$1(err);
47432
47599
  ctx.logger.debug("assignPipeline detach-old failed", {
47433
47600
  tags: { deviceId: input.deviceId },
47434
47601
  meta: { error: msg }
@@ -47453,7 +47620,7 @@ var PlacementService = class {
47453
47620
  await ctx.settings?.writeDeviceStore(input.deviceId, { pipelineDeviceKey: clearing ? "auto" : input.deviceKey }).catch((err) => {
47454
47621
  ctx.logger.warn("setPipelineDevicePin: failed to persist device pin", {
47455
47622
  tags: { deviceId: input.deviceId },
47456
- meta: { error: errMsg(err) }
47623
+ meta: { error: errMsg$1(err) }
47457
47624
  });
47458
47625
  });
47459
47626
  const sessionNode = this.deps.activeSessionNode(input.deviceId);
@@ -47476,7 +47643,7 @@ var PlacementService = class {
47476
47643
  [PREFERRED_AGENT_SETTING]: null,
47477
47644
  pipelineNodeId: "auto"
47478
47645
  }).catch((err) => {
47479
- const msg = errMsg(err);
47646
+ const msg = errMsg$1(err);
47480
47647
  ctx.logger.warn("unassignPipeline: failed to clear pin", {
47481
47648
  tags: { deviceId: input.deviceId },
47482
47649
  meta: { error: msg }
@@ -47497,7 +47664,7 @@ var PlacementService = class {
47497
47664
  else {
47498
47665
  const targetNodeId = decision.agentNodeId;
47499
47666
  if (current && current.agentNodeId !== targetNodeId) await this.detachOn(current.agentNodeId, input.deviceId).catch((err) => {
47500
- const msg = errMsg(err);
47667
+ const msg = errMsg$1(err);
47501
47668
  ctx.logger.debug("unassignPipeline detach-old failed", {
47502
47669
  tags: { deviceId: input.deviceId },
47503
47670
  meta: { error: msg }
@@ -47517,7 +47684,7 @@ var PlacementService = class {
47517
47684
  }
47518
47685
  }
47519
47686
  if (current) await this.detachOn(current.agentNodeId, input.deviceId).catch((err) => {
47520
- const msg = errMsg(err);
47687
+ const msg = errMsg$1(err);
47521
47688
  ctx.logger.debug("unassignPipeline detach failed", {
47522
47689
  tags: { deviceId: input.deviceId },
47523
47690
  meta: { error: msg }
@@ -47536,7 +47703,7 @@ var PlacementService = class {
47536
47703
  async runAutoRebalance() {
47537
47704
  if (!this.deps.ctxIfReady()) return;
47538
47705
  await this.deps.reconcilePlacementFromRunners().catch((err) => {
47539
- this.deps.ctx().logger.debug("auto-rebalance: attachment reconcile failed", { meta: { error: errMsg(err) } });
47706
+ this.deps.ctx().logger.debug("auto-rebalance: attachment reconcile failed", { meta: { error: errMsg$1(err) } });
47540
47707
  });
47541
47708
  if (this.autoRebalanceInFlight) return;
47542
47709
  if (this.deps.topology.enabledNodes.length < 2) return;
@@ -47545,7 +47712,7 @@ var PlacementService = class {
47545
47712
  const { migrated } = await this.rebalance({ minImprovement: AUTO_REBALANCE_MIN_IMPROVEMENT });
47546
47713
  if (migrated > 0) this.deps.ctx().logger.info("auto-rebalance: corrected placement drift", { meta: { migrated } });
47547
47714
  } catch (err) {
47548
- this.deps.ctx().logger.debug("auto-rebalance pass failed", { meta: { error: errMsg(err) } });
47715
+ this.deps.ctx().logger.debug("auto-rebalance pass failed", { meta: { error: errMsg$1(err) } });
47549
47716
  } finally {
47550
47717
  this.autoRebalanceInFlight = false;
47551
47718
  }
@@ -47596,7 +47763,7 @@ var PlacementService = class {
47596
47763
  }
47597
47764
  if (current) {
47598
47765
  await this.detachOn(current.agentNodeId, deviceId).catch((err) => {
47599
- const msg = errMsg(err);
47766
+ const msg = errMsg$1(err);
47600
47767
  ctx.logger.debug("rebalance detach-old failed", {
47601
47768
  tags: { deviceId },
47602
47769
  meta: { error: msg }
@@ -47923,7 +48090,7 @@ var NodeLifecycleHandler = class {
47923
48090
  nodeId: decision.agentNodeId
47924
48091
  } });
47925
48092
  } catch (err) {
47926
- const msg = errMsg(err);
48093
+ const msg = errMsg$1(err);
47927
48094
  this.deps.logger.error("Failover: attach failed", {
47928
48095
  tags: {
47929
48096
  deviceId,
@@ -47953,7 +48120,7 @@ var NodeLifecycleHandler = class {
47953
48120
  this.deps.schedulePendingRetry();
47954
48121
  if (failoverPolicy.onReconnect === "rebalance") {
47955
48122
  await this.deps.rebalance().catch((err) => {
47956
- const msg = errMsg(err);
48123
+ const msg = errMsg$1(err);
47957
48124
  this.deps.logger.error("rebalance after reconnect failed", { meta: { error: msg } });
47958
48125
  });
47959
48126
  return;
@@ -47979,7 +48146,7 @@ var NodeLifecycleHandler = class {
47979
48146
  this.deps.ledger.recordAssignment(deviceId, nodeId, "failover", false);
47980
48147
  restored++;
47981
48148
  } catch (err) {
47982
- const msg = errMsg(err);
48149
+ const msg = errMsg$1(err);
47983
48150
  this.deps.logger.error("restore attach failed", {
47984
48151
  tags: {
47985
48152
  deviceId,
@@ -48069,7 +48236,7 @@ var NodeLifecycleHandler = class {
48069
48236
  deviceId,
48070
48237
  nodeId
48071
48238
  },
48072
- meta: { error: errMsg(err) }
48239
+ meta: { error: errMsg$1(err) }
48073
48240
  });
48074
48241
  }
48075
48242
  this.deps.logger.info("readiness: detection-pipeline reseeded agent defaults + redispatched cameras", {
@@ -48083,7 +48250,7 @@ var NodeLifecycleHandler = class {
48083
48250
  this.reattachStaleEmpties(nodeId).catch((err) => {
48084
48251
  this.deps.logger.debug("readiness deferred sweep failed", {
48085
48252
  tags: { nodeId },
48086
- meta: { error: errMsg(err) }
48253
+ meta: { error: errMsg$1(err) }
48087
48254
  });
48088
48255
  });
48089
48256
  }, 3e3);
@@ -48094,7 +48261,7 @@ var NodeLifecycleHandler = class {
48094
48261
  tags: { nodeId },
48095
48262
  meta: {
48096
48263
  epoch: t.epoch,
48097
- error: errMsg(err)
48264
+ error: errMsg$1(err)
48098
48265
  }
48099
48266
  });
48100
48267
  }
@@ -48133,7 +48300,7 @@ var NodeLifecycleHandler = class {
48133
48300
  deviceId,
48134
48301
  nodeId
48135
48302
  },
48136
- meta: { error: errMsg(err) }
48303
+ meta: { error: errMsg$1(err) }
48137
48304
  });
48138
48305
  }
48139
48306
  }
@@ -48455,7 +48622,7 @@ var NodeStressController = class NodeStressController {
48455
48622
  if (this.timer) return;
48456
48623
  this.timer = setInterval(() => {
48457
48624
  this.sweep().catch((err) => {
48458
- this.deps.logger.warn("node-stress sweep failed", { meta: { error: errMsg(err) } });
48625
+ this.deps.logger.warn("node-stress sweep failed", { meta: { error: errMsg$1(err) } });
48459
48626
  });
48460
48627
  }, NodeStressController.SWEEP_INTERVAL_MS);
48461
48628
  }
@@ -48628,7 +48795,7 @@ var NodeStressController = class NodeStressController {
48628
48795
  meta: {
48629
48796
  from: plan.fromNodeId,
48630
48797
  to: plan.toNodeId,
48631
- error: errMsg(err)
48798
+ error: errMsg$1(err)
48632
48799
  }
48633
48800
  });
48634
48801
  } finally {
@@ -49325,7 +49492,7 @@ var NodeTopologyService = class {
49325
49492
  try {
49326
49493
  blob = await this.deps.readAgentSettingsMap();
49327
49494
  } catch (err) {
49328
- this.deps.logger.warn("refreshNodeCapabilities: agent settings read failed", { meta: { error: errMsg(err) } });
49495
+ this.deps.logger.warn("refreshNodeCapabilities: agent settings read failed", { meta: { error: errMsg$1(err) } });
49329
49496
  }
49330
49497
  const nodeIds = new Set(["hub"]);
49331
49498
  for (const nodeId of Object.keys(blob)) if (typeof nodeId === "string" && nodeId.length > 0 && !nodeId.includes("/")) nodeIds.add(nodeId);
@@ -49383,7 +49550,7 @@ function wireOrchestratorSubscriptions(deps) {
49383
49550
  const unsubInferenceResult = deps.eventBus.subscribe({ category: EventCategory.PipelineInferenceResult }, (event) => {
49384
49551
  if (!isEvent(event, EventCategory.PipelineInferenceResult)) return;
49385
49552
  deps.handleInferenceResult(event.data).catch((err) => {
49386
- const msg = errMsg(err);
49553
+ const msg = errMsg$1(err);
49387
49554
  deps.logger.error("PipelineInferenceResult post-processing failed", {
49388
49555
  tags: { deviceId: event.data.deviceId },
49389
49556
  meta: { error: msg }
@@ -49402,7 +49569,7 @@ function wireOrchestratorSubscriptions(deps) {
49402
49569
  deps.logger.info("received onProfileSlotsChanged", { tags: { deviceId } });
49403
49570
  deps.handleDeviceRegistered(deviceId).catch((err) => {
49404
49571
  if (isTornDown) return;
49405
- const msg = errMsg(err);
49572
+ const msg = errMsg$1(err);
49406
49573
  deps.logger.error("handleDeviceRegistered failed", {
49407
49574
  tags: { deviceId },
49408
49575
  meta: { error: msg }
@@ -49414,7 +49581,7 @@ function wireOrchestratorSubscriptions(deps) {
49414
49581
  const unsubDeviceUnregistered = deps.eventBus.subscribe({ category: EventCategory.DeviceUnregistered }, (event) => {
49415
49582
  const { deviceId } = event.data;
49416
49583
  deps.handleDeviceUnregistered(deviceId).catch((err) => {
49417
- const msg = errMsg(err);
49584
+ const msg = errMsg$1(err);
49418
49585
  deps.logger.error("handleDeviceUnregistered failed", {
49419
49586
  tags: { deviceId },
49420
49587
  meta: { error: msg }
@@ -49426,7 +49593,7 @@ function wireOrchestratorSubscriptions(deps) {
49426
49593
  const { deviceId } = event.data;
49427
49594
  deps.handleSettingsChanged(deviceId).catch((err) => {
49428
49595
  if (isTornDown) return;
49429
- const msg = errMsg(err);
49596
+ const msg = errMsg$1(err);
49430
49597
  deps.logger.error("handleSettingsChanged failed", {
49431
49598
  tags: { deviceId },
49432
49599
  meta: { error: msg }
@@ -49436,7 +49603,7 @@ function wireOrchestratorSubscriptions(deps) {
49436
49603
  const unsubCameraUpdated = deps.eventBus.subscribe({ category: EventCategory.PipelineCameraUpdated }, (event) => {
49437
49604
  if (!isEvent(event, EventCategory.PipelineCameraUpdated)) return;
49438
49605
  deps.handlePipelineCameraUpdated(event.data.deviceId, event.data.config).catch((err) => {
49439
- const msg = errMsg(err);
49606
+ const msg = errMsg$1(err);
49440
49607
  deps.logger.error("handlePipelineCameraUpdated failed", {
49441
49608
  tags: { deviceId: event.data.deviceId },
49442
49609
  meta: { error: msg }
@@ -49449,7 +49616,7 @@ function wireOrchestratorSubscriptions(deps) {
49449
49616
  if (!(reason === "wrapper-activated" || reason === "wrapper-deactivated") || !(capName === "detection-pipeline" || capName === "audio-analysis" || capName === "motion-detection")) return;
49450
49617
  deps.handleSettingsChanged(deviceId).catch((err) => {
49451
49618
  if (isTornDown) return;
49452
- const msg = errMsg(err);
49619
+ const msg = errMsg$1(err);
49453
49620
  deps.logger.error("binding-changed re-dispatch failed", {
49454
49621
  tags: { deviceId },
49455
49622
  meta: {
@@ -49477,7 +49644,7 @@ function wireOrchestratorSubscriptions(deps) {
49477
49644
  tags: { deviceId },
49478
49645
  meta: {
49479
49646
  detected,
49480
- error: errMsg(err)
49647
+ error: errMsg$1(err)
49481
49648
  }
49482
49649
  });
49483
49650
  });
@@ -49492,7 +49659,7 @@ function wireOrchestratorSubscriptions(deps) {
49492
49659
  tags: { deviceId },
49493
49660
  meta: {
49494
49661
  detected,
49495
- error: errMsg(err)
49662
+ error: errMsg$1(err)
49496
49663
  }
49497
49664
  });
49498
49665
  });
@@ -50486,7 +50653,7 @@ var PipelineSettingsStore = class PipelineSettingsStore {
50486
50653
  } catch (err) {
50487
50654
  this.deps.logger.debug("getCatalogForAgent failed", {
50488
50655
  tags: { nodeId },
50489
- meta: { error: errMsg(err) }
50656
+ meta: { error: errMsg$1(err) }
50490
50657
  });
50491
50658
  return null;
50492
50659
  }
@@ -50549,7 +50716,7 @@ var PipelineSettingsStore = class PipelineSettingsStore {
50549
50716
  tags: { deviceId },
50550
50717
  meta: {
50551
50718
  capName: "detection-pipeline",
50552
- error: errMsg(err)
50719
+ error: errMsg$1(err)
50553
50720
  }
50554
50721
  });
50555
50722
  return true;
@@ -51272,7 +51439,7 @@ var ReconcileController = class ReconcileController {
51272
51439
  try {
51273
51440
  slots = await api.streamBroker.listAllProfileSlots.query();
51274
51441
  } catch (err) {
51275
- this.deps.logger.debug("dispatch reconcile skipped — stream-broker not ready", { meta: { error: errMsg(err) } });
51442
+ this.deps.logger.debug("dispatch reconcile skipped — stream-broker not ready", { meta: { error: errMsg$1(err) } });
51276
51443
  return;
51277
51444
  }
51278
51445
  const desired = desiredDeviceIdsFromSlots(slots);
@@ -51299,7 +51466,7 @@ var ReconcileController = class ReconcileController {
51299
51466
  } catch (err) {
51300
51467
  this.deps.logger.warn("dispatch reconcile: handleDeviceRegistered failed", {
51301
51468
  tags: { deviceId },
51302
- meta: { error: errMsg(err) }
51469
+ meta: { error: errMsg$1(err) }
51303
51470
  });
51304
51471
  }
51305
51472
  await this.reconcilePlacementFromRunners();
@@ -51327,7 +51494,7 @@ var ReconcileController = class ReconcileController {
51327
51494
  const devices = await api.deviceManager.listAll.query({ projection: "slim" });
51328
51495
  return new Set(devices.map((device) => device.id));
51329
51496
  } catch (err) {
51330
- this.deps.logger.debug("dispatch reconcile: deviceManager.listAll failed", { meta: { error: errMsg(err) } });
51497
+ this.deps.logger.debug("dispatch reconcile: deviceManager.listAll failed", { meta: { error: errMsg$1(err) } });
51331
51498
  return null;
51332
51499
  }
51333
51500
  }
@@ -51353,7 +51520,7 @@ var ReconcileController = class ReconcileController {
51353
51520
  } catch (err) {
51354
51521
  this.deps.logger.warn("dispatch reconcile: teardown of vanished device failed", {
51355
51522
  tags: { deviceId },
51356
- meta: { error: errMsg(err) }
51523
+ meta: { error: errMsg$1(err) }
51357
51524
  });
51358
51525
  }
51359
51526
  }
@@ -51410,7 +51577,7 @@ var ReconcileController = class ReconcileController {
51410
51577
  this.deps.logger.debug("placement reconcile skipped node — getLocalCameras failed", {
51411
51578
  tags: { nodeId },
51412
51579
  meta: {
51413
- error: outcome.kind === "rejected" ? errMsg(outcome.error) : "budget exceeded",
51580
+ error: outcome.kind === "rejected" ? errMsg$1(outcome.error) : "budget exceeded",
51414
51581
  ms
51415
51582
  }
51416
51583
  });
@@ -51440,7 +51607,7 @@ var ReconcileController = class ReconcileController {
51440
51607
  nodeId,
51441
51608
  deviceId
51442
51609
  },
51443
- meta: { error: errMsg(err) }
51610
+ meta: { error: errMsg$1(err) }
51444
51611
  });
51445
51612
  })));
51446
51613
  }
@@ -51482,7 +51649,7 @@ var ReconcileController = class ReconcileController {
51482
51649
  this.deps.handleDeviceRegistered(deviceId).catch((err) => {
51483
51650
  this.deps.logger.debug("slot-read retry: handleDeviceRegistered failed", {
51484
51651
  tags: { deviceId },
51485
- meta: { error: errMsg(err) }
51652
+ meta: { error: errMsg$1(err) }
51486
51653
  });
51487
51654
  });
51488
51655
  }, delay);
@@ -51560,7 +51727,7 @@ var ReconcileController = class ReconcileController {
51560
51727
  } catch (err) {
51561
51728
  this.deps.logger.warn("pending retry: dispatchCamera failed", {
51562
51729
  tags: { deviceId },
51563
- meta: { error: errMsg(err) }
51730
+ meta: { error: errMsg$1(err) }
51564
51731
  });
51565
51732
  stillPending++;
51566
51733
  }
@@ -51638,7 +51805,7 @@ var ReconcileController = class ReconcileController {
51638
51805
  await this.deps.detachOn(assignment.agentNodeId, deviceId).catch((err) => {
51639
51806
  this.deps.logger.debug("remote-health exhausted-detach failed", {
51640
51807
  tags: { deviceId },
51641
- meta: { error: errMsg(err) }
51808
+ meta: { error: errMsg$1(err) }
51642
51809
  });
51643
51810
  });
51644
51811
  return;
@@ -51661,14 +51828,14 @@ var ReconcileController = class ReconcileController {
51661
51828
  await this.deps.detachOn(assignment.agentNodeId, deviceId).catch((err) => {
51662
51829
  this.deps.logger.warn("remote-health detach failed", {
51663
51830
  tags: { deviceId },
51664
- meta: { error: errMsg(err) }
51831
+ meta: { error: errMsg$1(err) }
51665
51832
  });
51666
51833
  });
51667
51834
  this.deps.ledger.dropAssignment(deviceId, "silent");
51668
51835
  await this.deps.dispatchCamera(cfg).catch((err) => {
51669
51836
  this.deps.logger.warn("remote-health re-dispatch failed", {
51670
51837
  tags: { deviceId },
51671
- meta: { error: errMsg(err) }
51838
+ meta: { error: errMsg$1(err) }
51672
51839
  });
51673
51840
  });
51674
51841
  }
@@ -52317,7 +52484,7 @@ var SessionDispatchController = class {
52317
52484
  deviceId,
52318
52485
  nodeId: session.nodeId
52319
52486
  },
52320
- meta: { error: errMsg(err) }
52487
+ meta: { error: errMsg$1(err) }
52321
52488
  });
52322
52489
  });
52323
52490
  this.deps.dropAssignment(deviceId, "silent");
@@ -52502,7 +52669,7 @@ var SessionDispatchController = class {
52502
52669
  };
52503
52670
  if (reconcileBudgetExceeded) log.warn("detection session: placement census overran its budget — placing without it", { meta: { budgetMs: 500 } });
52504
52671
  else if (censusOutcome.kind === "rejected") log.warn("detection session: placement census failed — placing on the ledger as it is", { meta: {
52505
- error: errMsg(censusOutcome.error),
52672
+ error: errMsg$1(censusOutcome.error),
52506
52673
  reconcileMs
52507
52674
  } });
52508
52675
  const balanceStartedAt = Date.now();
@@ -52664,7 +52831,7 @@ var SessionDispatchController = class {
52664
52831
  await this.resolveSessionLifecycleLocked(deviceId, reason);
52665
52832
  }).catch((err) => {
52666
52833
  log.warn("detection session: lifecycle re-check failed", { meta: {
52667
- error: errMsg(err),
52834
+ error: errMsg$1(err),
52668
52835
  reason
52669
52836
  } });
52670
52837
  });
@@ -52769,7 +52936,7 @@ var SessionDispatchController = class {
52769
52936
  log.warn("detection session: teardown detach failed", {
52770
52937
  tags: { nodeId: session.nodeId },
52771
52938
  meta: {
52772
- error: errMsg(err),
52939
+ error: errMsg$1(err),
52773
52940
  reason
52774
52941
  }
52775
52942
  });
@@ -52852,7 +53019,7 @@ var SessionDispatchController = class {
52852
53019
  deviceId,
52853
53020
  nodeId: session.nodeId
52854
53021
  },
52855
- meta: { error: errMsg(err) }
53022
+ meta: { error: errMsg$1(err) }
52856
53023
  });
52857
53024
  });
52858
53025
  this.sessionRegistry.deregister(deviceId);
@@ -52870,7 +53037,7 @@ var SessionDispatchController = class {
52870
53037
  deviceId,
52871
53038
  nodeId: watchNodeId
52872
53039
  },
52873
- meta: { error: errMsg(err) }
53040
+ meta: { error: errMsg$1(err) }
52874
53041
  });
52875
53042
  });
52876
53043
  this.motionWatchByDevice.delete(deviceId);
@@ -53050,7 +53217,7 @@ async function sweepMirror(deps, hydrator, cameraIds) {
53050
53217
  tags: { deviceId },
53051
53218
  meta: {
53052
53219
  mirror: hydrator.mirror,
53053
- error: errMsg(err)
53220
+ error: errMsg$1(err)
53054
53221
  }
53055
53222
  });
53056
53223
  return "threw";
@@ -53090,7 +53257,7 @@ async function readCameraIds(deps) {
53090
53257
  lastError = err;
53091
53258
  }
53092
53259
  if (Date.now() >= deadline) {
53093
- deps.logger.warn("zones mirror boot hydration SKIPPED — camera list never became readable; mirror-only consumers keep whatever the last write left", { meta: { error: lastError === null ? "ctx.api unavailable" : errMsg(lastError) } });
53260
+ deps.logger.warn("zones mirror boot hydration SKIPPED — camera list never became readable; mirror-only consumers keep whatever the last write left", { meta: { error: lastError === null ? "ctx.api unavailable" : errMsg$1(lastError) } });
53094
53261
  return null;
53095
53262
  }
53096
53263
  await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
@@ -53731,7 +53898,7 @@ async function buildOrchestratorControllers(deps) {
53731
53898
  } catch (err) {
53732
53899
  return {
53733
53900
  kind: "unknown",
53734
- reason: errMsg(err)
53901
+ reason: errMsg$1(err)
53735
53902
  };
53736
53903
  }
53737
53904
  };
@@ -53815,14 +53982,14 @@ async function buildOrchestratorControllers(deps) {
53815
53982
  readGlobalSettings: () => globalSettings
53816
53983
  });
53817
53984
  await NodeStressMoveLedger.declare(deps.ctx().api.settingsStore).then(() => nodeStress.hydrate()).catch((err) => {
53818
- deps.ctx().logger.warn("node-stress move history unavailable — this boot starts cold", { meta: { error: errMsg(err) } });
53985
+ deps.ctx().logger.warn("node-stress move history unavailable — this boot starts cold", { meta: { error: errMsg$1(err) } });
53819
53986
  });
53820
53987
  await NodeStressLts.declare(deps.ctx().api.settingsStore).catch((err) => {
53821
- deps.ctx().logger.warn("node-stress statistics unavailable — no baseline this boot", { meta: { error: errMsg(err) } });
53988
+ deps.ctx().logger.warn("node-stress statistics unavailable — no baseline this boot", { meta: { error: errMsg$1(err) } });
53822
53989
  });
53823
53990
  const nodeStressLtsTimer = setInterval(() => {
53824
53991
  nodeStressLts.flushDue().catch((err) => {
53825
- deps.ctx().logger.warn("node-stress statistics flush failed", { meta: { error: errMsg(err) } });
53992
+ deps.ctx().logger.warn("node-stress statistics flush failed", { meta: { error: errMsg$1(err) } });
53826
53993
  });
53827
53994
  }, 6e4);
53828
53995
  nodeStress.start();
@@ -53959,7 +54126,7 @@ async function buildOrchestratorControllers(deps) {
53959
54126
  deps.applyRuntimeSettings(globalSettings);
53960
54127
  await topology.refreshNodeCapabilities();
53961
54128
  } catch (err) {
53962
- const msg = errMsg(err);
54129
+ const msg = errMsg$1(err);
53963
54130
  deps.ctx().logger.warn("orchestrator settings load failed — using defaults", { meta: { error: msg } });
53964
54131
  }
53965
54132
  const rawNodeId = deps.ctx().kernel.localNodeId ?? "hub";
@@ -53992,7 +54159,7 @@ async function buildOrchestratorControllers(deps) {
53992
54159
  nodeLifecycle.unsubscribeDetectionPipelineReadiness(nodeId);
53993
54160
  audio.markNodeOffline(nodeId);
53994
54161
  nodeLifecycle.handleNodeDisconnect(nodeId).catch((err) => {
53995
- const msg = errMsg(err);
54162
+ const msg = errMsg$1(err);
53996
54163
  deps.ctx().logger.error("failover after disconnect failed", {
53997
54164
  tags: { nodeId },
53998
54165
  meta: { error: msg }
@@ -54007,7 +54174,7 @@ async function buildOrchestratorControllers(deps) {
54007
54174
  deps.subscribeToAudioAnalyzerReadiness(nodeId);
54008
54175
  }
54009
54176
  nodeLifecycle.handleNodeConnect(nodeId).catch((err) => {
54010
- const msg = errMsg(err);
54177
+ const msg = errMsg$1(err);
54011
54178
  deps.ctx().logger.error("reconnect handling failed", {
54012
54179
  tags: { nodeId },
54013
54180
  meta: { error: msg }
@@ -54021,7 +54188,7 @@ async function buildOrchestratorControllers(deps) {
54021
54188
  meta: { capName }
54022
54189
  });
54023
54190
  nodeLifecycle.handleNodeDisconnect(nodeId).catch((err) => {
54024
- const msg = errMsg(err);
54191
+ const msg = errMsg$1(err);
54025
54192
  deps.ctx().logger.error("failover after cap-down failed", {
54026
54193
  tags: { nodeId },
54027
54194
  meta: {
@@ -54084,7 +54251,7 @@ async function buildOrchestratorControllers(deps) {
54084
54251
  doneFlag: settingsStore.bindingsMigrationDoneState,
54085
54252
  logger: deps.ctx().logger
54086
54253
  }).catch((err) => {
54087
- deps.ctxIfReady()?.logger.warn("bindings migration failed — will retry on next boot", { meta: { error: errMsg(err) } });
54254
+ deps.ctxIfReady()?.logger.warn("bindings migration failed — will retry on next boot", { meta: { error: errMsg$1(err) } });
54088
54255
  });
54089
54256
  migrateStepGating({
54090
54257
  readCameraSettings: () => settingsStore.readCameraSettingsMap(),
@@ -54095,7 +54262,7 @@ async function buildOrchestratorControllers(deps) {
54095
54262
  }).then(async () => {
54096
54263
  if (await settingsStore.applyPerNodeDeviceMigration()) deps.ctxIfReady()?.logger.info("per-(node,device) config migration applied");
54097
54264
  }).catch((err) => {
54098
- deps.ctxIfReady()?.logger.warn("step-gating / per-node-device migration failed — retry next boot", { meta: { error: errMsg(err) } });
54265
+ deps.ctxIfReady()?.logger.warn("step-gating / per-node-device migration failed — retry next boot", { meta: { error: errMsg$1(err) } });
54099
54266
  });
54100
54267
  const zoneRulesProvider = new ZoneRulesProvider({
54101
54268
  logger: deps.ctx().logger.child("zone-rules"),
@@ -54123,7 +54290,7 @@ async function buildOrchestratorControllers(deps) {
54123
54290
  deviceId,
54124
54291
  nodeId: assignment.agentNodeId
54125
54292
  },
54126
- meta: { error: errMsg(err) }
54293
+ meta: { error: errMsg$1(err) }
54127
54294
  });
54128
54295
  });
54129
54296
  }
@@ -54151,7 +54318,7 @@ async function buildOrchestratorControllers(deps) {
54151
54318
  deviceId,
54152
54319
  nodeId: assignment.agentNodeId
54153
54320
  },
54154
- meta: { error: errMsg(err) }
54321
+ meta: { error: errMsg$1(err) }
54155
54322
  });
54156
54323
  });
54157
54324
  }
@@ -54167,7 +54334,7 @@ async function buildOrchestratorControllers(deps) {
54167
54334
  }],
54168
54335
  logger: deps.ctx().logger.child("zones")
54169
54336
  }).catch((err) => {
54170
- deps.ctxIfReady()?.logger.warn("zones mirror boot hydration failed", { meta: { error: errMsg(err) } });
54337
+ deps.ctxIfReady()?.logger.warn("zones mirror boot hydration failed", { meta: { error: errMsg$1(err) } });
54171
54338
  });
54172
54339
  const unsubOrchestratorSubscriptions = wireOrchestratorSubscriptions({
54173
54340
  eventBus: deps.ctx().eventBus,
@@ -54216,10 +54383,11 @@ async function buildOrchestratorControllers(deps) {
54216
54383
  isCapActiveForDevice: (deviceId, capName) => deps.isCapActiveForDevice(deviceId, capName),
54217
54384
  deviceHasOnboardMotionCap: (deviceId) => deps.deviceHasOnboardMotionCap(deviceId),
54218
54385
  deviceHasActivitySignalCap: (deviceId) => deps.deviceHasActivitySignalCap(deviceId),
54386
+ deviceHasNativeObjectDetectionCap: (deviceId) => deps.deviceHasNativeObjectDetectionCap(deviceId),
54219
54387
  deviceSettingsSchema: () => deps.deviceSettingsSchema()
54220
54388
  });
54221
54389
  await detectionWiring.hydrateFeaturesMirror().catch((err) => {
54222
- deps.ctx().logger.warn("device-features mirror not restored — this boot starts cold", { meta: { error: errMsg(err) } });
54390
+ deps.ctx().logger.warn("device-features mirror not restored — this boot starts cold", { meta: { error: errMsg$1(err) } });
54223
54391
  });
54224
54392
  return {
54225
54393
  ledger,
@@ -55292,7 +55460,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
55292
55460
  for (const deviceId of this.detectionWiring.activeDetectionDeviceIds()) try {
55293
55461
  await this.releaseCamera({ deviceId });
55294
55462
  } catch (err) {
55295
- const msg = errMsg(err);
55463
+ const msg = errMsg$1(err);
55296
55464
  this.ctx.logger.debug("releaseCamera failed during shutdown", {
55297
55465
  tags: { deviceId },
55298
55466
  meta: { error: msg }
@@ -55918,7 +56086,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
55918
56086
  tags: { nodeId },
55919
56087
  meta: {
55920
56088
  nodeId,
55921
- error: errMsg(err)
56089
+ error: errMsg$1(err)
55922
56090
  }
55923
56091
  });
55924
56092
  return null;
@@ -56024,7 +56192,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
56024
56192
  tags: { nodeId },
56025
56193
  meta: {
56026
56194
  nodeId,
56027
- error: errMsg(err)
56195
+ error: errMsg$1(err)
56028
56196
  }
56029
56197
  });
56030
56198
  return {
@@ -56071,7 +56239,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
56071
56239
  } catch (err) {
56072
56240
  this.ctx.logger.warn("resetNodePipelineDefaults: executor clearDeviceOverrides failed (node offline?)", {
56073
56241
  tags: { nodeId: node },
56074
- meta: { error: errMsg(err) }
56242
+ meta: { error: errMsg$1(err) }
56075
56243
  });
56076
56244
  }
56077
56245
  this.settingsStore.invalidateCatalog();
@@ -56082,7 +56250,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
56082
56250
  } catch (err) {
56083
56251
  this.ctx.logger.warn("resetNodePipelineDefaults: effective-model probe failed (node offline?)", {
56084
56252
  tags: { nodeId: node },
56085
- meta: { error: errMsg(err) }
56253
+ meta: { error: errMsg$1(err) }
56086
56254
  });
56087
56255
  }
56088
56256
  this.ctx.logger.info("node pipeline reset to hardware-aware defaults", {
@@ -56299,7 +56467,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
56299
56467
  tags: { deviceId },
56300
56468
  meta: {
56301
56469
  capName,
56302
- error: errMsg(err)
56470
+ error: errMsg$1(err)
56303
56471
  }
56304
56472
  });
56305
56473
  return true;