@camstack/addon-pipeline 1.2.300 → 1.2.301

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/dist/audio-analyzer/index.js +2 -2
  2. package/dist/audio-analyzer/index.mjs +2 -2
  3. package/dist/{default-detection-model-DX-p9O91.mjs → default-detection-model-JDKeiJPf.mjs} +15 -8
  4. package/dist/{default-detection-model-nKzvW7BX.js → default-detection-model-P7IIrP0a.js} +20 -7
  5. package/dist/detection-pipeline/index.js +15 -17
  6. package/dist/detection-pipeline/index.mjs +15 -17
  7. package/dist/{dist-C2WOjQsy.js → dist-BUs7H-fe.js} +12 -1
  8. package/dist/{dist-CqhrlD0m.mjs → dist-DvzAabca.mjs} +12 -1
  9. package/dist/motion-wasm/index.js +1 -1
  10. package/dist/motion-wasm/index.mjs +1 -1
  11. package/dist/{node-CZ1Z3f6z.mjs → node-DnP_6GBZ.mjs} +1 -1
  12. package/dist/{node-CiWM78Ze.js → node-DxVMyys-.js} +1 -1
  13. package/dist/pipeline-runner/index.js +129 -5
  14. package/dist/pipeline-runner/index.mjs +129 -5
  15. package/dist/{process-memory-taq9GnsO.mjs → process-memory-BMr61qT1.mjs} +1 -1
  16. package/dist/{process-memory-C0a37mXF.js → process-memory-DmYzYip-.js} +1 -1
  17. package/dist/recorder/index.js +2 -2
  18. package/dist/recorder/index.mjs +2 -2
  19. package/dist/{segment-demux-js-5Xcu3sTI.js → segment-demux-js-DANvUJgH.js} +1 -1
  20. package/dist/{segment-demux-js-Cydmp9fc.mjs → segment-demux-js-DBqdboBI.mjs} +1 -1
  21. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-C7I6DjP3.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-D0etdxl0.mjs} +1 -1
  22. package/dist/stream-broker/demux-worker-child.js +1 -1
  23. package/dist/stream-broker/demux-worker-child.mjs +1 -1
  24. package/dist/stream-broker/{hostInit-DyrGVuyu.mjs → hostInit-TY9BRVDy.mjs} +1 -1
  25. package/dist/stream-broker/index.js +3 -3
  26. package/dist/stream-broker/index.mjs +3 -3
  27. package/dist/stream-broker/remoteEntry.js +1 -1
  28. package/package.json +1 -1
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-emK7D4bc.js");
6
- const require_dist = require("../dist-C2WOjQsy.js");
7
- const require_process_memory = require("../process-memory-C0a37mXF.js");
6
+ const require_dist = require("../dist-BUs7H-fe.js");
7
+ const require_process_memory = require("../process-memory-DmYzYip-.js");
8
8
  let node_fs = require("node:fs");
9
9
  node_fs = require_chunk.__toESM(node_fs);
10
10
  let node_path = require("node:path");
@@ -1,6 +1,6 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { E as HF_BASE_URL, G as audioAnalyzerCapability, Rn as EventCategory, Ut as resolvePoolMemoryPolicy, W as audioAnalysisCapability, _n as hydrateSchema, bt as mapAudioLabelToMacro, en as errMsg, fn as audioChunkBytesPerSample, gn as expandAudioChunkToF32le, j as PoolMemoryWatchdog, n as AUDIO_BACKEND_CHOICES, p as DEFAULT_AUDIO_ANALYZER_CONFIG, sn as BaseAddon, xn as nodePin } from "../dist-CqhrlD0m.mjs";
3
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-taq9GnsO.mjs";
2
+ import { E as HF_BASE_URL, G as audioAnalyzerCapability, Rn as EventCategory, Ut as resolvePoolMemoryPolicy, W as audioAnalysisCapability, _n as hydrateSchema, bt as mapAudioLabelToMacro, en as errMsg, fn as audioChunkBytesPerSample, gn as expandAudioChunkToF32le, j as PoolMemoryWatchdog, n as AUDIO_BACKEND_CHOICES, p as DEFAULT_AUDIO_ANALYZER_CONFIG, sn as BaseAddon, xn as nodePin } from "../dist-DvzAabca.mjs";
3
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-BMr61qT1.mjs";
4
4
  import * as fs from "node:fs";
5
5
  import * as path$1 from "node:path";
6
6
  import { downloadFile } from "@camstack/system/addon-utils";
@@ -1,5 +1,11 @@
1
- import { K as audioKindId, Kt as stepModelRunsOnFormat, d as COCO_80_LABELS, f as COCO_TO_MACRO, gt as inferModelProvider, ht as hfModelUrl, r as AUDIO_MACRO_LABELS, y as DEVICE_BACKEND_TO_FORMAT } from "./dist-CqhrlD0m.mjs";
1
+ import { K as audioKindId, Kt as stepModelRunsOnFormat, d as COCO_80_LABELS, f as COCO_TO_MACRO, gt as inferModelProvider, ht as hfModelUrl, r as AUDIO_MACRO_LABELS, y as DEVICE_BACKEND_TO_FORMAT } from "./dist-DvzAabca.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
+ //#region src/detection-pipeline/registry/effective-confidence.ts
4
+ /** The default in force: the model's own floor, else the step's. */
5
+ function resolveModelDefaultConfidence(def, model) {
6
+ return model?.defaultConfidence ?? def.defaultConfidence;
7
+ }
8
+ //#endregion
3
9
  //#region src/detection-pipeline/pipeline/landmark-precision-gate.ts
4
10
  /**
5
11
  * `null` = admit. A verdict = refuse, carrying both numbers so the caller can
@@ -862,6 +868,7 @@ var FACE_DETECTION_MODELS = [
862
868
  }],
863
869
  preprocessMode: "letterbox",
864
870
  postprocessor: "yunet",
871
+ defaultConfidence: .85,
865
872
  formats: {
866
873
  onnx: {
867
874
  url: hf("faceDetection/yunet/onnx/camstack-yunet-2023mar.onnx"),
@@ -1753,7 +1760,7 @@ var AnimalClassifierStep = class {
1753
1760
  stickyOnConfidence: .7
1754
1761
  }
1755
1762
  };
1756
- getConfigSchema() {
1763
+ getConfigSchema(model) {
1757
1764
  return [{
1758
1765
  type: "multiselect",
1759
1766
  key: "enabledClasses",
@@ -1769,7 +1776,7 @@ var AnimalClassifierStep = class {
1769
1776
  key: "minConfidence",
1770
1777
  label: "Min Confidence",
1771
1778
  description: "Drop classifications whose score is below this threshold.",
1772
- default: this.definition.defaultConfidence,
1779
+ default: resolveModelDefaultConfidence(this.definition, model),
1773
1780
  min: 0,
1774
1781
  max: 1,
1775
1782
  step: .05,
@@ -1801,7 +1808,7 @@ var AnimalClassifierStep = class {
1801
1808
  * bug `packageDropEnabled` already was.
1802
1809
  */
