camstack 1.2.129 → 1.2.130

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.
@@ -28362,6 +28362,12 @@ var occupancyRecheckFramesField = {
28362
28362
  default: 4,
28363
28363
  step: 1
28364
28364
  };
28365
+ var preRollInferenceFramesField = {
28366
+ min: 0,
28367
+ max: 30,
28368
+ default: 12,
28369
+ step: 1
28370
+ };
28365
28371
  var MotionSourceEnum = external_exports.enum([
28366
28372
  "onboard",
28367
28373
  "analyzer",
@@ -28523,6 +28529,31 @@ var RunnerCameraConfigSchema = external_exports.object({
28523
28529
  * to every occupancy rule until something moved in front of it. The churn is
28524
28530
  * now paid on the interval instead — see `occupancyRecheckSecField`.
28525
28531
  */
28532
+ /**
28533
+ * Infer the session's PRE-ROLL — the retained history the restreamer replays
28534
+ * at session open — instead of decoding it and throwing it away.
28535
+ *
28536
+ * DEFAULT `true`, and the default is the argument. This is not a new
28537
+ * capability being offered cautiously: the pre-roll is ALREADY requested,
28538
+ * already served, already decoded and already paid for on every on-motion
28539
+ * detection session that asks for history. What shipped was a last-moment
28540
+ * discard — `FrameSlot`'s throttle compares wall clocks, and ~4 s of media
28541
+ * arriving inside a few hundred ms of wall clock looks to it like one frame's
28542
+ * worth. Device 617, 2026-09-08: a re-run of the SAME model over the stored
28543
+ * recording scored the subject `vehicle 0.5669` — above the 0.50 floor —
28544
+ * 1.68 s BEFORE the live track was born, on a frame that was in the pre-roll,
28545
+ * was decoded, and was freed.
28546
+ *
28547
+ * Shipping that as opt-in would ship the bug: an operator cannot discover a
28548
+ * setting whose absence looks exactly like a camera that noticed the cyclist
28549
+ * late. What makes ON safe is not a switch but the BOUND —
28550
+ * `preRollInferenceFrames`, a wall-clock ceiling, and a lane that never takes
28551
+ * the last inference permit — so the switch exists for the camera where the
28552
+ * history is worthless (a doorbell whose subject is always already at the
28553
+ * door), not as a hedge against the feature.
28554
+ */
28555
+ preRollInferenceEnabled: external_exports.boolean().default(true),
28556
+ preRollInferenceFrames: external_exports.number().min(preRollInferenceFramesField.min).max(preRollInferenceFramesField.max).default(preRollInferenceFramesField.default),
28526
28557
  occupancyRecheckEnabled: external_exports.boolean().default(true),
28527
28558
  occupancyRecheckSec: external_exports.number().min(occupancyRecheckSecField.min).max(occupancyRecheckSecField.max).default(occupancyRecheckSecField.default),
28528
28559
  occupancyRecheckFrames: external_exports.number().min(occupancyRecheckFramesField.min).max(occupancyRecheckFramesField.max).default(occupancyRecheckFramesField.default),
@@ -28662,6 +28693,29 @@ var RunnerCameraDeviceUIFields = [
28662
28693
  includes: "onboard"
28663
28694
  }
28664
28695
  },
28696
+ {
28697
+ key: "preRollInferenceEnabled",
28698
+ type: "boolean",
28699
+ style: "checkbox",
28700
+ label: "Detect in the pre-roll",
28701
+ description: "Run detection over the few seconds of footage the camera had already buffered when motion fired, so a subject that was in view before the trigger is found at the moment it appeared rather than seconds later. The burst is bounded and never delays live detection.",
28702
+ default: true
28703
+ },
28704
+ {
28705
+ key: "preRollInferenceFrames",
28706
+ type: "slider",
28707
+ label: "Pre-roll frames",
28708
+ description: "How many frames of buffered history may be detected on, per session. Higher samples the history more densely; 0 disables the pass.",
28709
+ min: preRollInferenceFramesField.min,
28710
+ max: preRollInferenceFramesField.max,
28711
+ step: preRollInferenceFramesField.step,
28712
+ default: preRollInferenceFramesField.default,
28713
+ showValue: true,
28714
+ showWhen: {
28715
+ field: "preRollInferenceEnabled",
28716
+ equals: true
28717
+ }
28718
+ },
28665
28719
  {
28666
28720
  key: "occupancyRecheckEnabled",
28667
28721
  type: "boolean",
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runDiscover
4
- } from "./chunk-WZY4EJWR.js";
4
+ } from "./chunk-FK6R4ZJQ.js";
5
5
  import "./chunk-LMMQX4CK.js";
6
6
 
7
7
  // src/cli.ts
@@ -38,7 +38,7 @@ async function runServe(args) {
38
38
  ...typeof values.data === "string" ? { data: values.data } : {}
39
39
  };
40
40
  Object.assign(process.env, buildServeEnv(opts));
41
- await import("./launcher-JP2K4C4Y.js");
41
+ await import("./launcher-O4PI5LJI.js");
42
42
  }
43
43
 
44
44
  // src/commands/agent.ts
@@ -83,7 +83,7 @@ async function runAgent(args) {
83
83
  ...typeof values.port === "string" ? { port: values.port } : {}
84
84
  };
85
85
  Object.assign(process.env, buildAgentEnv(opts));
86
- await import("./launcher-JP2K4C4Y.js");
86
+ await import("./launcher-O4PI5LJI.js");
87
87
  }
