@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.js CHANGED
@@ -5391,7 +5391,7 @@ var ZodIssueCode = {
5391
5391
  var ZodFirstPartyTypeKind;
5392
5392
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5393
5393
  //#endregion
5394
- //#region ../types/dist/sleep-e0RweZzn.mjs
5394
+ //#region ../types/dist/sleep-BDR76Ykr.mjs
5395
5395
  /**
5396
5396
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5397
5397
  * window to float samples (D455).
@@ -7929,7 +7929,7 @@ import { errMsg } from '@camstack/types'
7929
7929
  * Extract a human-readable message from an unknown error value.
7930
7930
  * Replaces the ubiquitous `errMsg(err)` pattern.
7931
7931
  */
7932
- function errMsg(err) {
7932
+ function errMsg$1(err) {
7933
7933
  if (err instanceof Error) return err.message;
7934
7934
  if (typeof err === "string") return err;
7935
7935
  return String(err);
@@ -18789,6 +18789,48 @@ var NcAlarmConfigSchema = object({
18789
18789
  settings: NcAlarmSettingsSchema,
18790
18790
  coverage: array(NcAlarmModeCoverageSchema)
18791
18791
  });
18792
+ /**
18793
+ * ONE rule's demand on ONE camera's clip ring.
18794
+ *
18795
+ * A rule, not a camera: the broker takes the MAX over the asks that reach a
18796
+ * camera, so the answer stays a faithful description of the rules and the
18797
+ * bounding (the byte budget, the broker's own ceiling) stays where the cost
18798
+ * lives. A camera that appears in no ask is being told **nothing** — which is
18799
+ * a different thing from never having been told, and only the envelope
18800
+ * (`rulesLoaded`) can tell those apart.
18801
+ */
18802
+ var NcClipRetentionAskSchema = object({
18803
+ /**
18804
+ * The camera this ask is about. **Absent = every camera**, which is what a
18805
+ * rule with no `conditions.devices` means: it can fire anywhere, so it is
18806
+ * asking everywhere.
18807
+ */
18808
+ deviceId: number().int().nonnegative().optional(),
18809
+ /** Seconds of history the rule needs held for it. Never zero — a rule that
18810
+ * needs nothing produces no ask at all. */
18811
+ seconds: number().min(0).max(60),
18812
+ /** The profile the rule cuts from, when it named one. Absent = the cheapest
18813
+ * assigned, which is what the cut defaults to. */
18814
+ profile: CamProfileSchema.optional(),
18815
+ /** Who is asking — so a retention the operator did not expect names a rule. */
18816
+ ruleId: string(),
18817
+ ruleName: string(),
18818
+ /** Why this many seconds: the rule's own window, or the occupancy ceiling. */
18819
+ reason: _enum(["window", "occupancy"])
18820
+ });
18821
+ /**
18822
+ * The whole answer, with the one bit that keeps absence from reading as zero.
18823
+ *
18824
+ * `rulesLoaded` is false until the rule ledger has completed a load at least
18825
+ * once. A centre that is up but has not read its rules yet answers with an
18826
+ * empty ask list that means nothing at all — applying it would drop every
18827
+ * camera's ring to zero for the first events after a restart, which is the
18828
+ * footage this mechanism exists to keep.
18829
+ */
18830
+ var NcClipRetentionPlanSchema = object({
18831
+ rulesLoaded: boolean(),
18832
+ asks: array(NcClipRetentionAskSchema).readonly()
18833
+ });
18792
18834
  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 }), {
18793
18835
  kind: "mutation",
18794
18836
  auth: "admin",
@@ -18809,7 +18851,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
18809
18851
  }), object({ success: literal(true) }), {
18810
18852
  kind: "mutation",
18811
18853
  auth: "admin"
18812
- }), method(object({}), object({ mutedDeviceIds: array(number().int()).readonly() }), { auth: "admin" }), method(object({
18854
+ }), method(object({}), NcClipRetentionPlanSchema, { auth: "admin" }), method(object({}), object({ mutedDeviceIds: array(number().int()).readonly() }), { auth: "admin" }), method(object({
18813
18855
  deviceId: number().int(),
18814
18856
  muted: boolean()
18815
18857
  }), object({ success: literal(true) }), {
@@ -35895,6 +35937,12 @@ Object.freeze({
35895
35937
  addonId: null,
35896
35938
  access: "view"
35897
35939
  },
35940
+ "notificationRules.getClipRetentionAsks": {
35941
+ capName: "notification-rules",
35942
+ capScope: "system",
35943
+ addonId: null,
35944
+ access: "view"
35945
+ },
35898
35946
  "notificationRules.getConditionCatalog": {
35899
35947
  capName: "notification-rules",
35900
35948
  capScope: "system",
@@ -42054,7 +42102,7 @@ var AudioSubscriptionController = class {
42054
42102
  } catch (err) {
42055
42103
  this.deps.logger.error("audio re-attach failed", {
42056
42104
  tags: { deviceId },
42057
- meta: { error: errMsg(err) }
42105
+ meta: { error: errMsg$1(err) }
42058
42106
  });
42059
42107
  }
42060
42108
  }
@@ -42165,7 +42213,7 @@ var AudioSubscriptionController = class {
42165
42213
  this.closeMotionAudioWindow(deviceId, "motion-cooldown-elapsed").catch((err) => {
42166
42214
  this.deps.logger.warn("lazy audio: cooldown teardown failed", {
42167
42215
  tags: { deviceId },
42168
- meta: { error: errMsg(err) }
42216
+ meta: { error: errMsg$1(err) }
42169
42217
  });
42170
42218
  });
42171
42219
  }, cooldownMs);
@@ -42184,7 +42232,7 @@ var AudioSubscriptionController = class {
42184
42232
  this.closeMotionAudioWindow(deviceId, "quiet-window-elapsed").catch((err) => {
42185
42233
  this.deps.logger.warn("lazy audio: quiet-window teardown failed", {
42186
42234
  tags: { deviceId },
42187
- meta: { error: errMsg(err) }
42235
+ meta: { error: errMsg$1(err) }
42188
42236
  });
42189
42237
  });
42190
42238
  }, windowMs);
@@ -42355,7 +42403,7 @@ var AudioSubscriptionController = class {
42355
42403
  meta: {
42356
42404
  audioNodeId,
42357
42405
  brokerId: audioBrokerId,
42358
- error: errMsg(err)
42406
+ error: errMsg$1(err)
42359
42407
  }
42360
42408
  });
42361
42409
  });
@@ -43375,7 +43423,7 @@ var LoadShedController = class LoadShedController {
43375
43423
  if (await this.tryClusterRelocate(deviceId).catch((err) => {
43376
43424
  this.deps.logger.warn("Load management: cluster relocate failed", {
43377
43425
  tags: { deviceId },
43378
- meta: { error: errMsg(err) }
43426
+ meta: { error: errMsg$1(err) }
43379
43427
  });
43380
43428
  return false;
43381
43429
  })) {
@@ -43389,7 +43437,7 @@ var LoadShedController = class LoadShedController {
43389
43437
  this.deps.api()?.pipelineRunner.detachCamera.mutate({ deviceId }).catch((err) => {
43390
43438
  this.deps.logger.warn("Load management: detachCamera failed", {
43391
43439
  tags: { deviceId },
43392
- meta: { error: errMsg(err) }
43440
+ meta: { error: errMsg$1(err) }
43393
43441
  });
43394
43442
  });
43395
43443
  this.ensureLoadShedResumeTimer();
@@ -43421,7 +43469,7 @@ var LoadShedController = class LoadShedController {
43421
43469
  tags: { deviceId },
43422
43470
  meta: {
43423
43471
  from: currentNode,
43424
- error: errMsg(err)
43472
+ error: errMsg$1(err)
43425
43473
  }
43426
43474
  });
43427
43475
  });