1803
1810
  var PackageDetectionStep = class extends PipelineStepBase {
1804
- getConfigSchema() {
1811
+ getConfigSchema(model) {
1805
1812
  return [{
1806
1813
  type: "slider",
1807
1814
  key: "minConfidencePackage",
@@ -1810,19 +1817,19 @@ var PackageDetectionStep = class extends PipelineStepBase {
1810
1817
  min: 0,
1811
1818
  max: 1,
1812
1819
  step: .05,
1813
- default: this.definition.defaultConfidence,
1820
+ default: resolveModelDefaultConfidence(this.definition, model),
1814
1821
  showValue: true
1815
1822
  }];
1816
1823
  }
1817
1824
  };
1818
1825
  var ClassifierWithMinConfidence = class extends PipelineStepBase {
1819
- getConfigSchema() {
1826
+ getConfigSchema(model) {
1820
1827
  return [{
1821
1828
  type: "slider",
1822
1829
  key: "minConfidence",
1823
1830
  label: "Min Confidence",
1824
1831
  description: "Drop classifications whose score is below this threshold.",
1825
- default: this.definition.defaultConfidence,
1832
+ default: resolveModelDefaultConfidence(this.definition, model),
1826
1833
  min: 0,
1827
1834
  max: 1,
1828
1835
  step: .05,
@@ -2843,4 +2850,4 @@ function resolveDefaultDetectionModel(backend, device, format, getStepDef = getS
2843
2850
  return getDefaultModelForFormatFromDef(def, format);
2844
2851
  }
2845
2852
  //#endregion
2846
- export { resolveModelForFormat as _, buildSubtreeCanRun as a, macroGateVerdict as c, resolveFrameViewGeometry as d, ALL_PIPELINE_STEPS as f, getStepDefinition as g, getStep as h, mergeCustomModels as i, rootObjectGate as l, getDefaultModelForFormat as m, resolveDefaultDetectionModel as n, placeDetailStep as o, ALL_STEPS as p, CustomModelCatalog as r, stepsForElectedPool as s, OBJECT_DETECTION_STEP_ID as t, localFrameRegistry as u, RETIRED_MODEL_IDS as v, landmarkPrecisionVerdict as y };
2853
+ export { resolveModelForFormat as _, buildSubtreeCanRun as a, resolveModelDefaultConfidence as b, macroGateVerdict as c, resolveFrameViewGeometry as d, ALL_PIPELINE_STEPS as f, getStepDefinition as g, getStep as h, mergeCustomModels as i, rootObjectGate as l, getDefaultModelForFormat as m, resolveDefaultDetectionModel as n, placeDetailStep as o, ALL_STEPS as p, CustomModelCatalog as r, stepsForElectedPool as s, OBJECT_DETECTION_STEP_ID as t, localFrameRegistry as u, RETIRED_MODEL_IDS as v, landmarkPrecisionVerdict as y };
@@ -1,5 +1,11 @@
1
- const require_dist = require("./dist-C2WOjQsy.js");
1
+ const require_dist = require("./dist-BUs7H-fe.js");
2
2
  let node_crypto = require("node:crypto");
3
+ //#region src/detection-pipeline/registry/effective-confidence.ts
4
+ /** The default in force: the model's own floor, else the step's. */
5
+ function resolveModelDefaultConfidence(def, model) {
6
+ return model?.defaultConfidence ?? def.defaultConfidence;
7
+ }
8
+ //#endregion
3
9
  //#region src/detection-pipeline/pipeline/landmark-precision-gate.ts
4
10
  /**
5
11
  * `null` = admit. A verdict = refuse, carrying both numbers so the caller can
@@ -862,6 +868,7 @@ var FACE_DETECTION_MODELS = [
862
868
  }],
863
869
  preprocessMode: "letterbox",
864
870
  postprocessor: "yunet",
871
+ defaultConfidence: .85,
865
872
  formats: {
866
873
  onnx: {
867
874
  url: hf("faceDetection/yunet/onnx/camstack-yunet-2023mar.onnx"),
@@ -1753,7 +1760,7 @@ var AnimalClassifierStep = class {
1753
1760
  stickyOnConfidence: .7
1754
1761
  }
1755
1762
  };
1756
- getConfigSchema() {
1763
+ getConfigSchema(model) {
1757
1764
  return [{
1758
1765
  type: "multiselect",
1759
1766
  key: "enabledClasses",
@@ -1769,7 +1776,7 @@ var AnimalClassifierStep = class {
1769
1776
  key: "minConfidence",
1770
1777
  label: "Min Confidence",
1771
1778
  description: "Drop classifications whose score is below this threshold.",
1772
- default: this.definition.defaultConfidence,
1779
+ default: resolveModelDefaultConfidence(this.definition, model),
1773
1780
  min: 0,
1774
1781
  max: 1,
1775
1782
  step: .05,
@@ -1801,7 +1808,7 @@ var AnimalClassifierStep = class {
1801
1808
  * bug `packageDropEnabled` already was.
1802
1809
  */
1803
1810
  var PackageDetectionStep = class extends PipelineStepBase {
1804
- getConfigSchema() {
1811
+ getConfigSchema(model) {
1805
1812
  return [{
1806
1813
  type: "slider",
1807
1814
  key: "minConfidencePackage",
@@ -1810,19 +1817,19 @@ var PackageDetectionStep = class extends PipelineStepBase {
1810
1817
  min: 0,
1811
1818
  max: 1,
1812
1819
  step: .05,
1813
- default: this.definition.defaultConfidence,
1820
+ default: resolveModelDefaultConfidence(this.definition, model),
1814
1821
  showValue: true
1815
1822
  }];
1816
1823
  }
1817
1824
  };
1818
1825
  var ClassifierWithMinConfidence = class extends PipelineStepBase {
1819
- getConfigSchema() {
1826
+ getConfigSchema(model) {
1820
1827
  return [{
1821
1828
  type: "slider",
1822
1829
  key: "minConfidence",
1823
1830
  label: "Min Confidence",
1824
1831
  description: "Drop classifications whose score is below this threshold.",
1825
- default: this.definition.defaultConfidence,
1832
+ default: resolveModelDefaultConfidence(this.definition, model),
1826
1833
  min: 0,
1827
1834
  max: 1,
1828
1835
  step: .05,
@@ -2939,6 +2946,12 @@ Object.defineProperty(exports, "resolveFrameViewGeometry", {
2939
2946
  return resolveFrameViewGeometry;
2940
2947
  }
2941
2948
  });
2949
+ Object.defineProperty(exports, "resolveModelDefaultConfidence", {
2950
+ enumerable: true,
2951
+ get: function() {
2952
+ return resolveModelDefaultConfidence;
2953
+ }
2954
+ });
2942
2955
  Object.defineProperty(exports, "resolveModelForFormat", {
2943
2956
  enumerable: true,
2944
2957
  get: function() {
@@ -3,11 +3,11 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-emK7D4bc.js");
6
- const require_dist = require("../dist-C2WOjQsy.js");
7
- const require_node = require("../node-CiWM78Ze.js");
8
- const require_default_detection_model = require("../default-detection-model-nKzvW7BX.js");
6
+ const require_dist = require("../dist-BUs7H-fe.js");
7
+ const require_node = require("../node-DxVMyys-.js");
8
+ const require_default_detection_model = require("../default-detection-model-P7IIrP0a.js");
9
9
  const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
10
- const require_process_memory = require("../process-memory-C0a37mXF.js");
10
+ const require_process_memory = require("../process-memory-DmYzYip-.js");
11
11
  let node_os = require("node:os");
12
12
  node_os = require_chunk.__toESM(node_os);
13
13
  let node_fs = require("node:fs");
@@ -3394,7 +3394,7 @@ function buildPoolModelConfigForStep(inputs) {
3394
3394
  inputNormalization: modelEntry.inputNormalization,
3395
3395
  outputProbabilities: modelEntry.outputProbabilities,
3396
3396
  postprocessor: resolveEffectivePostprocessorForEntry(def, modelEntry),
3397
- confidence: resolvePoolConfidenceFloor(stepId, def.defaultConfidence),
3397
+ confidence: resolvePoolConfidenceFloor(stepId, require_default_detection_model.resolveModelDefaultConfidence(def, modelEntry)),
3398
3398
  nmsIouThreshold: resolvePoolDecodeSettings({
3399
3399
  def,
3400
3400
  modelEntry,
@@ -6913,13 +6913,9 @@ function composeCropRoiToFrameNorm(roi, cropFrameSpace, frameWidth, frameHeight)
6913
6913
  }
6914
6914
  //#endregion
6915
6915
  //#region src/detection-pipeline/pipeline/tree-builder.ts
6916
- /**
6917
- * Effective class map for `(definition, modelId)` without writing back to the
6918
- * shared StepDefinition. Custom models missing from `definition.models` are
6919
- * resolved through the optional registry callback.
6920
- */
6921
- function resolveEffectiveClassMap(definition, modelId, resolveModel) {
6922
- return (definition.models.find((model) => model.id === modelId) ?? resolveModel?.(definition.id, modelId))?.classMap ?? definition.classMap;
6916
+ /** The catalog entry for `(definition, modelId)`: the static catalog, else the custom registry. */
6917
+ function resolveModelEntry(definition, modelId, resolveModel) {
6918
+ return definition.models.find((model) => model.id === modelId) ?? resolveModel?.(definition.id, modelId);
6923
6919
  }
6924
6920
  /**
6925
6921
  * Build an executable tree from user config.
@@ -6956,11 +6952,12 @@ function buildNode(step, getEngine, resolveModel, onMissingVariant, resolved) {
6956
6952
  const definition = require_default_detection_model.getStepDefinition(step.addonId);
6957
6953
  const variant = resolved ?? getEngine(step.addonId, step.modelId);
6958
6954
  const children = (step.children ?? []).filter((c) => c.enabled).map((c) => buildChild(c, step.addonId, getEngine, resolveModel, onMissingVariant)).filter((c) => c !== null);
6955
+ const modelEntry = resolveModelEntry(definition, variant.modelId, resolveModel);
6959
6956
  const mergedSettings = {
6960
- ...collectSchemaDefaults(step.addonId),
6957
+ ...collectSchemaDefaults(step.addonId, modelEntry),
6961
6958
  ...step.settings
6962
6959
  };
6963
- const effectiveClassMap = resolveEffectiveClassMap(definition, variant.modelId, resolveModel);
6960
+ const effectiveClassMap = modelEntry?.classMap ?? definition.classMap;
6964
6961
  return {
6965
6962
  stepId: step.addonId,
6966
6963
  definition,
@@ -6979,8 +6976,8 @@ function buildNode(step, getEngine, resolveModel, onMissingVariant, resolved) {
6979
6976
  * are flattened — a nested `{ type: 'group', fields: [...] }` is
6980
6977
  * entered recursively. Fields without a declared default are skipped.
6981
6978
  */
6982
- function collectSchemaDefaults(stepId) {
6983
- const schema = require_default_detection_model.getStep(stepId).getConfigSchema();
6979
+ function collectSchemaDefaults(stepId, model) {
6980
+ const schema = require_default_detection_model.getStep(stepId).getConfigSchema(model);
6984
6981
  const out = {};
6985
6982
  walkFieldsForDefaults(schema, out);
6986
6983
  return out;
@@ -10605,7 +10602,8 @@ function buildSchemaSlots(formats, modelsDir, customByStep) {
10605
10602
  }])),
10606
10603
  ...m.group ? { group: m.group } : {},
10607
10604
  ...m.legacy !== void 0 ? { legacy: m.legacy } : {},
10608
- provider: m.provider ?? "camstack"
10605
+ provider: m.provider ?? "camstack",
10606
+ defaultConfidence: require_default_detection_model.resolveModelDefaultConfidence(step, m)
10609
10607
  })),
10610
10608
  defaultModelId: step.defaultModelId,
10611
10609
  ...step.defaultModelIdByFormat ? { defaultModelIdByFormat: { ...step.defaultModelIdByFormat } } : {},
@@ -1,9 +1,9 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { Dn as array, Dt as overlayClusterStepSettings, Gt as runtimeDevices$1, H as YAMNET_TO_MACRO, In as string, Kt as stepModelRunsOnFormat, Ln as union, Mt as pipelineExecutorCapability, Nn as object, Rn as EventCategory, Sn as parseJsonUnknown, Tn as sleep, Ut as resolvePoolMemoryPolicy, Zt as supportedRuntimes$1, _n as hydrateSchema, en as errMsg, et as defaultDeviceFor$1, it as detectionPipelineCapability, j as PoolMemoryWatchdog, kt as pickClusterStepSettings, lt as evaluateZoneRules, m as DEFAULT_CLUSTER_STEP_SETTINGS, pn as createEvent, sn as BaseAddon, st as enumerateInferenceDevices, t as APPLE_SA_TO_MACRO, u as CLUSTER_MODEL_SCOPED_STEPS, vt as loadContributionCapability, xn as nodePin, y as DEVICE_BACKEND_TO_FORMAT, zt as resolveClusterStepModelId } from "../dist-CqhrlD0m.mjs";
3
- import { s as readProcessCost } from "../node-CZ1Z3f6z.mjs";
4
- import { _ as resolveModelForFormat, a as buildSubtreeCanRun, c as macroGateVerdict, f as ALL_PIPELINE_STEPS, g as getStepDefinition, h as getStep, i as mergeCustomModels, m as getDefaultModelForFormat, n as resolveDefaultDetectionModel, p as ALL_STEPS, r as CustomModelCatalog, u as localFrameRegistry, y as landmarkPrecisionVerdict } from "../default-detection-model-DX-p9O91.mjs";
2
+ import { Dn as array, Dt as overlayClusterStepSettings, Gt as runtimeDevices$1, H as YAMNET_TO_MACRO, In as string, Kt as stepModelRunsOnFormat, Ln as union, Mt as pipelineExecutorCapability, Nn as object, Rn as EventCategory, Sn as parseJsonUnknown, Tn as sleep, Ut as resolvePoolMemoryPolicy, Zt as supportedRuntimes$1, _n as hydrateSchema, en as errMsg, et as defaultDeviceFor$1, it as detectionPipelineCapability, j as PoolMemoryWatchdog, kt as pickClusterStepSettings, lt as evaluateZoneRules, m as DEFAULT_CLUSTER_STEP_SETTINGS, pn as createEvent, sn as BaseAddon, st as enumerateInferenceDevices, t as APPLE_SA_TO_MACRO, u as CLUSTER_MODEL_SCOPED_STEPS, vt as loadContributionCapability, xn as nodePin, y as DEVICE_BACKEND_TO_FORMAT, zt as resolveClusterStepModelId } from "../dist-DvzAabca.mjs";
3
+ import { s as readProcessCost } from "../node-DnP_6GBZ.mjs";
4
+ import { _ as resolveModelForFormat, a as buildSubtreeCanRun, b as resolveModelDefaultConfidence, c as macroGateVerdict, f as ALL_PIPELINE_STEPS, g as getStepDefinition, h as getStep, i as mergeCustomModels, m as getDefaultModelForFormat, n as resolveDefaultDetectionModel, p as ALL_STEPS, r as CustomModelCatalog, u as localFrameRegistry, y as landmarkPrecisionVerdict } from "../default-detection-model-JDKeiJPf.mjs";
5
5
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
6
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-taq9GnsO.mjs";
6
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-BMr61qT1.mjs";
7
7
  import * as os from "node:os";
8
8
  import * as fs from "node:fs";
9
9
  import * as path$1 from "node:path";
@@ -3387,7 +3387,7 @@ function buildPoolModelConfigForStep(inputs) {
3387
3387
  inputNormalization: modelEntry.inputNormalization,
3388
3388
  outputProbabilities: modelEntry.outputProbabilities,
3389
3389
  postprocessor: resolveEffectivePostprocessorForEntry(def, modelEntry),
3390
- confidence: resolvePoolConfidenceFloor(stepId, def.defaultConfidence),
3390
+ confidence: resolvePoolConfidenceFloor(stepId, resolveModelDefaultConfidence(def, modelEntry)),
3391
3391
  nmsIouThreshold: resolvePoolDecodeSettings({
3392
3392
  def,
3393
3393
  modelEntry,
@@ -6906,13 +6906,9 @@ function composeCropRoiToFrameNorm(roi, cropFrameSpace, frameWidth, frameHeight)
6906
6906
  }
6907
6907
  //#endregion
6908
6908
  //#region src/detection-pipeline/pipeline/tree-builder.ts
6909
- /**
6910
- * Effective class map for `(definition, modelId)` without writing back to the
6911
- * shared StepDefinition. Custom models missing from `definition.models` are
6912
- * resolved through the optional registry callback.
6913
- */
6914
- function resolveEffectiveClassMap(definition, modelId, resolveModel) {
6915
- return (definition.models.find((model) => model.id === modelId) ?? resolveModel?.(definition.id, modelId))?.classMap ?? definition.classMap;
6909
+ /** The catalog entry for `(definition, modelId)`: the static catalog, else the custom registry. */
6910
+ function resolveModelEntry(definition, modelId, resolveModel) {
6911
+ return definition.models.find((model) => model.id === modelId) ?? resolveModel?.(definition.id, modelId);
6916
6912
  }
6917
6913
  /**
6918
6914
  * Build an executable tree from user config.
@@ -6949,11 +6945,12 @@ function buildNode(step, getEngine, resolveModel, onMissingVariant, resolved) {
6949
6945
  const definition = getStepDefinition(step.addonId);
6950
6946
  const variant = resolved ?? getEngine(step.addonId, step.modelId);
6951
6947
  const children = (step.children ?? []).filter((c) => c.enabled).map((c) => buildChild(c, step.addonId, getEngine, resolveModel, onMissingVariant)).filter((c) => c !== null);
6948
+ const modelEntry = resolveModelEntry(definition, variant.modelId, resolveModel);
6952
6949
  const mergedSettings = {
6953
- ...collectSchemaDefaults(step.addonId),
6950
+ ...collectSchemaDefaults(step.addonId, modelEntry),
6954
6951
  ...step.settings
6955
6952
  };
6956
- const effectiveClassMap = resolveEffectiveClassMap(definition, variant.modelId, resolveModel);
6953
+ const effectiveClassMap = modelEntry?.classMap ?? definition.classMap;
6957
6954
  return {
6958
6955
  stepId: step.addonId,
6959
6956
  definition,
@@ -6972,8 +6969,8 @@ function buildNode(step, getEngine, resolveModel, onMissingVariant, resolved) {
6972
6969
  * are flattened — a nested `{ type: 'group', fields: [...] }` is
6973
6970
  * entered recursively. Fields without a declared default are skipped.
6974
6971
  */
6975
- function collectSchemaDefaults(stepId) {
6976
- const schema = getStep(stepId).getConfigSchema();
6972
+ function collectSchemaDefaults(stepId, model) {
6973
+ const schema = getStep(stepId).getConfigSchema(model);
6977
6974
  const out = {};
6978
6975
  walkFieldsForDefaults(schema, out);
6979
6976
  return out;
@@ -10598,7 +10595,8 @@ function buildSchemaSlots(formats, modelsDir, customByStep) {
10598
10595
  }])),
10599
10596
  ...m.group ? { group: m.group } : {},
10600
10597
  ...m.legacy !== void 0 ? { legacy: m.legacy } : {},
10601
- provider: m.provider ?? "camstack"
10598
+ provider: m.provider ?? "camstack",
10599
+ defaultConfidence: resolveModelDefaultConfidence(step, m)
10602
10600
  })),
10603
10601
  defaultModelId: step.defaultModelId,
10604
10602
  ...step.defaultModelIdByFormat ? { defaultModelIdByFormat: { ...step.defaultModelIdByFormat } } : {},
@@ -11569,6 +11569,16 @@ var ModelCatalogEntrySchema = object({
11569
11569
  */
11570
11570
  postprocessor: custom().optional(),
11571
11571
  /**
11572
+ * Per-MODEL default confidence floor. Absent ⇒ the step's
11573
+ * `StepDefinition.defaultConfidence` applies. A score is a property of one
11574
+ * model's output scale, not of the step slot it sits in: YuNet's
11575
+ * `sqrt(cls·obj)` is not SCRFD's score, and inheriting SCRFD's 0.5 filled the
11576
+ * face gallery with wheels and hands (D662, amends D645). An operator's
11577
+ * explicit value still wins over it. Resolved in ONE place —
11578
+ * `addon-pipeline/.../registry/effective-confidence.ts`.
11579
+ */
11580
+ defaultConfidence: number().min(0).max(1).optional(),
11581
+ /**
11572
11582
  * When true, the executor produces a landmark-aligned crop (similarity warp
11573
11583
  * onto the canonical template) before this step runs, instead of a plain
11574
11584
  * axis-aligned bbox crop. Required for face-recognition embedders (ArcFace):
@@ -24795,7 +24805,8 @@ var PipelineModelOptionSchema = object({
24795
24805
  })),
24796
24806
  group: ModelVariantGroupSchema.optional(),
24797
24807
  legacy: boolean().optional(),
24798
- provider: ModelProviderIdSchema.optional()
24808
+ provider: ModelProviderIdSchema.optional(),
24809
+ defaultConfidence: number().optional()
24799
24810
  });
24800
24811
  var ConfigFieldBridge = custom();
24801
24812
  var PipelineAddonSchemaSchema = object({
@@ -11569,6 +11569,16 @@ var ModelCatalogEntrySchema = object({
11569
11569
  */
11570
11570
  postprocessor: custom().optional(),
11571
11571
  /**
11572
+ * Per-MODEL default confidence floor. Absent ⇒ the step's
11573
+ * `StepDefinition.defaultConfidence` applies. A score is a property of one
11574
+ * model's output scale, not of the step slot it sits in: YuNet's
11575
+ * `sqrt(cls·obj)` is not SCRFD's score, and inheriting SCRFD's 0.5 filled the
11576
+ * face gallery with wheels and hands (D662, amends D645). An operator's
11577
+ * explicit value still wins over it. Resolved in ONE place —
11578
+ * `addon-pipeline/.../registry/effective-confidence.ts`.
11579
+ */
11580
+ defaultConfidence: number().min(0).max(1).optional(),
11581
+ /**
11572
11582
  * When true, the executor produces a landmark-aligned crop (similarity warp
11573
11583
  * onto the canonical template) before this step runs, instead of a plain
11574
11584
  * axis-aligned bbox crop. Required for face-recognition embedders (ArcFace):
@@ -24795,7 +24805,8 @@ var PipelineModelOptionSchema = object({
24795
24805
  })),
24796
24806
  group: ModelVariantGroupSchema.optional(),
24797
24807
  legacy: boolean().optional(),
24798
- provider: ModelProviderIdSchema.optional()
24808
+ provider: ModelProviderIdSchema.optional(),
24809
+ defaultConfidence: number().optional()
24799
24810
  });
24800
24811
  var ConfigFieldBridge = custom();
24801
24812
  var PipelineAddonSchemaSchema = object({
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-C2WOjQsy.js");
5
+ const require_dist = require("../dist-BUs7H-fe.js");
6
6
  const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
7
7
  let node_fs = require("node:fs");
8
8
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { Et as motionDetectionCapability, _n as hydrateSchema, dn as DeviceType, lt as evaluateZoneRules, sn as BaseAddon } from "../dist-CqhrlD0m.mjs";
1
+ import { Et as motionDetectionCapability, _n as hydrateSchema, dn as DeviceType, lt as evaluateZoneRules, sn as BaseAddon } from "../dist-DvzAabca.mjs";
2
2
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
3
3
  import { readFileSync } from "node:fs";
4
4
  import { join } from "node:path";
@@ -1,4 +1,4 @@
1
- import { an as isSoftwareDecode, en as errMsg, nn as Fmp4BoxSplitter, rn as buildFfmpegArgs } from "./dist-CqhrlD0m.mjs";
1
+ import { an as isSoftwareDecode, en as errMsg, nn as Fmp4BoxSplitter, rn as buildFfmpegArgs } from "./dist-DvzAabca.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { realpathSync } from "node:fs";
4
4
  import path from "node:path";
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-emK7D4bc.js");
2
- const require_dist = require("./dist-C2WOjQsy.js");
2
+ const require_dist = require("./dist-BUs7H-fe.js");
3
3
  let node_crypto = require("node:crypto");
4
4
  let node_fs = require("node:fs");
5
5
  node_fs = require_chunk.__toESM(node_fs, 1);
@@ -3,9 +3,9 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-emK7D4bc.js");
6
- const require_dist = require("../dist-C2WOjQsy.js");
7
- const require_node = require("../node-CiWM78Ze.js");
8
- const require_default_detection_model = require("../default-detection-model-nKzvW7BX.js");
6
+ const require_dist = require("../dist-BUs7H-fe.js");
7
+ const require_node = require("../node-DxVMyys-.js");
8
+ const require_default_detection_model = require("../default-detection-model-P7IIrP0a.js");
9
9
  const require_worker_protocol = require("../worker-protocol-C-G8qmye.js");
10
10
  const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
11
11
  const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
@@ -3704,6 +3704,87 @@ function buildDetailNotAttachedError(deviceId) {
3704
3704
  return /* @__PURE__ */ new Error(`${DETAIL_NOT_ATTACHED_MARKER} — camera ${deviceId} is not attached and no detail state is parked within the grace window`);
3705
3705
  }
3706
3706
  //#endregion
3707
+ //#region src/pipeline-runner/face-parent-geometry.ts
3708
+ /** Is the centre of `face` inside `parent` (edges inclusive)? */
3709
+ function faceCentreInsideParent(face, parent) {
3710
+ const cx = face.x + face.w / 2;
3711
+ const cy = face.y + face.h / 2;
3712
+ return cx >= parent.x && cx <= parent.x + parent.w && cy >= parent.y && cy <= parent.y + parent.h;
3713
+ }
3714
+ /** The log line, one name for both the throttled and the fallback path. */
3715
+ var FACE_GUARD_UNAVAILABLE_MESSAGE = "face geometry guard cannot run on a caller-cut tile — its padding is unknown, the faces pass unjudged";
3716
+ var FACE_OUTSIDE_PARENT_MESSAGE = "face dropped — its centre is outside the person box (it was found in the crop padding)";
3717
+ /** The fields of a drop the log line carries. */
3718
+ function faceOutsideParentMeta(drop) {
3719
+ const round = (r) => ({
3720
+ x: Math.round(r.x),
3721
+ y: Math.round(r.y),
3722
+ w: Math.round(r.w),
3723
+ h: Math.round(r.h)
3724
+ });
3725
+ return {
3726
+ score: Number(drop.score.toFixed(4)),
3727
+ faceBbox: round(drop.faceBbox),
3728
+ parentBbox: round(drop.parentBbox)
3729
+ };
3730
+ }
3731
+ /** Default window: the dispatcher refreshes a face every second per track. */
3732
+ var FACE_OUTSIDE_PARENT_LOG_INTERVAL_MS = 6e4;
3733
+ /**
3734
+ * Per-camera, rate-limited announcement of dropped faces (D391: a branch that
3735
+ * drops work says so). The first drop on a camera is logged at once; drops
3736
+ * inside the window are held and emitted as ONE line carrying their count —
3737
+ * by the next drop after the window, or by a flush armed when the first one
3738
+ * was held, whichever comes first. Every drop is counted in exactly one line.
3739
+ */
3740
+ var FaceOutsideParentLog = class {
3741
+ opts;
3742
+ lastLineAt = /* @__PURE__ */ new Map();
3743
+ heldBack = /* @__PURE__ */ new Map();
3744
+ flushArmed = /* @__PURE__ */ new Set();
3745
+ /** The latest held drop per camera — the example a flushed line shows. */
3746
+ lastHeld = /* @__PURE__ */ new Map();
3747
+ constructor(opts) {
3748
+ this.opts = opts;
3749
+ }
3750
+ record(drop) {
3751
+ const now = this.opts.now();
3752
+ const held = (this.heldBack.get(drop.deviceId) ?? 0) + 1;
3753
+ const last = this.lastLineAt.get(drop.deviceId);
3754
+ if (last !== void 0 && now - last < this.opts.intervalMs) {
3755
+ this.heldBack.set(drop.deviceId, held);
3756
+ this.lastHeld.set(drop.deviceId, drop);
3757
+ if (!this.flushArmed.has(drop.deviceId)) {
3758
+ this.flushArmed.add(drop.deviceId);
3759
+ this.opts.schedule(() => this.flush(drop.deviceId), last + this.opts.intervalMs - now);
3760
+ }
3761
+ return;
3762
+ }
3763
+ this.emit(drop, held, now);
3764
+ }
3765
+ /** Emit what a window held back, if anything; a no-op once already said. */
3766
+ flush(deviceId) {
3767
+ this.flushArmed.delete(deviceId);
3768
+ const held = this.heldBack.get(deviceId) ?? 0;
3769
+ const drop = this.lastHeld.get(deviceId);
3770
+ if (held === 0 || drop === void 0) return;
3771
+ this.emit(drop, held, this.opts.now());
3772
+ }
3773
+ emit(drop, count, now) {
3774
+ this.lastLineAt.set(drop.deviceId, now);
3775
+ this.heldBack.set(drop.deviceId, 0);
3776
+ this.flushArmed.delete(drop.deviceId);
3777
+ this.opts.info(FACE_OUTSIDE_PARENT_MESSAGE, {
3778
+ tags: { deviceId: drop.deviceId },
3779
+ meta: {
3780
+ ...faceOutsideParentMeta(drop),
3781
+ droppedSinceLastLine: count,
3782
+ windowMs: this.opts.intervalMs
3783
+ }
3784
+ });
3785
+ }
3786
+ };
3787
+ //#endregion
3707
3788
  //#region src/pipeline-runner/detail-subtree.ts
3708
3789
  /** Did the subtree run refuse because the camera is not attached (park lapsed)? */
3709
3790
  function isDetailNotAttachedRefusal(outcome) {
@@ -3713,6 +3794,8 @@ function isDetailNotAttachedRefusal(outcome) {
3713
3794
  function isNativeCropMiss(fetch) {
3714
3795
  return "miss" in fetch;
3715
3796
  }
3797
+ /** The class the geometry guard judges — the face detector's output. */
3798
+ var FACE_CLASS = "face";
3716
3799
  /** Normalize a frame-space pixel rect to `[0,1]` by the given frame dims. */
3717
3800
  function normalizeRect(rect, frameWidth, frameHeight) {
3718
3801
  return {
@@ -4014,14 +4097,45 @@ async function runDetailSubtree(deps, input) {
4014
4097
  cropFrameSpace: crop.frameSpace
4015
4098
  } : void 0;
4016
4099
  const details = [];
4100
+ let unjudgedFaces = 0;
4017
4101
  for (const step of steps) {
4018
4102
  const placement = deps.placeStep?.(input.deviceId, step);
4019
4103
  const result = await deps.runPipeline([placement?.step ?? step], crop.jpeg, input.deviceId, placement?.deviceKey, nativeCropRef);
4020
4104
  if (!result) continue;
4021
- for (const detection of result.detections) details.push(toDetailResult(detection, step.addonId, crop));
4105
+ for (const detection of result.detections) {
4106
+ const detail = toDetailResult(detection, step.addonId, crop);
4107
+ if (detail.className === FACE_CLASS && crop.source === "fallback") unjudgedFaces += 1;
4108
+ else if (detail.className === FACE_CLASS && detail.bbox !== void 0 && !faceCentreInsideParent(detail.bbox, input.parent.bbox)) {
4109
+ announceFaceOutsideParent(deps, {
4110
+ deviceId: input.deviceId,
4111
+ score: detail.score,
4112
+ faceBbox: detail.bbox,
4113
+ parentBbox: input.parent.bbox
4114
+ });
4115
+ continue;
4116
+ }
4117
+ details.push(detail);
4118
+ }
4022
4119
  }
4120
+ if (unjudgedFaces > 0) deps.logger.warn(FACE_GUARD_UNAVAILABLE_MESSAGE, {
4121
+ tags: { deviceId: input.deviceId },
4122
+ meta: {
4123
+ faces: unjudgedFaces,
4124
+ cropSource: crop.source
4125
+ }
4126
+ });
4023
4127
  return { details };
4024
4128
  }
4129
+ function announceFaceOutsideParent(deps, drop) {
4130
+ if (deps.recordFaceOutsideParent !== void 0) {
4131
+ deps.recordFaceOutsideParent(drop);
4132
+ return;
4133
+ }
4134
+ deps.logger.warn(FACE_OUTSIDE_PARENT_MESSAGE, {
4135
+ tags: { deviceId: drop.deviceId },
4136
+ meta: faceOutsideParentMeta(drop)
4137
+ });
4138
+ }
4025
4139
  //#endregion
4026
4140
  //#region src/pipeline-runner/device-load.ts
4027
4141
  /** The backend prefix of a `<backend>:<device>` key (bare `cpu` → `cpu`). */
@@ -9682,7 +9796,8 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
9682
9796
  runPipeline: (steps, imageJpeg, deviceId, deviceKey, nativeCropRef) => this.runDetailPipeline(steps, imageJpeg, deviceId, deviceKey, nativeCropRef),
9683
9797
  placeStep: (deviceId, step) => this.placeDetailStepForCamera(deviceId, step),
9684
9798
  resolveCropConvention: () => convention,
9685
- logger: this.detailSubtreeLogger()
9799
+ logger: this.detailSubtreeLogger(),
9800
+ recordFaceOutsideParent: (drop) => this.faceOutsideParentLog.record(drop)
9686
9801
  }, input);
9687
9802
  if (outcome !== null && isDetailNotAttachedRefusal(outcome)) throw buildDetailNotAttachedError(input.deviceId);
9688
9803
  return outcome;
@@ -9896,6 +10011,15 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
9896
10011
  decodeCeilingInForce: this.liveWorkers?.ceiling
9897
10012
  } });
9898
10013
  }
10014
+ /** D662: faces the detail plane's geometry guard dropped, one line per camera per minute. */
10015
+ faceOutsideParentLog = new FaceOutsideParentLog({
10016
+ info: (message, extras) => this.ctxIfReady?.logger.info(message, extras),
10017
+ now: () => Date.now(),
10018
+ intervalMs: FACE_OUTSIDE_PARENT_LOG_INTERVAL_MS,
10019
+ schedule: (flush, delayMs) => {
10020
+ setTimeout(flush, delayMs).unref();
10021
+ }
10022
+ });
9899
10023
  /** A warn sink that survives a not-yet-ready ctx (boot-order dispatches). */
9900
10024
  detailSubtreeLogger() {
9901
10025
  return { warn: (message, extras) => this.ctxIfReady?.logger.warn(message, extras) };
@@ -1,6 +1,6 @@
1
- import { An as lazy, At as pickDetailCropConvention, D as MOTION_CLOSE_AFTER_MS, Dn as array, En as _enum, In as string, Mn as number, Nn as object, Nt as pipelineRunnerCapability, O as NativeLeaseAdmissionSchema, On as boolean, Rn as EventCategory, en as errMsg, h as DEFAULT_DETAIL_CROP_CONVENTION, hn as defineCustomActions, i as BackgroundRunRegistry, jn as literal, jt as pickNativeLeaseOverride, k as NativeLeaseSettingsSchema, mn as customAction, nt as deriveDetailCropRect, pn as createEvent, pt as failureContributionCapability, sn as BaseAddon, v as DEFAULT_NATIVE_LEASE_SETTINGS, vt as loadContributionCapability, w as FailureCounters, xn as nodePin } from "../dist-CqhrlD0m.mjs";
2
- import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-CZ1Z3f6z.mjs";
3
- import { c as macroGateVerdict, d as resolveFrameViewGeometry, g as getStepDefinition, l as rootObjectGate, o as placeDetailStep, r as CustomModelCatalog, s as stepsForElectedPool, u as localFrameRegistry, v as RETIRED_MODEL_IDS } from "../default-detection-model-DX-p9O91.mjs";
1
+ import { An as lazy, At as pickDetailCropConvention, D as MOTION_CLOSE_AFTER_MS, Dn as array, En as _enum, In as string, Mn as number, Nn as object, Nt as pipelineRunnerCapability, O as NativeLeaseAdmissionSchema, On as boolean, Rn as EventCategory, en as errMsg, h as DEFAULT_DETAIL_CROP_CONVENTION, hn as defineCustomActions, i as BackgroundRunRegistry, jn as literal, jt as pickNativeLeaseOverride, k as NativeLeaseSettingsSchema, mn as customAction, nt as deriveDetailCropRect, pn as createEvent, pt as failureContributionCapability, sn as BaseAddon, v as DEFAULT_NATIVE_LEASE_SETTINGS, vt as loadContributionCapability, w as FailureCounters, xn as nodePin } from "../dist-DvzAabca.mjs";
2
+ import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-DnP_6GBZ.mjs";
3
+ import { c as macroGateVerdict, d as resolveFrameViewGeometry, g as getStepDefinition, l as rootObjectGate, o as placeDetailStep, r as CustomModelCatalog, s as stepsForElectedPool, u as localFrameRegistry, v as RETIRED_MODEL_IDS } from "../default-detection-model-JDKeiJPf.mjs";
4
4
  import { t as isWorkerReply } from "../worker-protocol-D_NzPcnh.mjs";
5
5
  import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
6
6
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
@@ -3696,6 +3696,87 @@ function buildDetailNotAttachedError(deviceId) {
3696
3696
  return /* @__PURE__ */ new Error(`${DETAIL_NOT_ATTACHED_MARKER} — camera ${deviceId} is not attached and no detail state is parked within the grace window`);
3697
3697
  }
3698
3698
  //#endregion
3699
+ //#region src/pipeline-runner/face-parent-geometry.ts
3700
+ /** Is the centre of `face` inside `parent` (edges inclusive)? */
3701
+ function faceCentreInsideParent(face, parent) {
3702
+ const cx = face.x + face.w / 2;
3703
+ const cy = face.y + face.h / 2;
3704
+ return cx >= parent.x && cx <= parent.x + parent.w && cy >= parent.y && cy <= parent.y + parent.h;
3705
+ }
3706
+ /** The log line, one name for both the throttled and the fallback path. */
3707
+ var FACE_GUARD_UNAVAILABLE_MESSAGE = "face geometry guard cannot run on a caller-cut tile — its padding is unknown, the faces pass unjudged";
3708
+ var FACE_OUTSIDE_PARENT_MESSAGE = "face dropped — its centre is outside the person box (it was found in the crop padding)";
3709
+ /** The fields of a drop the log line carries. */
3710
+ function faceOutsideParentMeta(drop) {
3711
+ const round = (r) => ({
3712
+ x: Math.round(r.x),
3713
+ y: Math.round(r.y),
3714
+ w: Math.round(r.w),
3715
+ h: Math.round(r.h)
3716
+ });
3717
+ return {
3718
+ score: Number(drop.score.toFixed(4)),
3719
+ faceBbox: round(drop.faceBbox),
3720
+ parentBbox: round(drop.parentBbox)
3721
+ };
3722
+ }
3723
+ /** Default window: the dispatcher refreshes a face every second per track. */
3724
+ var FACE_OUTSIDE_PARENT_LOG_INTERVAL_MS = 6e4;
3725
+ /**
3726
+ * Per-camera, rate-limited announcement of dropped faces (D391: a branch that
3727
+ * drops work says so). The first drop on a camera is logged at once; drops
3728
+ * inside the window are held and emitted as ONE line carrying their count —
3729
+ * by the next drop after the window, or by a flush armed when the first one
3730
+ * was held, whichever comes first. Every drop is counted in exactly one line.
3731
+ */
3732
+ var FaceOutsideParentLog = class {
3733
+ opts;
3734
+ lastLineAt = /* @__PURE__ */ new Map();
3735
+ heldBack = /* @__PURE__ */ new Map();
3736
+ flushArmed = /* @__PURE__ */ new Set();
3737
+ /** The latest held drop per camera — the example a flushed line shows. */
3738
+ lastHeld = /* @__PURE__ */ new Map();
3739
+ constructor(opts) {
3740
+ this.opts = opts;
3741
+ }
3742
+ record(drop) {
3743
+ const now = this.opts.now();
3744
+ const held = (this.heldBack.get(drop.deviceId) ?? 0) + 1;
3745
+ const last = this.lastLineAt.get(drop.deviceId);
3746
+ if (last !== void 0 && now - last < this.opts.intervalMs) {
3747
+ this.heldBack.set(drop.deviceId, held);
3748
+ this.lastHeld.set(drop.deviceId, drop);
3749
+ if (!this.flushArmed.has(drop.deviceId)) {
3750
+ this.flushArmed.add(drop.deviceId);
3751
+ this.opts.schedule(() => this.flush(drop.deviceId), last + this.opts.intervalMs - now);
3752
+ }
3753
+ return;
3754
+ }
3755
+ this.emit(drop, held, now);
3756
+ }
3757
+ /** Emit what a window held back, if anything; a no-op once already said. */
3758
+ flush(deviceId) {
3759
+ this.flushArmed.delete(deviceId);
3760
+ const held = this.heldBack.get(deviceId) ?? 0;
3761
+ const drop = this.lastHeld.get(deviceId);
3762
+ if (held === 0 || drop === void 0) return;
3763
+ this.emit(drop, held, this.opts.now());
3764
+ }
3765
+ emit(drop, count, now) {
3766
+ this.lastLineAt.set(drop.deviceId, now);
3767
+ this.heldBack.set(drop.deviceId, 0);
3768
+ this.flushArmed.delete(drop.deviceId);
3769
+ this.opts.info(FACE_OUTSIDE_PARENT_MESSAGE, {
3770
+ tags: { deviceId: drop.deviceId },
3771
+ meta: {
3772
+ ...faceOutsideParentMeta(drop),
3773
+ droppedSinceLastLine: count,
3774
+ windowMs: this.opts.intervalMs
3775
+ }
3776
+ });
3777
+ }
3778
+ };
3779
+ //#endregion
3699
3780
  //#region src/pipeline-runner/detail-subtree.ts
3700
3781
  /** Did the subtree run refuse because the camera is not attached (park lapsed)? */
3701
3782
  function isDetailNotAttachedRefusal(outcome) {
@@ -3705,6 +3786,8 @@ function isDetailNotAttachedRefusal(outcome) {
3705
3786
  function isNativeCropMiss(fetch) {
3706
3787
  return "miss" in fetch;
3707
3788
  }
3789
+ /** The class the geometry guard judges — the face detector's output. */
3790
+ var FACE_CLASS = "face";
3708
3791
  /** Normalize a frame-space pixel rect to `[0,1]` by the given frame dims. */
3709
3792
  function normalizeRect(rect, frameWidth, frameHeight) {
3710
3793
  return {
@@ -4006,14 +4089,45 @@ async function runDetailSubtree(deps, input) {
4006
4089
  cropFrameSpace: crop.frameSpace
4007
4090
  } : void 0;
4008
4091
  const details = [];
4092
+ let unjudgedFaces = 0;
4009
4093
  for (const step of steps) {
4010
4094
  const placement = deps.placeStep?.(input.deviceId, step);
4011
4095
  const result = await deps.runPipeline([placement?.step ?? step], crop.jpeg, input.deviceId, placement?.deviceKey, nativeCropRef);
4012
4096
  if (!result) continue;
4013
- for (const detection of result.detections) details.push(toDetailResult(detection, step.addonId, crop));
4097
+ for (const detection of result.detections) {
4098
+ const detail = toDetailResult(detection, step.addonId, crop);
4099
+ if (detail.className === FACE_CLASS && crop.source === "fallback") unjudgedFaces += 1;
4100
+ else if (detail.className === FACE_CLASS && detail.bbox !== void 0 && !faceCentreInsideParent(detail.bbox, input.parent.bbox)) {
4101
+ announceFaceOutsideParent(deps, {
4102
+ deviceId: input.deviceId,
4103
+ score: detail.score,
4104
+ faceBbox: detail.bbox,
4105
+ parentBbox: input.parent.bbox
4106
+ });
4107
+ continue;
4108
+ }
4109
+ details.push(detail);
4110
+ }
4014
4111
  }
4112
+ if (unjudgedFaces > 0) deps.logger.warn(FACE_GUARD_UNAVAILABLE_MESSAGE, {
4113
+ tags: { deviceId: input.deviceId },
4114
+ meta: {
4115
+ faces: unjudgedFaces,
4116
+ cropSource: crop.source
4117
+ }
4118
+ });
4015
4119
  return { details };
4016
4120
  }
4121
+ function announceFaceOutsideParent(deps, drop) {
4122
+ if (deps.recordFaceOutsideParent !== void 0) {
4123
+ deps.recordFaceOutsideParent(drop);
4124
+ return;
4125
+ }
4126
+ deps.logger.warn(FACE_OUTSIDE_PARENT_MESSAGE, {
4127
+ tags: { deviceId: drop.deviceId },
4128
+ meta: faceOutsideParentMeta(drop)
4129
+ });
4130
+ }
4017
4131
  //#endregion
4018
4132
  //#region src/pipeline-runner/device-load.ts
4019
4133
  /** The backend prefix of a `<backend>:<device>` key (bare `cpu` → `cpu`). */
@@ -9674,7 +9788,8 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
9674
9788
  runPipeline: (steps, imageJpeg, deviceId, deviceKey, nativeCropRef) => this.runDetailPipeline(steps, imageJpeg, deviceId, deviceKey, nativeCropRef),
9675
9789
  placeStep: (deviceId, step) => this.placeDetailStepForCamera(deviceId, step),
9676
9790
  resolveCropConvention: () => convention,
9677
- logger: this.detailSubtreeLogger()
9791
+ logger: this.detailSubtreeLogger(),
9792
+ recordFaceOutsideParent: (drop) => this.faceOutsideParentLog.record(drop)
9678
9793
  }, input);
9679
9794
  if (outcome !== null && isDetailNotAttachedRefusal(outcome)) throw buildDetailNotAttachedError(input.deviceId);
9680
9795
  return outcome;
@@ -9888,6 +10003,15 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
9888
10003
  decodeCeilingInForce: this.liveWorkers?.ceiling
9889
10004
  } });
9890
10005
  }
10006
+ /** D662: faces the detail plane's geometry guard dropped, one line per camera per minute. */
10007
+ faceOutsideParentLog = new FaceOutsideParentLog({
10008
+ info: (message, extras) => this.ctxIfReady?.logger.info(message, extras),
10009
+ now: () => Date.now(),
10010
+ intervalMs: FACE_OUTSIDE_PARENT_LOG_INTERVAL_MS,
10011
+ schedule: (flush, delayMs) => {
10012
+ setTimeout(flush, delayMs).unref();
10013
+ }
10014
+ });
9891
10015
  /** A warn sink that survives a not-yet-ready ctx (boot-order dispatches). */
9892
10016
  detailSubtreeLogger() {
9893
10017
  return { warn: (message, extras) => this.ctxIfReady?.logger.warn(message, extras) };
@@ -1,4 +1,4 @@
1
- import { Ot as parseProcStatus } from "./dist-CqhrlD0m.mjs";
1
+ import { Ot as parseProcStatus } from "./dist-DvzAabca.mjs";
2
2
  import * as fs from "node:fs";
3
3
  import { execFile } from "node:child_process";
4
4
  //#region src/shared/node-topology-platform.ts
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-emK7D4bc.js");
2
- const require_dist = require("./dist-C2WOjQsy.js");
2
+ const require_dist = require("./dist-BUs7H-fe.js");
3
3
  let node_fs = require("node:fs");
4
4
  node_fs = require_chunk.__toESM(node_fs);
5
5
  let node_child_process = require("node:child_process");
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-emK7D4bc.js");
6
- const require_dist = require("../dist-C2WOjQsy.js");
7
- const require_node = require("../node-CiWM78Ze.js");
6
+ const require_dist = require("../dist-BUs7H-fe.js");
7
+ const require_node = require("../node-DxVMyys-.js");
8
8
  const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
9
9
  const require_restream_intent = require("../restream-intent-7uDNqMKs.js");
10
10
  const require_retire_root_keys = require("../retire-root-keys-Csb8z2f3.js");
@@ -1,5 +1,5 @@
1
- import { A as OpsLogEntrySchema, B as VIDEOCLIPS_MAX_OFFER_BYTES, Bt as resolveCreateExportSubject, C as ExportRecordSchema, Ct as mayWriteToLocation, Dn as array, En as _enum, F as RECORDING_SOURCE_CAMSTACK, Fn as record, Ft as recordingArchiveCapability, Ht as resolveLocationMode, I as RECORDING_SOURCE_CAMSTACK_ADDON, In as string, It as recordingCapability, Jt as storageOccupancyCapability, L as RecordingConfigSchema, Lt as recordingExportCapability, Mn as number, Nn as object, On as boolean, P as RECORDING_EXPORT_MAX_READ_BYTES, Pn as preprocess, Qt as videoclipsCapability, R as RecordingSignalStatusSchema, Rn as EventCategory, Rt as recordingSignalCapability, St as mayReadLocation, Tn as sleep$1, Tt as modeMayWrite, V as VISIT_MERGE_GAP_MS, Wt as resolveRecordingProfiles, X as clipExportFailureOf, Xt as stripRetiredBandPreBufferSec, Y as clipExportFailure, _n as hydrateSchema, _t as isFirstLevelMacroClass, a as BatteryStatusSchema, b as EVENT_OWNER_TYPES, ct as evaluateSensorEdge, dn as DeviceType, dt as evictionPolicyOfLocation, en as errMsg, ft as exportSubjectOf, g as DEFAULT_EVENTS_BAND_BUFFER_SEC, hn as defineCustomActions, mn as customAction, mt as gbToBytes, o as CLIP_BROKER_PACED_RATES, q as batteryCapability, qt as storageEvictableCapability, rt as deriveRecordingMode, sn as BaseAddon, tt as deriveBatteryPresence, un as DeviceFeature, ut as evictionPolicyForMode, vt as loadContributionCapability, wn as selectAssignedProfileSlots, wt as migrateLegacyDeviceSignalConfig, x as EVENT_PAD_MS, xn as nodePin } from "../dist-CqhrlD0m.mjs";
2
- import { a as physicalRootOf, i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-CZ1Z3f6z.mjs";
1
+ import { A as OpsLogEntrySchema, B as VIDEOCLIPS_MAX_OFFER_BYTES, Bt as resolveCreateExportSubject, C as ExportRecordSchema, Ct as mayWriteToLocation, Dn as array, En as _enum, F as RECORDING_SOURCE_CAMSTACK, Fn as record, Ft as recordingArchiveCapability, Ht as resolveLocationMode, I as RECORDING_SOURCE_CAMSTACK_ADDON, In as string, It as recordingCapability, Jt as storageOccupancyCapability, L as RecordingConfigSchema, Lt as recordingExportCapability, Mn as number, Nn as object, On as boolean, P as RECORDING_EXPORT_MAX_READ_BYTES, Pn as preprocess, Qt as videoclipsCapability, R as RecordingSignalStatusSchema, Rn as EventCategory, Rt as recordingSignalCapability, St as mayReadLocation, Tn as sleep$1, Tt as modeMayWrite, V as VISIT_MERGE_GAP_MS, Wt as resolveRecordingProfiles, X as clipExportFailureOf, Xt as stripRetiredBandPreBufferSec, Y as clipExportFailure, _n as hydrateSchema, _t as isFirstLevelMacroClass, a as BatteryStatusSchema, b as EVENT_OWNER_TYPES, ct as evaluateSensorEdge, dn as DeviceType, dt as evictionPolicyOfLocation, en as errMsg, ft as exportSubjectOf, g as DEFAULT_EVENTS_BAND_BUFFER_SEC, hn as defineCustomActions, mn as customAction, mt as gbToBytes, o as CLIP_BROKER_PACED_RATES, q as batteryCapability, qt as storageEvictableCapability, rt as deriveRecordingMode, sn as BaseAddon, tt as deriveBatteryPresence, un as DeviceFeature, ut as evictionPolicyForMode, vt as loadContributionCapability, wn as selectAssignedProfileSlots, wt as migrateLegacyDeviceSignalConfig, x as EVENT_PAD_MS, xn as nodePin } from "../dist-DvzAabca.mjs";
2
+ import { a as physicalRootOf, i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-DnP_6GBZ.mjs";
3
3
  import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
4
4
  import { d as PREBUFFER_MAX_MS, l as withRecordingIntent, r as RECORDING_PRE_ROLL_REQUEST_MS } from "../restream-intent-DyGmLAU9.mjs";
5
5
  import { n as RowMapStore, t as retireRootKeys } from "../retire-root-keys-DZvlso2l.mjs";
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-emK7D4bc.js");
2
- const require_dist = require("./dist-C2WOjQsy.js");
2
+ const require_dist = require("./dist-BUs7H-fe.js");
3
3
  let node_child_process = require("node:child_process");
4
4
  //#region src/stream-broker/recorded/avcc-annexb.ts
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  import { r as __toESM, t as __commonJSMin } from "./chunk-DnnnRqeS.mjs";
2
- import { en as errMsg } from "./dist-CqhrlD0m.mjs";
2
+ import { en as errMsg } from "./dist-DvzAabca.mjs";
3
3
  import { spawn } from "node:child_process";
4
4
  //#region src/stream-broker/recorded/avcc-annexb.ts
5
5
  /**
@@ -18,7 +18,7 @@ var e = {
18
18
  },
19
19
  "@camstack/types": {
20
20
  name: "@camstack/types",
21
- version: "1.2.265",
21
+ version: "1.2.266",
22
22
  scope: ["default"],
23
23
  loaded: !1,
24
24
  from: "addon_stream_broker_widgets",
@@ -1,4 +1,4 @@
1
- const require_segment_demux_js = require("../segment-demux-js-5Xcu3sTI.js");
1
+ const require_segment_demux_js = require("../segment-demux-js-DANvUJgH.js");
2
2
  let node_worker_threads = require("node:worker_threads");
3
3
  //#region src/stream-broker/recorded/demux-worker-child.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { t as demuxSegmentFullJs } from "../segment-demux-js-Cydmp9fc.mjs";
1
+ import { t as demuxSegmentFullJs } from "../segment-demux-js-DBqdboBI.mjs";
2
2
  import { parentPort } from "node:worker_threads";
3
3
  //#region src/stream-broker/recorded/demux-worker-child.ts
4
4
  /**
@@ -36,7 +36,7 @@ async function r() {
36
36
  }
37
37
  },
38
38
  "@camstack/types": {
39
- version: "1.2.265",
39
+ version: "1.2.266",
40
40
  scope: "default",
41
41
  shareConfig: {
42
42
  singleton: !0,
@@ -3,12 +3,12 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-emK7D4bc.js");
6
- const require_dist = require("../dist-C2WOjQsy.js");
7
- const require_node = require("../node-CiWM78Ze.js");
6
+ const require_dist = require("../dist-BUs7H-fe.js");
7
+ const require_node = require("../node-DxVMyys-.js");
8
8
  const require_restream_intent = require("../restream-intent-7uDNqMKs.js");
9
9
  const require_remote_restream = require("../remote-restream-CO36Sr30.js");
10
10
  const require_retire_root_keys = require("../retire-root-keys-Csb8z2f3.js");
11
- const require_segment_demux_js = require("../segment-demux-js-5Xcu3sTI.js");
11
+ const require_segment_demux_js = require("../segment-demux-js-DANvUJgH.js");
12
12
  let node_os = require("node:os");
13
13
  node_os = require_chunk.__toESM(node_os);
14
14
  let node_crypto = require("node:crypto");
@@ -1,10 +1,10 @@
1
1
  import { r as __toESM } from "../chunk-DnnnRqeS.mjs";
2
- import { $ as declareLogChannel, $t as webrtcSessionCapability, Cn as parseProfileBrokerId, Dn as array, En as _enum, Fn as record, In as string, J as cameraStreamsCapability, Ln as union, M as RATE_CONTROL_RELAXED, Mn as number, N as RATE_CONTROL_TIGHT, Nn as object, On as boolean, Pt as rankStreams, Q as createLogChannelsProvider, Rn as EventCategory, S as EncodeProfileSchema, T as G711_SCALE_CORRECTION_DB, U as addonWidgetsSourceCapability, Vt as resolveEgressDecodeHwAccel, X as clipExportFailureOf, Yt as streamBrokerCapability, Z as createHwAccelCache, a as BatteryStatusSchema, an as isSoftwareDecode, at as egressTranscodeSharingKey, bn as makeSourceBrokerId, cn as CAM_PROFILE_ORDER, dn as DeviceType, en as errMsg, gn as expandAudioChunkToF32le, in as invocationFromEncodeProfile, jn as literal, kn as discriminatedUnion, ln as CamProfileSchema, o as CLIP_BROKER_PACED_RATES, on as BOOT_RECOVERY_BACKOFF_MS, ot as egressTransportFromRequest, pn as createEvent, q as batteryCapability, rn as buildFfmpegArgs$1, s as CLIP_STILL_REASON_CODE_HEADER, sn as BaseAddon, tn as AUDIO_PRESETS, tt as deriveBatteryPresence, un as DeviceFeature, vn as isEvent, vt as loadContributionCapability, xn as nodePin, xt as maskUrlCredentials, yn as makeProfileBrokerId, yt as logChannelsCapability, z as RingBuffer } from "../dist-CqhrlD0m.mjs";
3
- import { i as NO_COST_CLAIM, n as Fmp4FragmentChild, o as probeFfmpegBinary, r as Fmp4FragmentPlane, t as ChildCostRegistry } from "../node-CZ1Z3f6z.mjs";
2
+ import { $ as declareLogChannel, $t as webrtcSessionCapability, Cn as parseProfileBrokerId, Dn as array, En as _enum, Fn as record, In as string, J as cameraStreamsCapability, Ln as union, M as RATE_CONTROL_RELAXED, Mn as number, N as RATE_CONTROL_TIGHT, Nn as object, On as boolean, Pt as rankStreams, Q as createLogChannelsProvider, Rn as EventCategory, S as EncodeProfileSchema, T as G711_SCALE_CORRECTION_DB, U as addonWidgetsSourceCapability, Vt as resolveEgressDecodeHwAccel, X as clipExportFailureOf, Yt as streamBrokerCapability, Z as createHwAccelCache, a as BatteryStatusSchema, an as isSoftwareDecode, at as egressTranscodeSharingKey, bn as makeSourceBrokerId, cn as CAM_PROFILE_ORDER, dn as DeviceType, en as errMsg, gn as expandAudioChunkToF32le, in as invocationFromEncodeProfile, jn as literal, kn as discriminatedUnion, ln as CamProfileSchema, o as CLIP_BROKER_PACED_RATES, on as BOOT_RECOVERY_BACKOFF_MS, ot as egressTransportFromRequest, pn as createEvent, q as batteryCapability, rn as buildFfmpegArgs$1, s as CLIP_STILL_REASON_CODE_HEADER, sn as BaseAddon, tn as AUDIO_PRESETS, tt as deriveBatteryPresence, un as DeviceFeature, vn as isEvent, vt as loadContributionCapability, xn as nodePin, xt as maskUrlCredentials, yn as makeProfileBrokerId, yt as logChannelsCapability, z as RingBuffer } from "../dist-DvzAabca.mjs";
3
+ import { i as NO_COST_CLAIM, n as Fmp4FragmentChild, o as probeFfmpegBinary, r as Fmp4FragmentPlane, t as ChildCostRegistry } from "../node-DnP_6GBZ.mjs";
4
4
  import { a as parseRestreamPath, d as PREBUFFER_MAX_MS, f as capPreRollRequestMs, i as isLiveEdgeOnlyDial, m as resolvePrebuffer, n as NO_DECLARATION, p as prebufferRetentionMs, s as sdpVariantFor, u as withSentryIntent } from "../restream-intent-DyGmLAU9.mjs";
5
5
  import { n as profileForStreamId } from "../remote-restream-BeHi78PZ.mjs";
6
6
  import { n as RowMapStore, t as retireRootKeys } from "../retire-root-keys-DZvlso2l.mjs";
7
- import { a as avccSampleToAnnexB, i as require_mp4box_all, n as demuxSegmentPreferJs, o as buildKeyframeAnnexB, r as runFfmpegOnce, s as parseNalLengthSize, t as demuxSegmentFullJs } from "../segment-demux-js-Cydmp9fc.mjs";
7
+ import { a as avccSampleToAnnexB, i as require_mp4box_all, n as demuxSegmentPreferJs, o as buildKeyframeAnnexB, r as runFfmpegOnce, s as parseNalLengthSize, t as demuxSegmentFullJs } from "../segment-demux-js-DBqdboBI.mjs";
8
8
  import { createRequire } from "node:module";
9
9
  import * as os from "node:os";
10
10
  import { networkInterfaces, tmpdir } from "node:os";
@@ -30,7 +30,7 @@ async function d(e) {
30
30
  }
31
31
  }
32
32
  async function f() {
33
- return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-C7I6DjP3.mjs")).catch((e) => {
33
+ return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-D0etdxl0.mjs")).catch((e) => {
34
34
  throw l = void 0, e;
35
35
  }), l;
36
36
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-pipeline",
3
- "version": "1.2.300",
3
+ "version": "1.2.301",
4
4
  "description": "Pipeline bundle — runner, detection, motion, audio + stream broker. Multi-entry npm package shipping pipeline addons under a single bundle.",
5
5
  "keywords": [
6
6
  "camstack",