88
88
 
89
89
  // src/commands/setup.ts
@@ -1130,7 +1130,7 @@ function isUnknown(_value) {
1130
1130
  return true;
1131
1131
  }
1132
1132
  async function resolveServerInteractive(presetNamespace) {
1133
- const { discoverNodes, resolveHubFromDiscovered, filterHubNodes, DEFAULT_HUB_HTTPS_PORT } = await import("./discover-VXR5SN5P.js");
1133
+ const { discoverNodes, resolveHubFromDiscovered, filterHubNodes, DEFAULT_HUB_HTTPS_PORT } = await import("./discover-Q75B3UUE.js");
1134
1134
  if (presetNamespace) {
1135
1135
  const spinner4 = clack.spinner();
1136
1136
  spinner4.start(`Discovering hub on LAN (namespace "${presetNamespace}")`);
@@ -5,7 +5,7 @@ import {
5
5
  filterHubNodes,
6
6
  resolveHubFromDiscovered,
7
7
  runDiscover
8
- } from "./chunk-WZY4EJWR.js";
8
+ } from "./chunk-FK6R4ZJQ.js";
9
9
  import "./chunk-LMMQX4CK.js";
10
10
  export {
11
11
  DEFAULT_HUB_HTTPS_PORT,
@@ -23633,9 +23633,9 @@ var require_zod = __commonJS({
23633
23633
  }
23634
23634
  });
23635
23635
 
23636
- // ../system/dist/dist-WLsoGpyn.js
23637
- var require_dist_WLsoGpyn = __commonJS({
23638
- "../system/dist/dist-WLsoGpyn.js"(exports) {
23636
+ // ../system/dist/dist-9GQQ9F3s.js
23637
+ var require_dist_9GQQ9F3s = __commonJS({
23638
+ "../system/dist/dist-9GQQ9F3s.js"(exports) {
23639
23639
  "use strict";
23640
23640
  var zod = require_zod();
23641
23641
  var EventCategory = /* @__PURE__ */ (function(EventCategory2) {
@@ -39131,6 +39131,12 @@ var require_dist_WLsoGpyn = __commonJS({
39131
39131
  default: 4,
39132
39132
  step: 1
39133
39133
  };
39134
+ var preRollInferenceFramesField = {
39135
+ min: 0,
39136
+ max: 30,
39137
+ default: 12,
39138
+ step: 1
39139
+ };
39134
39140
  var MotionSourceEnum = zod.z.enum([
39135
39141
  "onboard",
39136
39142
  "analyzer",
@@ -39292,6 +39298,31 @@ var require_dist_WLsoGpyn = __commonJS({
39292
39298
  * to every occupancy rule until something moved in front of it. The churn is
39293
39299
  * now paid on the interval instead — see `occupancyRecheckSecField`.
39294
39300
  */
39301
+ /**
39302
+ * Infer the session's PRE-ROLL — the retained history the restreamer replays
39303
+ * at session open — instead of decoding it and throwing it away.
39304
+ *
39305
+ * DEFAULT `true`, and the default is the argument. This is not a new
39306
+ * capability being offered cautiously: the pre-roll is ALREADY requested,
39307
+ * already served, already decoded and already paid for on every on-motion
39308
+ * detection session that asks for history. What shipped was a last-moment
39309
+ * discard — `FrameSlot`'s throttle compares wall clocks, and ~4 s of media
39310
+ * arriving inside a few hundred ms of wall clock looks to it like one frame's
39311
+ * worth. Device 617, 2026-09-08: a re-run of the SAME model over the stored
39312
+ * recording scored the subject `vehicle 0.5669` — above the 0.50 floor —
39313
+ * 1.68 s BEFORE the live track was born, on a frame that was in the pre-roll,
39314
+ * was decoded, and was freed.
39315
+ *
39316
+ * Shipping that as opt-in would ship the bug: an operator cannot discover a
39317
+ * setting whose absence looks exactly like a camera that noticed the cyclist
39318
+ * late. What makes ON safe is not a switch but the BOUND —
39319
+ * `preRollInferenceFrames`, a wall-clock ceiling, and a lane that never takes
39320
+ * the last inference permit — so the switch exists for the camera where the
39321
+ * history is worthless (a doorbell whose subject is always already at the
39322
+ * door), not as a hedge against the feature.
39323
+ */
39324
+ preRollInferenceEnabled: zod.z.boolean().default(true),
39325
+ preRollInferenceFrames: zod.z.number().min(preRollInferenceFramesField.min).max(preRollInferenceFramesField.max).default(preRollInferenceFramesField.default),
39295
39326
  occupancyRecheckEnabled: zod.z.boolean().default(true),
39296
39327
  occupancyRecheckSec: zod.z.number().min(occupancyRecheckSecField.min).max(occupancyRecheckSecField.max).default(occupancyRecheckSecField.default),
39297
39328
  occupancyRecheckFrames: zod.z.number().min(occupancyRecheckFramesField.min).max(occupancyRecheckFramesField.max).default(occupancyRecheckFramesField.default),
@@ -39320,7 +39351,7 @@ var require_dist_WLsoGpyn = __commonJS({
39320
39351
  */
39321
39352
  inferenceDevices: zod.z.array(RunnerInferenceDeviceSchema).readonly().optional()
39322
39353
  });
39323
- motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, maxSessionHoldMsField.min, maxSessionHoldMsField.max, maxSessionHoldMsField.step, maxSessionHoldMsField.default, audioMotionWindowMsField.min, audioMotionWindowMsField.max, audioMotionWindowMsField.step, audioMotionWindowMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
39354
+ motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, maxSessionHoldMsField.min, maxSessionHoldMsField.max, maxSessionHoldMsField.step, maxSessionHoldMsField.default, audioMotionWindowMsField.min, audioMotionWindowMsField.max, audioMotionWindowMsField.step, audioMotionWindowMsField.default, preRollInferenceFramesField.min, preRollInferenceFramesField.max, preRollInferenceFramesField.step, preRollInferenceFramesField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
39324
39355
  var RunnerLocalLoadSchema = zod.z.object({
39325
39356
  /** Moleculer node id of this runner instance. */
39326
39357
  nodeId: zod.z.string(),
@@ -61277,7 +61308,7 @@ var require_alerts_addon = __commonJS({
61277
61308
  [Symbol.toStringTag]: { value: "Module" }
61278
61309
  });
61279
61310
  require_chunk_Cek0wNdY();
61280
- var require_dist10 = require_dist_WLsoGpyn();
61311
+ var require_dist10 = require_dist_9GQQ9F3s();
61281
61312
  function selectExpired(alerts, cutoffMs) {
61282
61313
  return alerts.filter((a) => a.createdAt < cutoffMs).sort((a, b) => a.createdAt - b.createdAt).map((a) => a.id);
61283
61314
  }
@@ -62096,7 +62127,7 @@ var require_console_logging = __commonJS({
62096
62127
  [Symbol.toStringTag]: { value: "Module" }
62097
62128
  });
62098
62129
  require_chunk_Cek0wNdY();
62099
- var require_dist10 = require_dist_WLsoGpyn();
62130
+ var require_dist10 = require_dist_9GQQ9F3s();
62100
62131
  var require_formatter = require_formatter_DqAKDlvN();
62101
62132
  var LEVEL_RANK = {
62102
62133
  debug: 0,
@@ -62190,7 +62221,7 @@ var require_core_blocks_addon = __commonJS({
62190
62221
  "use strict";
62191
62222
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
62192
62223
  var require_chunk = require_chunk_Cek0wNdY();
62193
- var require_dist10 = require_dist_WLsoGpyn();
62224
+ var require_dist10 = require_dist_9GQQ9F3s();
62194
62225
  var node_crypto = __require("crypto");
62195
62226
  var node_fs_promises = __require("fs/promises");
62196
62227
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -63087,11 +63118,11 @@ var require_core_blocks = __commonJS({
63087
63118
  }
63088
63119
  });
63089
63120
 
63090
- // ../system/dist/retired-settings-keys-WShMmPM4.js
63091
- var require_retired_settings_keys_WShMmPM4 = __commonJS({
63092
- "../system/dist/retired-settings-keys-WShMmPM4.js"(exports) {
63121
+ // ../system/dist/retired-settings-keys-DfdSH46H.js
63122
+ var require_retired_settings_keys_DfdSH46H = __commonJS({
63123
+ "../system/dist/retired-settings-keys-DfdSH46H.js"(exports) {
63093
63124
  "use strict";
63094
- var require_dist10 = require_dist_WLsoGpyn();
63125
+ var require_dist10 = require_dist_9GQQ9F3s();
63095
63126
  function settingsStoreIsAuthoritativeHere(env) {
63096
63127
  const raw = (env["CAMSTACK_ROLE"] ?? "").trim().toLowerCase();
63097
63128
  return raw === "" || raw === "hub";
@@ -65326,8 +65357,8 @@ var require_device_manager_addon = __commonJS({
65326
65357
  [Symbol.toStringTag]: { value: "Module" }
65327
65358
  });
65328
65359
  require_chunk_Cek0wNdY();
65329
- var require_dist10 = require_dist_WLsoGpyn();
65330
- var require_retired_settings_keys = require_retired_settings_keys_WShMmPM4();
65360
+ var require_dist10 = require_dist_9GQQ9F3s();
65361
+ var require_retired_settings_keys = require_retired_settings_keys_DfdSH46H();
65331
65362
  var node_crypto = __require("crypto");
65332
65363
  var _camstack_types_node = require_node();
65333
65364
  var JOB_HISTORY = 20;
@@ -70952,7 +70983,7 @@ var require_hub_forwarder = __commonJS({
70952
70983
  [Symbol.toStringTag]: { value: "Module" }
70953
70984
  });
70954
70985
  require_chunk_Cek0wNdY();
70955
- var require_dist10 = require_dist_WLsoGpyn();
70986
+ var require_dist10 = require_dist_9GQQ9F3s();
70956
70987
  var require_formatter = require_formatter_DqAKDlvN();
70957
70988
  var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
70958
70989
  var HubForwarderDestination = class {
@@ -71089,7 +71120,7 @@ var require_liveness_monitor_addon = __commonJS({
71089
71120
  "use strict";
71090
71121
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
71091
71122
  require_chunk_Cek0wNdY();
71092
- var require_dist10 = require_dist_WLsoGpyn();
71123
+ var require_dist10 = require_dist_9GQQ9F3s();
71093
71124
  var NO_DEVICES = "liveness:no-devices";
71094
71125
  var ALL_OFFLINE = "liveness:all-devices-offline";
71095
71126
  var NO_FOOTAGE_PREFIX = "liveness:no-footage:";
@@ -71285,7 +71316,7 @@ var require_local_auth_addon = __commonJS({
71285
71316
  [Symbol.toStringTag]: { value: "Module" }
71286
71317
  });
71287
71318
  var require_chunk = require_chunk_Cek0wNdY();
71288
- var require_dist10 = require_dist_WLsoGpyn();
71319
+ var require_dist10 = require_dist_9GQQ9F3s();
71289
71320
  var node_crypto = __require("crypto");
71290
71321
  node_crypto = require_chunk.__toESM(node_crypto);
71291
71322
  var crypto$1 = __require("crypto");
@@ -79098,7 +79129,7 @@ var require_loki_logging = __commonJS({
79098
79129
  [Symbol.toStringTag]: { value: "Module" }
79099
79130
  });
79100
79131
  require_chunk_Cek0wNdY();
79101
- var require_dist10 = require_dist_WLsoGpyn();
79132
+ var require_dist10 = require_dist_9GQQ9F3s();
79102
79133
  function sanitizeLabelName(raw) {
79103
79134
  const replaced = raw.replaceAll(/[^a-zA-Z0-9_]/g, "_");
79104
79135
  return /^[a-zA-Z_]/.test(replaced) ? replaced : `_${replaced}`;
@@ -79663,7 +79694,7 @@ var require_native_metrics_addon = __commonJS({
79663
79694
  [Symbol.toStringTag]: { value: "Module" }
79664
79695
  });
79665
79696
  var require_chunk = require_chunk_Cek0wNdY();
79666
- var require_dist10 = require_dist_WLsoGpyn();
79697
+ var require_dist10 = require_dist_9GQQ9F3s();
79667
79698
  var node_fs_promises = __require("fs/promises");
79668
79699
  var node_child_process = __require("child_process");
79669
79700
  var node_util = __require("util");
@@ -82247,7 +82278,7 @@ var require_filesystem_storage_addon = __commonJS({
82247
82278
  [Symbol.toStringTag]: { value: "Module" }
82248
82279
  });
82249
82280
  var require_chunk = require_chunk_Cek0wNdY();
82250
- var require_dist10 = require_dist_WLsoGpyn();
82281
+ var require_dist10 = require_dist_9GQQ9F3s();
82251
82282
  var node_crypto = __require("crypto");
82252
82283
  var node_fs_promises = __require("fs/promises");
82253
82284
  var node_path = __require("path");
@@ -83363,8 +83394,8 @@ var require_sqlite_settings_addon = __commonJS({
83363
83394
  [Symbol.toStringTag]: { value: "Module" }
83364
83395
  });
83365
83396
  var require_chunk = require_chunk_Cek0wNdY();
83366
- var require_dist10 = require_dist_WLsoGpyn();
83367
- var require_retired_settings_keys = require_retired_settings_keys_WShMmPM4();
83397
+ var require_dist10 = require_dist_9GQQ9F3s();
83398
+ var require_retired_settings_keys = require_retired_settings_keys_DfdSH46H();
83368
83399
  var node_crypto = __require("crypto");
83369
83400
  var node_fs = __require("fs");
83370
83401
  var node_module = __require("module");
@@ -85868,7 +85899,7 @@ var require_storage_orchestrator_addon = __commonJS({
85868
85899
  [Symbol.toStringTag]: { value: "Module" }
85869
85900
  });
85870
85901
  var require_chunk = require_chunk_Cek0wNdY();
85871
- var require_dist10 = require_dist_WLsoGpyn();
85902
+ var require_dist10 = require_dist_9GQQ9F3s();
85872
85903
  var require_hub_cap_forward = require_hub_cap_forward_DmHNjbB0();
85873
85904
  var zod = require_zod();
85874
85905
  var node_crypto = __require("crypto");
@@ -89518,7 +89549,7 @@ var require_system_config_addon = __commonJS({
89518
89549
  [Symbol.toStringTag]: { value: "Module" }
89519
89550
  });
89520
89551
  require_chunk_Cek0wNdY();
89521
- var require_dist10 = require_dist_WLsoGpyn();
89552
+ var require_dist10 = require_dist_9GQQ9F3s();
89522
89553
  var SECTION_TITLES = {
89523
89554
  server: "Server",
89524
89555
  auth: "Authentication"
@@ -107579,7 +107610,7 @@ var require_winston_logging = __commonJS({
107579
107610
  [Symbol.toStringTag]: { value: "Module" }
107580
107611
  });
107581
107612
  var require_chunk = require_chunk_Cek0wNdY();
107582
- var require_dist10 = require_dist_WLsoGpyn();
107613
+ var require_dist10 = require_dist_9GQQ9F3s();
107583
107614
  var require_formatter = require_formatter_DqAKDlvN();
107584
107615
  var node_path = __require("path");
107585
107616
  node_path = require_chunk.__toESM(node_path);
@@ -113393,6 +113424,8 @@ var require_addon = __commonJS({
113393
113424
  "pipelineEnabled": true,
113394
113425
  "zones": [],
113395
113426
  "onboardMotionDrivesAnalyzer": true,
113427
+ "preRollInferenceEnabled": true,
113428
+ "preRollInferenceFrames": 12,
113396
113429
  "occupancyRecheckEnabled": true,
113397
113430
  "occupancyRecheckSec": 300,
113398
113431
  "occupancyRecheckFrames": 4,
@@ -132191,7 +132224,7 @@ var require_dist3 = __commonJS({
132191
132224
  "use strict";
132192
132225
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
132193
132226
  var require_chunk = require_chunk_Cek0wNdY();
132194
- var require_dist10 = require_dist_WLsoGpyn();
132227
+ var require_dist10 = require_dist_9GQQ9F3s();
132195
132228
  var require_builtins_alerts_alerts_addon = require_alerts_addon();
132196
132229
  require_alerts();
132197
132230
  var require_formatter = require_formatter_DqAKDlvN();
@@ -229552,6 +229585,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
229552
229585
  default: 4,
229553
229586
  step: 1
229554
229587
  };
229588
+ var preRollInferenceFramesField = {
229589
+ min: 0,
229590
+ max: 30,
229591
+ default: 12,
229592
+ step: 1
229593
+ };
229555
229594
  var MotionSourceEnum = zod.z.enum([
229556
229595
  "onboard",
229557
229596
  "analyzer",
@@ -229713,6 +229752,31 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
229713
229752
  * to every occupancy rule until something moved in front of it. The churn is
229714
229753
  * now paid on the interval instead — see `occupancyRecheckSecField`.
229715
229754
  */
229755
+ /**
229756
+ * Infer the session's PRE-ROLL — the retained history the restreamer replays
229757
+ * at session open — instead of decoding it and throwing it away.
229758
+ *
229759
+ * DEFAULT `true`, and the default is the argument. This is not a new
229760
+ * capability being offered cautiously: the pre-roll is ALREADY requested,
229761
+ * already served, already decoded and already paid for on every on-motion
229762
+ * detection session that asks for history. What shipped was a last-moment
229763
+ * discard — `FrameSlot`'s throttle compares wall clocks, and ~4 s of media
229764
+ * arriving inside a few hundred ms of wall clock looks to it like one frame's
229765
+ * worth. Device 617, 2026-09-08: a re-run of the SAME model over the stored
229766
+ * recording scored the subject `vehicle 0.5669` — above the 0.50 floor —
229767
+ * 1.68 s BEFORE the live track was born, on a frame that was in the pre-roll,
229768
+ * was decoded, and was freed.
229769
+ *
229770
+ * Shipping that as opt-in would ship the bug: an operator cannot discover a
229771
+ * setting whose absence looks exactly like a camera that noticed the cyclist
229772
+ * late. What makes ON safe is not a switch but the BOUND —
229773
+ * `preRollInferenceFrames`, a wall-clock ceiling, and a lane that never takes
229774
+ * the last inference permit — so the switch exists for the camera where the
229775
+ * history is worthless (a doorbell whose subject is always already at the
229776
+ * door), not as a hedge against the feature.
229777
+ */
229778
+ preRollInferenceEnabled: zod.z.boolean().default(true),
229779
+ preRollInferenceFrames: zod.z.number().min(preRollInferenceFramesField.min).max(preRollInferenceFramesField.max).default(preRollInferenceFramesField.default),
229716
229780
  occupancyRecheckEnabled: zod.z.boolean().default(true),
229717
229781
  occupancyRecheckSec: zod.z.number().min(occupancyRecheckSecField.min).max(occupancyRecheckSecField.max).default(occupancyRecheckSecField.default),
229718
229782
  occupancyRecheckFrames: zod.z.number().min(occupancyRecheckFramesField.min).max(occupancyRecheckFramesField.max).default(occupancyRecheckFramesField.default),
@@ -229852,6 +229916,29 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
229852
229916
  includes: "onboard"
229853
229917
  }
229854
229918
  },
229919
+ {
229920
+ key: "preRollInferenceEnabled",
229921
+ type: "boolean",
229922
+ style: "checkbox",
229923
+ label: "Detect in the pre-roll",
229924
+ description: "Run detection over the few seconds of footage the camera had already buffered when motion fired, so a subject that was in view before the trigger is found at the moment it appeared rather than seconds later. The burst is bounded and never delays live detection.",
229925
+ default: true
229926
+ },
229927
+ {
229928
+ key: "preRollInferenceFrames",
229929
+ type: "slider",
229930
+ label: "Pre-roll frames",
229931
+ description: "How many frames of buffered history may be detected on, per session. Higher samples the history more densely; 0 disables the pass.",
229932
+ min: preRollInferenceFramesField.min,
229933
+ max: preRollInferenceFramesField.max,
229934
+ step: preRollInferenceFramesField.step,
229935
+ default: preRollInferenceFramesField.default,
229936
+ showValue: true,
229937
+ showWhen: {
229938
+ field: "preRollInferenceEnabled",
229939
+ equals: true
229940
+ }
229941
+ },
229855
229942
  {
229856
229943
  key: "occupancyRecheckEnabled",
229857
229944
  type: "boolean",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "camstack",
3
- "version": "1.2.129",
3
+ "version": "1.2.130",
4
4
  "description": "CLI tool for managing and running CamStack server",
5
5
  "keywords": [
6
6
  "camstack",