@@ -43464,7 +43512,7 @@ var LoadShedController = class LoadShedController {
43464
43512
  this.deps.redispatchSingleCamera(deviceId).catch((err) => {
43465
43513
  this.deps.logger.warn("Load management: auto-resume dispatch failed", {
43466
43514
  tags: { deviceId },
43467
- meta: { error: errMsg(err) }
43515
+ meta: { error: errMsg$1(err) }
43468
43516
  });
43469
43517
  });
43470
43518
  }
@@ -43625,7 +43673,7 @@ var AgentLoadService = class AgentLoadService {
43625
43673
  ms,
43626
43674
  outcome: "failed",
43627
43675
  load: null,
43628
- error: errMsg(outcome.error)
43676
+ error: errMsg$1(outcome.error)
43629
43677
  };
43630
43678
  return {
43631
43679
  nodeId,
@@ -44629,7 +44677,7 @@ function warnSampled(deps, deviceId, source, message, meta) {
44629
44677
  function warnUnreachable(deps, deviceId, source, err) {
44630
44678
  warnSampled(deps, deviceId, source, UNREACHABLE_MESSAGE, {
44631
44679
  source,
44632
- error: errMsg(err)
44680
+ error: errMsg$1(err)
44633
44681
  });
44634
44682
  }
44635
44683
  /**
@@ -45874,6 +45922,89 @@ function sameFeatures(a, b) {
45874
45922
  return b.every((f) => held.has(f));
45875
45923
  }
45876
45924
  //#endregion
45925
+ //#region src/onboard-forwarding-reconcile.ts
45926
+ /** The `detectionSources` member that means "this camera's own firmware". */
45927
+ var ONBOARD_DETECTION_SOURCE = "onboard";
45928
+ /**
45929
+ * What an ABSENT `detectionSources` means. `CameraDetectionConfig` declares the
45930
+ * field optional and its own contract as "absent is `['pipeline']` all the way
45931
+ * down" — the resolver always fills it, so this only covers the hand-built
45932
+ * configs, and it reads them the same way the runner does.
45933
+ */
45934
+ var DETECTION_SOURCES_WHEN_ABSENT = ["pipeline"];
45935
+ function errMsg(err) {
45936
+ return err instanceof Error ? err.message : String(err);
45937
+ }
45938
+ /**
45939
+ * Put the vendor forwarding flag back where `detectionSources` says it belongs.
45940
+ * Never throws — a camera's attach is not failed by a mechanism that could not
45941
+ * be reached, it is reported.
45942
+ */
45943
+ async function reconcileOnboardForwarding(input, deps) {
45944
+ const { deviceId, detectionSources } = input;
45945
+ const wantsOnboard = detectionSources.includes(ONBOARD_DETECTION_SOURCE);
45946
+ const log = deps.logger.withTags({ deviceId });
45947
+ let hasCap;
45948
+ try {
45949
+ hasCap = await deps.hasNativeObjectDetectionCap(deviceId);
45950
+ } catch (err) {
45951
+ log.warn("onboard forwarding not reconciled — could not tell whether the camera has the cap", { meta: {
45952
+ wantsOnboard,
45953
+ detectionSources: [...detectionSources],
45954
+ error: errMsg(err)
45955
+ } });
45956
+ return {
45957
+ kind: "read-failed",
45958
+ wantsOnboard
45959
+ };
45960
+ }
45961
+ if (!hasCap) return {
45962
+ kind: "no-cap",
45963
+ wantsOnboard
45964
+ };
45965
+ let current;
45966
+ try {
45967
+ current = await deps.readForwardingEnabled(deviceId);
45968
+ } catch (err) {
45969
+ log.warn("onboard forwarding not reconciled — the vendor flag could not be read", { meta: {
45970
+ wantsOnboard,
45971
+ detectionSources: [...detectionSources],
45972
+ error: errMsg(err)
45973
+ } });
45974
+ return {
45975
+ kind: "read-failed",
45976
+ wantsOnboard
45977
+ };
45978
+ }
45979
+ if (current === wantsOnboard) return {
45980
+ kind: "aligned",
45981
+ wantsOnboard
45982
+ };
45983
+ try {
45984
+ await deps.writeForwardingEnabled(deviceId, wantsOnboard);
45985
+ } catch (err) {
45986
+ log.warn("onboard forwarding drifted and the repair failed", { meta: {
45987
+ was: current,
45988
+ wanted: wantsOnboard,
45989
+ detectionSources: [...detectionSources],
45990
+ error: errMsg(err)
45991
+ } });
45992
+ return {
45993
+ kind: "write-failed",
45994
+ wantsOnboard
45995
+ };
45996
+ }
45997
+ log.info("onboard forwarding flag put back to match the camera pick", { meta: {
45998
+ was: current,
45999
+ now: wantsOnboard,
46000
+ detectionSources: [...detectionSources]
46001
+ } });
46002
+ return {
46003
+ kind: "repaired",
46004
+ wantsOnboard
46005
+ };
46006
+ }
46007
+ //#endregion
45877
46008
  //#region src/watchdog-camera.ts
45878
46009
  /**
45879
46010
  * Derive the watchdog camera descriptor from a runner config. Captures which
@@ -46043,7 +46174,7 @@ var DetectionWiringController = class {
46043
46174
  try {
46044
46175
  raw = await this.deps.ctx().settings.readDeviceStore(deviceId);
46045
46176
  } catch (err) {
46046
- const msg = errMsg(err);
46177
+ const msg = errMsg$1(err);
46047
46178
  this.deps.logger.error("resolveDeviceDetectionSettings failed", {
46048
46179
  tags: { deviceId },
46049
46180
  meta: { error: msg }
@@ -46074,7 +46205,7 @@ var DetectionWiringController = class {
46074
46205
  motionDetectionEnabled
46075
46206
  });
46076
46207
  } catch (err) {
46077
- const msg = errMsg(err);
46208
+ const msg = errMsg$1(err);
46078
46209
  this.deps.logger.error("resolveDeviceDetectionSettings narrowing failed", {
46079
46210
  tags: { deviceId },
46080
46211
  meta: { error: msg }
@@ -46104,7 +46235,7 @@ var DetectionWiringController = class {
46104
46235
  } catch (err) {
46105
46236
  this.deps.logger.debug("fetchAssignedProfiles: slot read failed (transient) — treating as unknown", {
46106
46237
  tags: { deviceId },
46107
- meta: { error: errMsg(err) }
46238
+ meta: { error: errMsg$1(err) }
46108
46239
  });
46109
46240
  return null;
46110
46241
  }
@@ -46124,6 +46255,41 @@ var DetectionWiringController = class {
46124
46255
  return buildDetectionConfigFromInputs(resolved, assigned);
46125
46256
  }
46126
46257
  /**
46258
+ * Make the vendor's onboard-AI forwarding flag agree with this camera's
46259
+ * `detectionSources` pick — in both directions. See
46260
+ * `onboard-forwarding-reconcile.ts` for why the save-time write is not
46261
+ * enough (the flag is device state and a provider restart re-seeds it OFF,
46262
+ * measured on all seven Reolink cameras of the live hub).
46263
+ *
46264
+ * Never throws: a mechanism that could not be reached is reported, it does
46265
+ * not fail the camera's attach.
46266
+ */
46267
+ async reconcileOnboardForwarding(deviceId, detectionSources) {
46268
+ return reconcileOnboardForwarding({
46269
+ deviceId,
46270
+ detectionSources
46271
+ }, {
46272
+ hasNativeObjectDetectionCap: (id) => this.deps.deviceHasNativeObjectDetectionCap(id),
46273
+ readForwardingEnabled: async (id) => {
46274
+ const api = this.deps.api();
46275
+ if (!api) throw new Error("orchestrator: no api — cannot read the onboard forwarding flag");
46276
+ const raw = await api.nativeObjectDetection.getStatus.query({ deviceId: id });
46277
+ const parsed = NativeObjectDetectionStatusSchema.safeParse(raw);
46278
+ if (!parsed.success) throw new Error(`orchestrator: nativeObjectDetection.getStatus returned an unusable status — ${parsed.error.message}`);
46279
+ return parsed.data.enabled;
46280
+ },
46281
+ writeForwardingEnabled: async (id, enabled) => {
46282
+ const api = this.deps.api();
46283
+ if (!api) throw new Error("orchestrator: no api — cannot write the onboard forwarding flag");
46284
+ await api.nativeObjectDetection.setEnabled.mutate({
46285
+ deviceId: id,
46286
+ enabled
46287
+ });
46288
+ },
46289
+ logger: this.deps.logger
46290
+ });
46291
+ }
46292
+ /**
46127
46293
  * Start detection for a camera: dispatch to runner via the orchestrator
46128
46294
  * local path and subscribe to the audio broker if audio is enabled.
46129
46295
  */
@@ -46135,6 +46301,7 @@ var DetectionWiringController = class {
46135
46301
  await this.stopDetection(deviceId);
46136
46302
  }
46137
46303
  this.activeDetections.set(deviceId, config);
46304
+ await this.reconcileOnboardForwarding(deviceId, config.detectionSources ?? DETECTION_SOURCES_WHEN_ABSENT);
46138
46305
  if (!config.pipelineEnabled || config.detectionMode === "disabled") if (!config.pipelineEnabled) log.info("object detection switched off — no attach, no decode session", { meta: { detectionMode: config.detectionMode } });
46139
46306
  else log.info("detection mode disabled — no standing attach, no decode session", { meta: {
46140
46307
  detectionMode: config.detectionMode,
@@ -46144,7 +46311,7 @@ var DetectionWiringController = class {
46144
46311
  if (config.motionSources.includes("analyzer")) try {
46145
46312
  await this.deps.session.ensureMotionWatch(deviceId, config);
46146
46313
  } catch (err) {
46147
- log.error("ensureMotionWatch failed", { meta: { error: errMsg(err) } });
46314
+ log.error("ensureMotionWatch failed", { meta: { error: errMsg$1(err) } });
46148
46315
  }
46149
46316
  log.info("detection armed (session-time) — watching for motion", { meta: { motion: config.motionSources.join("+") } });
46150
46317
  } else {
@@ -46163,7 +46330,7 @@ var DetectionWiringController = class {
46163
46330
  const result = await this.deps.placement.dispatchCamera(runnerConfig);
46164
46331
  if (result.kind === "assigned") dispatchedNodeId = result.agentNodeId;
46165
46332
  } catch (err) {
46166
- const msg = errMsg(err);
46333
+ const msg = errMsg$1(err);
46167
46334
  log.error("dispatchCamera failed", { meta: { error: msg } });
46168
46335
  }
46169
46336
  if (dispatchedNodeId && (dispatchedNodeId !== hydrateNodeId || (runnerConfig.steps?.length ?? 0) === 0)) try {
@@ -46192,13 +46359,13 @@ var DetectionWiringController = class {
46192
46359
  });
46193
46360
  }
46194
46361
  } catch (err) {
46195
- log.warn("startDetection: post-dispatch re-resolve failed", { meta: { error: errMsg(err) } });
46362
+ log.warn("startDetection: post-dispatch re-resolve failed", { meta: { error: errMsg$1(err) } });
46196
46363
  }
46197
46364
  }
46198
46365
  try {
46199
46366
  await this.deps.audio.resubscribe(deviceId, config);
46200
46367
  } catch (err) {
46201
- const msg = errMsg(err);
46368
+ const msg = errMsg$1(err);
46202
46369
  log.error("subscribeAudioStream failed", { meta: { error: msg } });
46203
46370
  }
46204
46371
  if (config.detectionMode !== "on-motion") log.info("Detection dispatched", { meta: {
@@ -46214,7 +46381,7 @@ var DetectionWiringController = class {
46214
46381
  try {
46215
46382
  await this.deps.placement.releaseCamera({ deviceId });
46216
46383
  } catch (err) {
46217
- const msg = errMsg(err);
46384
+ const msg = errMsg$1(err);
46218
46385
  this.deps.logger.error("releaseCamera failed", {
46219
46386
  tags: { deviceId },
46220
46387
  meta: { error: msg }
@@ -46240,7 +46407,7 @@ var DetectionWiringController = class {
46240
46407
  } catch (err) {
46241
46408
  this.deps.logger.warn("failed to clear per-device orchestrator settings on removal", {
46242
46409
  tags: { deviceId },
46243
- meta: { error: errMsg(err) }
46410
+ meta: { error: errMsg$1(err) }
46244
46411
  });
46245
46412
  }
46246
46413
  this.deps.logger.info("Purged pipeline config for removed device", { tags: { deviceId } });
@@ -46264,7 +46431,7 @@ var DetectionWiringController = class {
46264
46431
  } catch (err) {
46265
46432
  this.deps.logger.debug("device existence check failed — proceeding as before", {
46266
46433
  tags: { deviceId },
46267
- meta: { error: errMsg(err) }
46434
+ meta: { error: errMsg$1(err) }
46268
46435
  });
46269
46436
  return false;
46270
46437
  }
@@ -46381,7 +46548,7 @@ var DetectionWiringController = class {
46381
46548
  await this.deps.attachOn(assignment.agentNodeId, nextConfig);
46382
46549
  log.info("pipeline.camera-updated: hot-reloaded", { tags: { nodeId: assignment.agentNodeId } });
46383
46550
  } catch (err) {
46384
- const msg = errMsg(err);
46551
+ const msg = errMsg$1(err);
46385
46552
  log.error("pipeline.camera-updated: attachOn failed", {
46386
46553
  tags: { nodeId: assignment.agentNodeId },
46387
46554
  meta: { error: msg }
@@ -46457,7 +46624,7 @@ var DetectionWiringController = class {
46457
46624
  this.deps.audio.resubscribe(deviceId, audioCfg).catch((err) => {
46458
46625
  this.deps.logger.warn("watchdog audio re-subscribe failed", {
46459
46626
  tags: { deviceId },
46460
- meta: { error: errMsg(err) }
46627
+ meta: { error: errMsg$1(err) }
46461
46628
  });
46462
46629
  });
46463
46630
  }
@@ -46656,7 +46823,7 @@ var DeviceConfigContributions = class {
46656
46823
  issue: configIssue
46657
46824
  } });
46658
46825
  this.deps.topology.refreshNodeCapabilities().then(() => this.deps.redispatchAllActiveCameras("ingest-owner-changed")).catch((err) => {
46659
- this.deps.ctx().logger.warn("ingest-owner-changed re-dispatch failed", { meta: { error: errMsg(err) } });
46826
+ this.deps.ctx().logger.warn("ingest-owner-changed re-dispatch failed", { meta: { error: errMsg$1(err) } });
46660
46827
  });
46661
46828
  }
46662
46829
  this.deps.clearOnSettingsChange();
@@ -47396,7 +47563,7 @@ var PlacementService = class {
47396
47563
  async releaseCamera(input) {
47397
47564
  const current = this.deps.ledger.getAssignment(input.deviceId);
47398
47565
  if (current) await this.detachOn(current.agentNodeId, input.deviceId).catch((err) => {
47399
- const msg = errMsg(err);
47566
+ const msg = errMsg$1(err);
47400
47567
  this.deps.ctx().logger.debug("releaseCamera detach failed", {
47401
47568
  tags: { deviceId: input.deviceId },
47402
47569
  meta: { error: msg }
@@ -47424,7 +47591,7 @@ var PlacementService = class {
47424
47591
  pipelineNodeId: input.agentNodeId,
47425
47592
  [PREFERRED_AGENT_SETTING]: null
47426
47593
  }).catch((err) => {
47427
- const msg = errMsg(err);
47594
+ const msg = errMsg$1(err);
47428
47595
  ctx.logger.warn("assignPipeline: failed to persist pin", {
47429
47596
  tags: { deviceId: input.deviceId },
47430
47597
  meta: { error: msg }
@@ -47456,7 +47623,7 @@ var PlacementService = class {
47456
47623
  }
47457
47624
  const current = this.deps.ledger.getAssignment(input.deviceId);
47458
47625
  if (current && current.agentNodeId !== input.agentNodeId) await this.detachOn(current.agentNodeId, input.deviceId).catch((err) => {
47459
- const msg = errMsg(err);
47626
+ const msg = errMsg$1(err);
47460
47627
  ctx.logger.debug("assignPipeline detach-old failed", {
47461
47628
  tags: { deviceId: input.deviceId },
47462
47629
  meta: { error: msg }
@@ -47481,7 +47648,7 @@ var PlacementService = class {
47481
47648
  await ctx.settings?.writeDeviceStore(input.deviceId, { pipelineDeviceKey: clearing ? "auto" : input.deviceKey }).catch((err) => {
47482
47649
  ctx.logger.warn("setPipelineDevicePin: failed to persist device pin", {
47483
47650
  tags: { deviceId: input.deviceId },
47484
- meta: { error: errMsg(err) }
47651
+ meta: { error: errMsg$1(err) }
47485
47652
  });
47486
47653
  });
47487
47654
  const sessionNode = this.deps.activeSessionNode(input.deviceId);
@@ -47504,7 +47671,7 @@ var PlacementService = class {
47504
47671
  [PREFERRED_AGENT_SETTING]: null,
47505
47672
  pipelineNodeId: "auto"
47506
47673
  }).catch((err) => {
47507
- const msg = errMsg(err);
47674
+ const msg = errMsg$1(err);
47508
47675
  ctx.logger.warn("unassignPipeline: failed to clear pin", {
47509
47676
  tags: { deviceId: input.deviceId },
47510
47677
  meta: { error: msg }
@@ -47525,7 +47692,7 @@ var PlacementService = class {
47525
47692
  else {
47526
47693
  const targetNodeId = decision.agentNodeId;
47527
47694
  if (current && current.agentNodeId !== targetNodeId) await this.detachOn(current.agentNodeId, input.deviceId).catch((err) => {
47528
- const msg = errMsg(err);
47695
+ const msg = errMsg$1(err);
47529
47696
  ctx.logger.debug("unassignPipeline detach-old failed", {
47530
47697
  tags: { deviceId: input.deviceId },
47531
47698
  meta: { error: msg }
@@ -47545,7 +47712,7 @@ var PlacementService = class {
47545
47712
  }
47546
47713
  }
47547
47714
  if (current) await this.detachOn(current.agentNodeId, input.deviceId).catch((err) => {
47548
- const msg = errMsg(err);
47715
+ const msg = errMsg$1(err);
47549
47716
  ctx.logger.debug("unassignPipeline detach failed", {
47550
47717
  tags: { deviceId: input.deviceId },
47551
47718
  meta: { error: msg }
@@ -47564,7 +47731,7 @@ var PlacementService = class {
47564
47731
  async runAutoRebalance() {
47565
47732
  if (!this.deps.ctxIfReady()) return;
47566
47733
  await this.deps.reconcilePlacementFromRunners().catch((err) => {
47567
- this.deps.ctx().logger.debug("auto-rebalance: attachment reconcile failed", { meta: { error: errMsg(err) } });
47734
+ this.deps.ctx().logger.debug("auto-rebalance: attachment reconcile failed", { meta: { error: errMsg$1(err) } });
47568
47735
  });
47569
47736
  if (this.autoRebalanceInFlight) return;
47570
47737
  if (this.deps.topology.enabledNodes.length < 2) return;
@@ -47573,7 +47740,7 @@ var PlacementService = class {
47573
47740
  const { migrated } = await this.rebalance({ minImprovement: AUTO_REBALANCE_MIN_IMPROVEMENT });
47574
47741
  if (migrated > 0) this.deps.ctx().logger.info("auto-rebalance: corrected placement drift", { meta: { migrated } });
47575
47742
  } catch (err) {
47576
- this.deps.ctx().logger.debug("auto-rebalance pass failed", { meta: { error: errMsg(err) } });
47743
+ this.deps.ctx().logger.debug("auto-rebalance pass failed", { meta: { error: errMsg$1(err) } });
47577
47744
  } finally {
47578
47745
  this.autoRebalanceInFlight = false;
47579
47746
  }
@@ -47624,7 +47791,7 @@ var PlacementService = class {
47624
47791
  }
47625
47792
  if (current) {
47626
47793
  await this.detachOn(current.agentNodeId, deviceId).catch((err) => {
47627
- const msg = errMsg(err);
47794
+ const msg = errMsg$1(err);
47628
47795
  ctx.logger.debug("rebalance detach-old failed", {
47629
47796
  tags: { deviceId },
47630
47797
  meta: { error: msg }
@@ -47951,7 +48118,7 @@ var NodeLifecycleHandler = class {
47951
48118
  nodeId: decision.agentNodeId
47952
48119
  } });
47953
48120
  } catch (err) {
47954
- const msg = errMsg(err);
48121
+ const msg = errMsg$1(err);
47955
48122
  this.deps.logger.error("Failover: attach failed", {
47956
48123
  tags: {
47957
48124
  deviceId,
@@ -47981,7 +48148,7 @@ var NodeLifecycleHandler = class {
47981
48148
  this.deps.schedulePendingRetry();
47982
48149
  if (failoverPolicy.onReconnect === "rebalance") {
47983
48150
  await this.deps.rebalance().catch((err) => {
47984
- const msg = errMsg(err);
48151
+ const msg = errMsg$1(err);
47985
48152
  this.deps.logger.error("rebalance after reconnect failed", { meta: { error: msg } });
47986
48153
  });
47987
48154
  return;
@@ -48007,7 +48174,7 @@ var NodeLifecycleHandler = class {
48007
48174
  this.deps.ledger.recordAssignment(deviceId, nodeId, "failover", false);
48008
48175
  restored++;
48009
48176
  } catch (err) {
48010
- const msg = errMsg(err);
48177
+ const msg = errMsg$1(err);
48011
48178
  this.deps.logger.error("restore attach failed", {
48012
48179
  tags: {
48013
48180
  deviceId,
@@ -48097,7 +48264,7 @@ var NodeLifecycleHandler = class {
48097
48264
  deviceId,
48098
48265
  nodeId
48099
48266
  },
48100
- meta: { error: errMsg(err) }
48267
+ meta: { error: errMsg$1(err) }
48101
48268
  });
48102
48269
  }
48103
48270
  this.deps.logger.info("readiness: detection-pipeline reseeded agent defaults + redispatched cameras", {
@@ -48111,7 +48278,7 @@ var NodeLifecycleHandler = class {
48111
48278
  this.reattachStaleEmpties(nodeId).catch((err) => {
48112
48279
  this.deps.logger.debug("readiness deferred sweep failed", {
48113
48280
  tags: { nodeId },
48114
- meta: { error: errMsg(err) }
48281
+ meta: { error: errMsg$1(err) }
48115
48282
  });
48116
48283
  });
48117
48284
  }, 3e3);
@@ -48122,7 +48289,7 @@ var NodeLifecycleHandler = class {
48122
48289
  tags: { nodeId },
48123
48290
  meta: {
48124
48291
  epoch: t.epoch,
48125
- error: errMsg(err)
48292
+ error: errMsg$1(err)
48126
48293
  }
48127
48294
  });
48128
48295
  }
@@ -48161,7 +48328,7 @@ var NodeLifecycleHandler = class {
48161
48328
  deviceId,
48162
48329
  nodeId
48163
48330
  },
48164
- meta: { error: errMsg(err) }
48331
+ meta: { error: errMsg$1(err) }
48165
48332
  });
48166
48333
  }
48167
48334
  }
@@ -48483,7 +48650,7 @@ var NodeStressController = class NodeStressController {
48483
48650
  if (this.timer) return;
48484
48651
  this.timer = setInterval(() => {
48485
48652
  this.sweep().catch((err) => {
48486
- this.deps.logger.warn("node-stress sweep failed", { meta: { error: errMsg(err) } });
48653
+ this.deps.logger.warn("node-stress sweep failed", { meta: { error: errMsg$1(err) } });
48487
48654
  });
48488
48655
  }, NodeStressController.SWEEP_INTERVAL_MS);
48489
48656
  }
@@ -48656,7 +48823,7 @@ var NodeStressController = class NodeStressController {
48656
48823
  meta: {
48657
48824
  from: plan.fromNodeId,
48658
48825
  to: plan.toNodeId,
48659
- error: errMsg(err)
48826
+ error: errMsg$1(err)
48660
48827
  }
48661
48828
  });
48662
48829
  } finally {
@@ -49353,7 +49520,7 @@ var NodeTopologyService = class {
49353
49520
  try {
49354
49521
  blob = await this.deps.readAgentSettingsMap();
49355
49522
  } catch (err) {
49356
- this.deps.logger.warn("refreshNodeCapabilities: agent settings read failed", { meta: { error: errMsg(err) } });
49523
+ this.deps.logger.warn("refreshNodeCapabilities: agent settings read failed", { meta: { error: errMsg$1(err) } });
49357
49524
  }
49358
49525
  const nodeIds = new Set(["hub"]);
49359
49526
  for (const nodeId of Object.keys(blob)) if (typeof nodeId === "string" && nodeId.length > 0 && !nodeId.includes("/")) nodeIds.add(nodeId);
@@ -49411,7 +49578,7 @@ function wireOrchestratorSubscriptions(deps) {
49411
49578
  const unsubInferenceResult = deps.eventBus.subscribe({ category: EventCategory.PipelineInferenceResult }, (event) => {
49412
49579
  if (!isEvent(event, EventCategory.PipelineInferenceResult)) return;
49413
49580
  deps.handleInferenceResult(event.data).catch((err) => {
49414
- const msg = errMsg(err);
49581
+ const msg = errMsg$1(err);
49415
49582
  deps.logger.error("PipelineInferenceResult post-processing failed", {
49416
49583
  tags: { deviceId: event.data.deviceId },
49417
49584
  meta: { error: msg }
@@ -49430,7 +49597,7 @@ function wireOrchestratorSubscriptions(deps) {
49430
49597
  deps.logger.info("received onProfileSlotsChanged", { tags: { deviceId } });
49431
49598
  deps.handleDeviceRegistered(deviceId).catch((err) => {
49432
49599
  if (isTornDown) return;
49433
- const msg = errMsg(err);
49600
+ const msg = errMsg$1(err);
49434
49601
  deps.logger.error("handleDeviceRegistered failed", {
49435
49602
  tags: { deviceId },
49436
49603
  meta: { error: msg }
@@ -49442,7 +49609,7 @@ function wireOrchestratorSubscriptions(deps) {
49442
49609
  const unsubDeviceUnregistered = deps.eventBus.subscribe({ category: EventCategory.DeviceUnregistered }, (event) => {
49443
49610
  const { deviceId } = event.data;
49444
49611
  deps.handleDeviceUnregistered(deviceId).catch((err) => {
49445
- const msg = errMsg(err);
49612
+ const msg = errMsg$1(err);
49446
49613
  deps.logger.error("handleDeviceUnregistered failed", {
49447
49614
  tags: { deviceId },
49448
49615
  meta: { error: msg }
@@ -49454,7 +49621,7 @@ function wireOrchestratorSubscriptions(deps) {
49454
49621
  const { deviceId } = event.data;
49455
49622
  deps.handleSettingsChanged(deviceId).catch((err) => {
49456
49623
  if (isTornDown) return;
49457
- const msg = errMsg(err);
49624
+ const msg = errMsg$1(err);
49458
49625
  deps.logger.error("handleSettingsChanged failed", {
49459
49626
  tags: { deviceId },
49460
49627
  meta: { error: msg }
@@ -49464,7 +49631,7 @@ function wireOrchestratorSubscriptions(deps) {
49464
49631
  const unsubCameraUpdated = deps.eventBus.subscribe({ category: EventCategory.PipelineCameraUpdated }, (event) => {
49465
49632
  if (!isEvent(event, EventCategory.PipelineCameraUpdated)) return;
49466
49633
  deps.handlePipelineCameraUpdated(event.data.deviceId, event.data.config).catch((err) => {
49467
- const msg = errMsg(err);
49634
+ const msg = errMsg$1(err);
49468
49635
  deps.logger.error("handlePipelineCameraUpdated failed", {
49469
49636
  tags: { deviceId: event.data.deviceId },
49470
49637
  meta: { error: msg }
@@ -49477,7 +49644,7 @@ function wireOrchestratorSubscriptions(deps) {
49477
49644
  if (!(reason === "wrapper-activated" || reason === "wrapper-deactivated") || !(capName === "detection-pipeline" || capName === "audio-analysis" || capName === "motion-detection")) return;
49478
49645
  deps.handleSettingsChanged(deviceId).catch((err) => {
49479
49646
  if (isTornDown) return;
49480
- const msg = errMsg(err);
49647
+ const msg = errMsg$1(err);
49481
49648
  deps.logger.error("binding-changed re-dispatch failed", {
49482
49649
  tags: { deviceId },
49483
49650
  meta: {
@@ -49505,7 +49672,7 @@ function wireOrchestratorSubscriptions(deps) {
49505
49672
  tags: { deviceId },
49506
49673
  meta: {
49507
49674
  detected,
49508
- error: errMsg(err)
49675
+ error: errMsg$1(err)
49509
49676
  }
49510
49677
  });
49511
49678
  });
@@ -49520,7 +49687,7 @@ function wireOrchestratorSubscriptions(deps) {
49520
49687
  tags: { deviceId },
49521
49688
  meta: {
49522
49689
  detected,
49523
- error: errMsg(err)
49690
+ error: errMsg$1(err)
49524
49691
  }
49525
49692
  });
49526
49693
  });
@@ -50514,7 +50681,7 @@ var PipelineSettingsStore = class PipelineSettingsStore {
50514
50681
  } catch (err) {
50515
50682
  this.deps.logger.debug("getCatalogForAgent failed", {
50516
50683
  tags: { nodeId },
50517
- meta: { error: errMsg(err) }
50684
+ meta: { error: errMsg$1(err) }
50518
50685
  });
50519
50686
  return null;
50520
50687
  }
@@ -50577,7 +50744,7 @@ var PipelineSettingsStore = class PipelineSettingsStore {
50577
50744
  tags: { deviceId },
50578
50745
  meta: {
50579
50746
  capName: "detection-pipeline",
50580
- error: errMsg(err)
50747
+ error: errMsg$1(err)
50581
50748
  }
50582
50749
  });
50583
50750
  return true;
@@ -51300,7 +51467,7 @@ var ReconcileController = class ReconcileController {
51300
51467
  try {
51301
51468
  slots = await api.streamBroker.listAllProfileSlots.query();
51302
51469
  } catch (err) {
51303
- this.deps.logger.debug("dispatch reconcile skipped — stream-broker not ready", { meta: { error: errMsg(err) } });
51470
+ this.deps.logger.debug("dispatch reconcile skipped — stream-broker not ready", { meta: { error: errMsg$1(err) } });
51304
51471
  return;
51305
51472
  }
51306
51473
  const desired = desiredDeviceIdsFromSlots(slots);
@@ -51327,7 +51494,7 @@ var ReconcileController = class ReconcileController {
51327
51494
  } catch (err) {
51328
51495
  this.deps.logger.warn("dispatch reconcile: handleDeviceRegistered failed", {
51329
51496
  tags: { deviceId },
51330
- meta: { error: errMsg(err) }
51497
+ meta: { error: errMsg$1(err) }
51331
51498
  });
51332
51499
  }
51333
51500
  await this.reconcilePlacementFromRunners();
@@ -51355,7 +51522,7 @@ var ReconcileController = class ReconcileController {
51355
51522
  const devices = await api.deviceManager.listAll.query({ projection: "slim" });
51356
51523
  return new Set(devices.map((device) => device.id));
51357
51524
  } catch (err) {
51358
- this.deps.logger.debug("dispatch reconcile: deviceManager.listAll failed", { meta: { error: errMsg(err) } });
51525
+ this.deps.logger.debug("dispatch reconcile: deviceManager.listAll failed", { meta: { error: errMsg$1(err) } });
51359
51526
  return null;
51360
51527
  }
51361
51528
  }
@@ -51381,7 +51548,7 @@ var ReconcileController = class ReconcileController {
51381
51548
  } catch (err) {
51382
51549
  this.deps.logger.warn("dispatch reconcile: teardown of vanished device failed", {
51383
51550
  tags: { deviceId },
51384
- meta: { error: errMsg(err) }
51551
+ meta: { error: errMsg$1(err) }
51385
51552
  });
51386
51553
  }
51387
51554
  }
@@ -51438,7 +51605,7 @@ var ReconcileController = class ReconcileController {
51438
51605
  this.deps.logger.debug("placement reconcile skipped node — getLocalCameras failed", {
51439
51606
  tags: { nodeId },
51440
51607
  meta: {
51441
- error: outcome.kind === "rejected" ? errMsg(outcome.error) : "budget exceeded",
51608
+ error: outcome.kind === "rejected" ? errMsg$1(outcome.error) : "budget exceeded",
51442
51609
  ms
51443
51610
  }
51444
51611
  });
@@ -51468,7 +51635,7 @@ var ReconcileController = class ReconcileController {
51468
51635
  nodeId,
51469
51636
  deviceId
51470
51637
  },
51471
- meta: { error: errMsg(err) }
51638
+ meta: { error: errMsg$1(err) }
51472
51639
  });
51473
51640
  })));
51474
51641
  }
@@ -51510,7 +51677,7 @@ var ReconcileController = class ReconcileController {
51510
51677
  this.deps.handleDeviceRegistered(deviceId).catch((err) => {
51511
51678
  this.deps.logger.debug("slot-read retry: handleDeviceRegistered failed", {
51512
51679
  tags: { deviceId },
51513
- meta: { error: errMsg(err) }
51680
+ meta: { error: errMsg$1(err) }
51514
51681
  });
51515
51682
  });
51516
51683
  }, delay);
@@ -51588,7 +51755,7 @@ var ReconcileController = class ReconcileController {
51588
51755
  } catch (err) {
51589
51756
  this.deps.logger.warn("pending retry: dispatchCamera failed", {
51590
51757
  tags: { deviceId },
51591
- meta: { error: errMsg(err) }
51758
+ meta: { error: errMsg$1(err) }
51592
51759
  });
51593
51760
  stillPending++;
51594
51761
  }
@@ -51666,7 +51833,7 @@ var ReconcileController = class ReconcileController {
51666
51833
  await this.deps.detachOn(assignment.agentNodeId, deviceId).catch((err) => {
51667
51834
  this.deps.logger.debug("remote-health exhausted-detach failed", {
51668
51835
  tags: { deviceId },
51669
- meta: { error: errMsg(err) }
51836
+ meta: { error: errMsg$1(err) }
51670
51837
  });
51671
51838
  });
51672
51839
  return;
@@ -51689,14 +51856,14 @@ var ReconcileController = class ReconcileController {
51689
51856
  await this.deps.detachOn(assignment.agentNodeId, deviceId).catch((err) => {
51690
51857
  this.deps.logger.warn("remote-health detach failed", {
51691
51858
  tags: { deviceId },
51692
- meta: { error: errMsg(err) }
51859
+ meta: { error: errMsg$1(err) }
51693
51860
  });
51694
51861
  });
51695
51862
  this.deps.ledger.dropAssignment(deviceId, "silent");
51696
51863
  await this.deps.dispatchCamera(cfg).catch((err) => {
51697
51864
  this.deps.logger.warn("remote-health re-dispatch failed", {
51698
51865
  tags: { deviceId },
51699
- meta: { error: errMsg(err) }
51866
+ meta: { error: errMsg$1(err) }
51700
51867
  });
51701
51868
  });
51702
51869
  }
@@ -52345,7 +52512,7 @@ var SessionDispatchController = class {
52345
52512
  deviceId,
52346
52513
  nodeId: session.nodeId
52347
52514
  },
52348
- meta: { error: errMsg(err) }
52515
+ meta: { error: errMsg$1(err) }
52349
52516
  });
52350
52517
  });
52351
52518
  this.deps.dropAssignment(deviceId, "silent");
@@ -52530,7 +52697,7 @@ var SessionDispatchController = class {
52530
52697
  };
52531
52698
  if (reconcileBudgetExceeded) log.warn("detection session: placement census overran its budget — placing without it", { meta: { budgetMs: 500 } });
52532
52699
  else if (censusOutcome.kind === "rejected") log.warn("detection session: placement census failed — placing on the ledger as it is", { meta: {
52533
- error: errMsg(censusOutcome.error),
52700
+ error: errMsg$1(censusOutcome.error),
52534
52701
  reconcileMs
52535
52702
  } });
52536
52703
  const balanceStartedAt = Date.now();
@@ -52692,7 +52859,7 @@ var SessionDispatchController = class {
52692
52859
  await this.resolveSessionLifecycleLocked(deviceId, reason);
52693
52860
  }).catch((err) => {
52694
52861
  log.warn("detection session: lifecycle re-check failed", { meta: {
52695
- error: errMsg(err),
52862
+ error: errMsg$1(err),
52696
52863
  reason
52697
52864
  } });
52698
52865
  });
@@ -52797,7 +52964,7 @@ var SessionDispatchController = class {
52797
52964
  log.warn("detection session: teardown detach failed", {
52798
52965
  tags: { nodeId: session.nodeId },
52799
52966
  meta: {
52800
- error: errMsg(err),
52967
+ error: errMsg$1(err),
52801
52968
  reason
52802
52969
  }
52803
52970
  });
@@ -52880,7 +53047,7 @@ var SessionDispatchController = class {
52880
53047
  deviceId,
52881
53048
  nodeId: session.nodeId
52882
53049
  },
52883
- meta: { error: errMsg(err) }
53050
+ meta: { error: errMsg$1(err) }
52884
53051
  });
52885
53052
  });
52886
53053
  this.sessionRegistry.deregister(deviceId);
@@ -52898,7 +53065,7 @@ var SessionDispatchController = class {
52898
53065
  deviceId,
52899
53066
  nodeId: watchNodeId
52900
53067
  },
52901
- meta: { error: errMsg(err) }
53068
+ meta: { error: errMsg$1(err) }
52902
53069
  });
52903
53070
  });
52904
53071
  this.motionWatchByDevice.delete(deviceId);
@@ -53078,7 +53245,7 @@ async function sweepMirror(deps, hydrator, cameraIds) {
53078
53245
  tags: { deviceId },
53079
53246
  meta: {
53080
53247
  mirror: hydrator.mirror,
53081
- error: errMsg(err)
53248
+ error: errMsg$1(err)
53082
53249
  }
53083
53250
  });
53084
53251
  return "threw";
@@ -53118,7 +53285,7 @@ async function readCameraIds(deps) {
53118
53285
  lastError = err;
53119
53286
  }
53120
53287
  if (Date.now() >= deadline) {
53121
- 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) } });
53288
+ 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) } });
53122
53289
  return null;
53123
53290
  }
53124
53291
  await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
@@ -53759,7 +53926,7 @@ async function buildOrchestratorControllers(deps) {
53759
53926
  } catch (err) {
53760
53927
  return {
53761
53928
  kind: "unknown",
53762
- reason: errMsg(err)
53929
+ reason: errMsg$1(err)
53763
53930
  };
53764
53931
  }
53765
53932
  };
@@ -53843,14 +54010,14 @@ async function buildOrchestratorControllers(deps) {
53843
54010
  readGlobalSettings: () => globalSettings
53844
54011
  });
53845
54012
  await NodeStressMoveLedger.declare(deps.ctx().api.settingsStore).then(() => nodeStress.hydrate()).catch((err) => {
53846
- deps.ctx().logger.warn("node-stress move history unavailable — this boot starts cold", { meta: { error: errMsg(err) } });
54013
+ deps.ctx().logger.warn("node-stress move history unavailable — this boot starts cold", { meta: { error: errMsg$1(err) } });
53847
54014
  });
53848
54015
  await NodeStressLts.declare(deps.ctx().api.settingsStore).catch((err) => {
53849
- deps.ctx().logger.warn("node-stress statistics unavailable — no baseline this boot", { meta: { error: errMsg(err) } });
54016
+ deps.ctx().logger.warn("node-stress statistics unavailable — no baseline this boot", { meta: { error: errMsg$1(err) } });
53850
54017
  });
53851
54018
  const nodeStressLtsTimer = setInterval(() => {
53852
54019
  nodeStressLts.flushDue().catch((err) => {
53853
- deps.ctx().logger.warn("node-stress statistics flush failed", { meta: { error: errMsg(err) } });
54020
+ deps.ctx().logger.warn("node-stress statistics flush failed", { meta: { error: errMsg$1(err) } });
53854
54021
  });
53855
54022
  }, 6e4);
53856
54023
  nodeStress.start();
@@ -53987,7 +54154,7 @@ async function buildOrchestratorControllers(deps) {
53987
54154
  deps.applyRuntimeSettings(globalSettings);
53988
54155
  await topology.refreshNodeCapabilities();
53989
54156
  } catch (err) {
53990
- const msg = errMsg(err);
54157
+ const msg = errMsg$1(err);
53991
54158
  deps.ctx().logger.warn("orchestrator settings load failed — using defaults", { meta: { error: msg } });
53992
54159
  }
53993
54160
  const rawNodeId = deps.ctx().kernel.localNodeId ?? "hub";
@@ -54020,7 +54187,7 @@ async function buildOrchestratorControllers(deps) {
54020
54187
  nodeLifecycle.unsubscribeDetectionPipelineReadiness(nodeId);
54021
54188
  audio.markNodeOffline(nodeId);
54022
54189
  nodeLifecycle.handleNodeDisconnect(nodeId).catch((err) => {
54023
- const msg = errMsg(err);
54190
+ const msg = errMsg$1(err);
54024
54191
  deps.ctx().logger.error("failover after disconnect failed", {
54025
54192
  tags: { nodeId },
54026
54193
  meta: { error: msg }
@@ -54035,7 +54202,7 @@ async function buildOrchestratorControllers(deps) {
54035
54202
  deps.subscribeToAudioAnalyzerReadiness(nodeId);
54036
54203
  }
54037
54204
  nodeLifecycle.handleNodeConnect(nodeId).catch((err) => {
54038
- const msg = errMsg(err);
54205
+ const msg = errMsg$1(err);
54039
54206
  deps.ctx().logger.error("reconnect handling failed", {
54040
54207
  tags: { nodeId },
54041
54208
  meta: { error: msg }
@@ -54049,7 +54216,7 @@ async function buildOrchestratorControllers(deps) {
54049
54216
  meta: { capName }
54050
54217
  });
54051
54218
  nodeLifecycle.handleNodeDisconnect(nodeId).catch((err) => {
54052
- const msg = errMsg(err);
54219
+ const msg = errMsg$1(err);
54053
54220
  deps.ctx().logger.error("failover after cap-down failed", {
54054
54221
  tags: { nodeId },
54055
54222
  meta: {
@@ -54112,7 +54279,7 @@ async function buildOrchestratorControllers(deps) {
54112
54279
  doneFlag: settingsStore.bindingsMigrationDoneState,
54113
54280
  logger: deps.ctx().logger
54114
54281
  }).catch((err) => {
54115
- deps.ctxIfReady()?.logger.warn("bindings migration failed — will retry on next boot", { meta: { error: errMsg(err) } });
54282
+ deps.ctxIfReady()?.logger.warn("bindings migration failed — will retry on next boot", { meta: { error: errMsg$1(err) } });
54116
54283
  });
54117
54284
  migrateStepGating({
54118
54285
  readCameraSettings: () => settingsStore.readCameraSettingsMap(),
@@ -54123,7 +54290,7 @@ async function buildOrchestratorControllers(deps) {
54123
54290
  }).then(async () => {
54124
54291
  if (await settingsStore.applyPerNodeDeviceMigration()) deps.ctxIfReady()?.logger.info("per-(node,device) config migration applied");
54125
54292
  }).catch((err) => {
54126
- deps.ctxIfReady()?.logger.warn("step-gating / per-node-device migration failed — retry next boot", { meta: { error: errMsg(err) } });
54293
+ deps.ctxIfReady()?.logger.warn("step-gating / per-node-device migration failed — retry next boot", { meta: { error: errMsg$1(err) } });
54127
54294
  });
54128
54295
  const zoneRulesProvider = new ZoneRulesProvider({
54129
54296
  logger: deps.ctx().logger.child("zone-rules"),
@@ -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
  }
@@ -54179,7 +54346,7 @@ async function buildOrchestratorControllers(deps) {
54179
54346
  deviceId,
54180
54347
  nodeId: assignment.agentNodeId
54181
54348
  },
54182
- meta: { error: errMsg(err) }
54349
+ meta: { error: errMsg$1(err) }
54183
54350
  });
54184
54351
  });
54185
54352
  }
@@ -54195,7 +54362,7 @@ async function buildOrchestratorControllers(deps) {
54195
54362
  }],
54196
54363
  logger: deps.ctx().logger.child("zones")
54197
54364
  }).catch((err) => {
54198
- deps.ctxIfReady()?.logger.warn("zones mirror boot hydration failed", { meta: { error: errMsg(err) } });
54365
+ deps.ctxIfReady()?.logger.warn("zones mirror boot hydration failed", { meta: { error: errMsg$1(err) } });
54199
54366
  });
54200
54367
  const unsubOrchestratorSubscriptions = wireOrchestratorSubscriptions({
54201
54368
  eventBus: deps.ctx().eventBus,
@@ -54244,10 +54411,11 @@ async function buildOrchestratorControllers(deps) {
54244
54411
  isCapActiveForDevice: (deviceId, capName) => deps.isCapActiveForDevice(deviceId, capName),
54245
54412
  deviceHasOnboardMotionCap: (deviceId) => deps.deviceHasOnboardMotionCap(deviceId),
54246
54413
  deviceHasActivitySignalCap: (deviceId) => deps.deviceHasActivitySignalCap(deviceId),
54414
+ deviceHasNativeObjectDetectionCap: (deviceId) => deps.deviceHasNativeObjectDetectionCap(deviceId),
54247
54415
  deviceSettingsSchema: () => deps.deviceSettingsSchema()
54248
54416
  });
54249
54417
  await detectionWiring.hydrateFeaturesMirror().catch((err) => {
54250
- deps.ctx().logger.warn("device-features mirror not restored — this boot starts cold", { meta: { error: errMsg(err) } });
54418
+ deps.ctx().logger.warn("device-features mirror not restored — this boot starts cold", { meta: { error: errMsg$1(err) } });
54251
54419
  });
54252
54420
  return {
54253
54421
  ledger,
@@ -55320,7 +55488,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
55320
55488
  for (const deviceId of this.detectionWiring.activeDetectionDeviceIds()) try {
55321
55489
  await this.releaseCamera({ deviceId });
55322
55490
  } catch (err) {
55323
- const msg = errMsg(err);
55491
+ const msg = errMsg$1(err);
55324
55492
  this.ctx.logger.debug("releaseCamera failed during shutdown", {
55325
55493
  tags: { deviceId },
55326
55494
  meta: { error: msg }
@@ -55946,7 +56114,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
55946
56114
  tags: { nodeId },
55947
56115
  meta: {
55948
56116
  nodeId,
55949
- error: errMsg(err)
56117
+ error: errMsg$1(err)
55950
56118
  }
55951
56119
  });
55952
56120
  return null;
@@ -56052,7 +56220,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
56052
56220
  tags: { nodeId },
56053
56221
  meta: {
56054
56222
  nodeId,
56055
- error: errMsg(err)
56223
+ error: errMsg$1(err)
56056
56224
  }
56057
56225
  });
56058
56226
  return {
@@ -56099,7 +56267,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
56099
56267
  } catch (err) {
56100
56268
  this.ctx.logger.warn("resetNodePipelineDefaults: executor clearDeviceOverrides failed (node offline?)", {
56101
56269
  tags: { nodeId: node },
56102
- meta: { error: errMsg(err) }
56270
+ meta: { error: errMsg$1(err) }
56103
56271
  });
56104
56272
  }
56105
56273
  this.settingsStore.invalidateCatalog();
@@ -56110,7 +56278,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
56110
56278
  } catch (err) {
56111
56279
  this.ctx.logger.warn("resetNodePipelineDefaults: effective-model probe failed (node offline?)", {
56112
56280
  tags: { nodeId: node },
56113
- meta: { error: errMsg(err) }
56281
+ meta: { error: errMsg$1(err) }
56114
56282
  });
56115
56283
  }
56116
56284
  this.ctx.logger.info("node pipeline reset to hardware-aware defaults", {
@@ -56327,7 +56495,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
56327
56495
  tags: { deviceId },
56328
56496
  meta: {
56329
56497
  capName,
56330
- error: errMsg(err)
56498
+ error: errMsg$1(err)
56331
56499
  }
56332
56500
  });
56333
56501
  return true;