camstack 1.2.22 → 1.2.23

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.
@@ -40771,25 +40771,32 @@ var DETAIL_CROP_PADDING_FIELD = {
40771
40771
  var NativeLeaseAdmissionSchema = external_exports.enum(["all", "inferred"]);
40772
40772
  var NativeLeaseSettingsSchema = external_exports.object({
40773
40773
  /**
40774
- * How long a retained native frame is served before it counts as a miss.
40774
+ * How many delivered frames the worker HOLDS at once, waiting for each one's
40775
+ * detection result.
40775
40776
  *
40776
- * Must cover the FULL late-crop horizon: detection inference + the
40777
- * cross-process inference-result hop to hub post-analysis + tracking + the
40778
- * tRPC crop round-trip back. Below ~500 ms the busiest cameras' subject crops
40779
- * outrun it and fall back to the ≤640 detection frame; above ~3 s the resident
40780
- * RAM per busy camera grows linearly with no measured hit-rate gain.
40777
+ * This replaced a TTL on 2026-08-13, and the replacement is the whole point:
40778
+ * a time window was never related to the event the pixels were waiting for.
40779
+ * A held frame now lives from delivery until the runner has its `FrameResult`
40780
+ * at which moment the runner cuts the subject tiles it actually wanted and
40781
+ * releases the frame. The bound exists only so a runner that stops answering
40782
+ * cannot pin RAM: above it the OLDEST held frame is dropped and counted.
40783
+ *
40784
+ * Sizing: the steady state is `inferenceLatency × deliveredFps`, measured at
40785
+ * 40-160 ms × ≤25 fps = 1-4 frames. The default leaves headroom for a hiccup
40786
+ * without ever approaching the old resident set (43 frames × 24.9 MB at 4K).
40787
+ * Raising it does not buy hit rate — it buys tolerance for a slow runner, and
40788
+ * `holdOverflow` on the metrics line is what says you need it.
40781
40789
  */
40782
- ttlMs: external_exports.number().int().min(250).max(1e4),
40790
+ holdFrames: external_exports.number().int().min(1).max(64),
40783
40791
  /**
40784
40792
  * Hard per-decode-worker RAM ceiling for retained native frames, in MB.
40785
40793
  *
40786
- * Intended as a SAFETY ceiling with the TTL as the effective cap — but check
40787
- * which one is actually binding before reasoning from that. At the shipped
40788
- * 1024 MB and a 2 800 ms TTL, a 4K camera hits the CEILING first (~43 frames
40789
- * at ~24 MB each) and the TTL never gets to expire anything; `leaseMb` /
40790
- * `leaseFrames` on the metrics line say which. When the ceiling binds, a
40791
- * change that admits fewer frames buys retention WINDOW at constant RAM
40792
- * rather than giving RAM back — lower this knob if RAM is what you wanted.
40794
+ * Since 2026-08-13 this is a SAFETY ceiling and nothing else: `holdFrames`
40795
+ * is what decides how much is held, and the ceiling is the number above which
40796
+ * something is wrong. Before that it was the effective cap at 1024 MB with
40797
+ * a 2 800 ms TTL a 4K camera sat pinned at `leaseMb:1020, leaseFrames:43`
40798
+ * with the TTL expiring nothing, which is exactly the confusion the hold
40799
+ * removes. `leaseMb` / `leaseFrames` still say what is resident.
40793
40800
  * `0` DISABLES the lease entirely and falls the worker back to the tiny
40794
40801
  * leak-prone GPU surface ring (~85% crop miss; that is what the lease exists
40795
40802
  * to replace).
@@ -40815,19 +40822,37 @@ var NativeLeaseSettingsSchema = external_exports.object({
40815
40822
  * there is the signal that some caller names frames outside the inference set
40816
40823
  * and that this must go back to `all`.
40817
40824
  */
40818
- admission: NativeLeaseAdmissionSchema
40825
+ admission: NativeLeaseAdmissionSchema,
40826
+ /**
40827
+ * RAM ceiling per decode worker, in MB, for the SUBJECT TILES — the
40828
+ * compressed native crops the worker cuts at the moment a frame's detection
40829
+ * result arrives, and keeps long after the frame itself is freed.
40830
+ *
40831
+ * This is the knob that replaced the old retention window, and it buys about
40832
+ * three orders of magnitude more of it: a tile is one subject at native
40833
+ * resolution, JPEG-encoded (~60-120 KB on a 4K person), against ~24.9 MB for
40834
+ * the frame it was cut from. A frame on which nothing was detected costs
40835
+ * nothing at all, which is the real change — the old lease paid per FRAME and
40836
+ * was interrogated per SUBJECT.
40837
+ *
40838
+ * `0` DISABLES tiles, leaving only the hold window and the ≤640 RAM
40839
+ * fallback — i.e. the pre-2026-08-13 miss profile. Set it there only to
40840
+ * reproduce that.
40841
+ */
40842
+ tileBudgetMb: external_exports.number().int().min(0).max(1024)
40819
40843
  });
40820
40844
  var DEFAULT_NATIVE_LEASE_SETTINGS = {
40821
- ttlMs: 1200,
40845
+ holdFrames: 8,
40822
40846
  budgetMb: 1024,
40823
40847
  activityMs: 15e3,
40848
+ tileBudgetMb: 64,
40824
40849
  admission: "inferred"
40825
40850
  };
40826
- var NATIVE_LEASE_TTL_FIELD = {
40827
- min: 250,
40828
- max: 1e4,
40829
- step: 50,
40830
- default: DEFAULT_NATIVE_LEASE_SETTINGS.ttlMs
40851
+ var NATIVE_LEASE_HOLD_FIELD = {
40852
+ min: 1,
40853
+ max: 64,
40854
+ step: 1,
40855
+ default: DEFAULT_NATIVE_LEASE_SETTINGS.holdFrames
40831
40856
  };
40832
40857
  var NATIVE_LEASE_BUDGET_FIELD = {
40833
40858
  min: 0,
@@ -40841,6 +40866,12 @@ var NATIVE_LEASE_ACTIVITY_FIELD = {
40841
40866
  step: 1e3,
40842
40867
  default: DEFAULT_NATIVE_LEASE_SETTINGS.activityMs
40843
40868
  };
40869
+ var NATIVE_LEASE_TILE_BUDGET_FIELD = {
40870
+ min: 0,
40871
+ max: 1024,
40872
+ step: 16,
40873
+ default: DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb
40874
+ };
40844
40875
  var NATIVE_LEASE_ADMISSION_FIELD = {
40845
40876
  options: [{
40846
40877
  value: "all",
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runDiscover
4
- } from "./chunk-2OGTDEYC.js";
4
+ } from "./chunk-GGJX3DXD.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-AG7EDMPV.js");
41
+ await import("./launcher-SELE3BGC.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-AG7EDMPV.js");
86
+ await import("./launcher-SELE3BGC.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-JSQS63TR.js");
1133
+ const { discoverNodes, resolveHubFromDiscovered, filterHubNodes, DEFAULT_HUB_HTTPS_PORT } = await import("./discover-QCITTX74.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-2OGTDEYC.js";
8
+ } from "./chunk-GGJX3DXD.js";
9
9
  import "./chunk-LMMQX4CK.js";
10
10
  export {
11
11
  DEFAULT_HUB_HTTPS_PORT,
@@ -6378,62 +6378,30 @@ var require_first_boot_addon_plan = __commonJS({
6378
6378
  "../../server/backend/dist/first-boot-addon-plan.js"(exports) {
6379
6379
  "use strict";
6380
6380
  Object.defineProperty(exports, "__esModule", { value: true });
6381
- exports.resolveWantedVersion = resolveWantedVersion;
6382
- exports.compareVersions = compareVersions;
6383
- exports.bootstrapPinsFrom = bootstrapPinsFrom;
6384
6381
  exports.planFirstBootAddons = planFirstBootAddons;
6385
6382
  exports.formatFirstBootPlan = formatFirstBootPlan;
6386
- var EXACT_VERSION = /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/;
6387
- function resolveWantedVersion(raw) {
6388
- if (raw !== void 0 && EXACT_VERSION.test(raw))
6389
- return { spec: raw, pinned: true };
6390
- return { spec: "latest", pinned: false };
6391
- }
6392
- function compareVersions(a, b) {
6393
- if (!EXACT_VERSION.test(a) || !EXACT_VERSION.test(b))
6394
- return null;
6395
- const parse4 = (v) => v.split(/[-+]/)[0].split(".").map((n) => Number.parseInt(n, 10));
6396
- const left = parse4(a);
6397
- const right = parse4(b);
6398
- for (let i = 0; i < 3; i++) {
6399
- const l = left[i] ?? 0;
6400
- const r = right[i] ?? 0;
6401
- if (l !== r)
6402
- return l > r ? 1 : -1;
6403
- }
6404
- return 0;
6405
- }
6406
- function bootstrapPinsFrom(manifest) {
6407
- const out = {};
6408
- for (const [name, spec] of Object.entries(manifest.dependencies ?? {})) {
6409
- if (name.startsWith("@camstack/"))
6410
- out[name] = spec;
6411
- }
6412
- return out;
6413
- }
6414
6383
  function planFirstBootAddons(input) {
6415
6384
  const provided = new Set(input.closureProvided);
6416
- const decisions = input.required.map((pkg) => decide(pkg, input.closurePins[pkg], input.installed, provided));
6385
+ const decisions = input.required.map((pkg) => decide(pkg, input.installed, input.closureVersions, provided));
6417
6386
  const wouldInstall = decisions.filter((d) => d.action === "install-npm").map((d) => d.pkg);
6418
6387
  return {
6419
6388
  decisions,
6420
6389
  wouldInstall,
6421
- unpinned: decisions.filter((d) => d.action === "install-npm" && !d.want.pinned).map((d) => d.pkg),
6422
- divergent: decisions.filter((d) => d.divergent).map((d) => d.pkg),
6390
+ twoVersions: decisions.filter((d) => d.twoVersions).map((d) => d.pkg),
6423
6391
  needsRegistry: wouldInstall.length > 0
6424
6392
  };
6425
6393
  }
6426
- function decide(pkg, pin, installed, closureProvided) {
6427
- const want = resolveWantedVersion(pin);
6394
+ function decide(pkg, installed, closureVersions, closureProvided) {
6428
6395
  const hasEntry = Object.hasOwn(installed, pkg);
6429
6396
  const version = installed[pkg] ?? null;
6397
+ const closureVersion = closureVersions[pkg] ?? null;
6430
6398
  if (closureProvided.has(pkg)) {
6431
6399
  return {
6432
6400
  pkg,
6433
6401
  action: "skip-closure-provided",
6434
- want,
6435
6402
  installedVersion: version,
6436
- divergent: false,
6403
+ closureVersion,
6404
+ twoVersions: false,
6437
6405
  reason: "provided by the server closure \u2014 a copy here would shadow it (D15)"
6438
6406
  };
6439
6407
  }
@@ -6441,59 +6409,33 @@ var require_first_boot_addon_plan = __commonJS({
6441
6409
  return {
6442
6410
  pkg,
6443
6411
  action: "install-npm",
6444
- want,
6445
6412
  installedVersion: null,
6446
- divergent: false,
6447
- reason: hasEntry ? `installed copy has an unreadable package.json \u2014 fetching ${want.spec}` : want.pinned ? `absent \u2014 fetch ${want.spec}, the version the running closure pins` : "absent, and the closure carries no pin \u2014 fetching latest"
6413
+ closureVersion,
6414
+ twoVersions: false,
6415
+ reason: hasEntry ? "installed copy has an unreadable package.json \u2014 fetching latest" : "absent \u2014 fetching latest, which is the whole version contract (addons-agnostic)"
6448
6416
  };
6449
6417
  }
6418
+ const twoVersions = closureVersion !== null && closureVersion !== version;
6450
6419
  return {
6451
6420
  pkg,
6452
6421
  action: "adopt-installed",
6453
- want,
6454
6422
  installedVersion: version,
6455
- ...adoptionVerdict(version, want)
6456
- };
6457
- }
6458
- function adoptionVerdict(version, want) {
6459
- if (!want.pinned) {
6460
- return { divergent: false, reason: `installed ${version}; the closure carries no pin to check` };
6461
- }
6462
- const order = compareVersions(version, want.spec);
6463
- if (order === null) {
6464
- return { divergent: true, reason: `installed ${version} is not comparable to pin ${want.spec}` };
6465
- }
6466
- if (order === 0)
6467
- return { divergent: false, reason: `installed ${version} matches the pin` };
6468
- const sameMajor = version.split(".")[0] === want.spec.split(".")[0];
6469
- if (!sameMajor) {
6470
- return {
6471
- divergent: true,
6472
- reason: `installed ${version} is a different major from the pinned ${want.spec} \u2014 a framework contract, not a version gap`
6473
- };
6474
- }
6475
- if (order > 0) {
6476
- return {
6477
- divergent: false,
6478
- reason: `installed ${version} is ahead of the pinned ${want.spec} \u2014 a deploy outranks the image (D90)`
6479
- };
6480
- }
6481
- return {
6482
- divergent: true,
6483
- reason: `installed ${version} is BEHIND the pinned ${want.spec} \u2014 kept, because replacing it is an un-deploy`
6423
+ closureVersion,
6424
+ twoVersions,
6425
+ reason: twoVersions ? `installed ${version}; this closure carries ${closureVersion} \u2014 the installed copy is what runs (D90)` : `installed ${version} \u2014 kept`
6484
6426
  };
6485
6427
  }
6486
6428
  function formatFirstBootPlan(plan, mode) {
6487
- const header = `first-boot addon plan (${mode}) \u2014 ${plan.decisions.length} package(s), ${plan.wouldInstall.length} to install, ${plan.divergent.length} divergent`;
6429
+ const header = `first-boot addon plan (${mode}) \u2014 ${plan.decisions.length} package(s), ${plan.wouldInstall.length} to install`;
6488
6430
  const lines = [
6489
6431
  mode === "observe" ? `${header}; nothing was installed from this plan` : header
6490
6432
  ];
6491
6433
  for (const d of plan.decisions) {
6492
- const target = d.action === "install-npm" ? `@${d.want.spec}` : "";
6434
+ const target = d.action === "install-npm" ? "@latest" : "";
6493
6435
  lines.push(` ${d.pkg}${target} \u2014 ${d.action}: ${d.reason}`);
6494
6436
  }
6495
- if (plan.unpinned.length > 0) {
6496
- lines.push(` unpinned (would resolve the registry's latest): ${plan.unpinned.join(", ")} \u2014 the running closure declares no exact version for these, so what a node ends up with depends on when it booted`);
6437
+ if (plan.twoVersions.length > 0) {
6438
+ lines.push(` two versions on this node (installed vs this closure's own copy): ${plan.twoVersions.join(", ")} \u2014 INFO: the installed copy is the one that runs`);
6497
6439
  }
6498
6440
  if (!plan.needsRegistry) {
6499
6441
  lines.push(" no registry access needed \u2014 every required addon is already on disk");
@@ -23689,9 +23631,9 @@ var require_zod = __commonJS({
23689
23631
  }
23690
23632
  });
23691
23633
 
23692
- // ../system/dist/dist-DiScsb8j.js
23693
- var require_dist_DiScsb8j = __commonJS({
23694
- "../system/dist/dist-DiScsb8j.js"(exports) {
23634
+ // ../system/dist/dist-BV5Bug9t.js
23635
+ var require_dist_BV5Bug9t = __commonJS({
23636
+ "../system/dist/dist-BV5Bug9t.js"(exports) {
23695
23637
  "use strict";
23696
23638
  var zod = require_zod();
23697
23639
  var EventCategory = /* @__PURE__ */ (function(EventCategory2) {
@@ -51812,25 +51754,32 @@ var require_dist_DiScsb8j = __commonJS({
51812
51754
  var NativeLeaseAdmissionSchema = zod.z.enum(["all", "inferred"]);
51813
51755
  zod.z.object({
51814
51756
  /**
51815
- * How long a retained native frame is served before it counts as a miss.
51757
+ * How many delivered frames the worker HOLDS at once, waiting for each one's
51758
+ * detection result.
51759
+ *
51760
+ * This replaced a TTL on 2026-08-13, and the replacement is the whole point:
51761
+ * a time window was never related to the event the pixels were waiting for.
51762
+ * A held frame now lives from delivery until the runner has its `FrameResult`
51763
+ * — at which moment the runner cuts the subject tiles it actually wanted and
51764
+ * releases the frame. The bound exists only so a runner that stops answering
51765
+ * cannot pin RAM: above it the OLDEST held frame is dropped and counted.
51816
51766
  *
51817
- * Must cover the FULL late-crop horizon: detection inference + the
51818
- * cross-process inference-result hop to hub post-analysis + tracking + the
51819
- * tRPC crop round-trip back. Below ~500 ms the busiest cameras' subject crops
51820
- * outrun it and fall back to the ≤640 detection frame; above ~3 s the resident
51821
- * RAM per busy camera grows linearly with no measured hit-rate gain.
51767
+ * Sizing: the steady state is `inferenceLatency × deliveredFps`, measured at
51768
+ * 40-160 ms × ≤25 fps = 1-4 frames. The default leaves headroom for a hiccup
51769
+ * without ever approaching the old resident set (43 frames × 24.9 MB at 4K).
51770
+ * Raising it does not buy hit rate it buys tolerance for a slow runner, and
51771
+ * `holdOverflow` on the metrics line is what says you need it.
51822
51772
  */
51823
- ttlMs: zod.z.number().int().min(250).max(1e4),
51773
+ holdFrames: zod.z.number().int().min(1).max(64),
51824
51774
  /**
51825
51775
  * Hard per-decode-worker RAM ceiling for retained native frames, in MB.
51826
51776
  *
51827
- * Intended as a SAFETY ceiling with the TTL as the effective cap — but check
51828
- * which one is actually binding before reasoning from that. At the shipped
51829
- * 1024 MB and a 2 800 ms TTL, a 4K camera hits the CEILING first (~43 frames
51830
- * at ~24 MB each) and the TTL never gets to expire anything; `leaseMb` /
51831
- * `leaseFrames` on the metrics line say which. When the ceiling binds, a
51832
- * change that admits fewer frames buys retention WINDOW at constant RAM
51833
- * rather than giving RAM back — lower this knob if RAM is what you wanted.
51777
+ * Since 2026-08-13 this is a SAFETY ceiling and nothing else: `holdFrames`
51778
+ * is what decides how much is held, and the ceiling is the number above which
51779
+ * something is wrong. Before that it was the effective cap at 1024 MB with
51780
+ * a 2 800 ms TTL a 4K camera sat pinned at `leaseMb:1020, leaseFrames:43`
51781
+ * with the TTL expiring nothing, which is exactly the confusion the hold
51782
+ * removes. `leaseMb` / `leaseFrames` still say what is resident.
51834
51783
  * `0` DISABLES the lease entirely and falls the worker back to the tiny
51835
51784
  * leak-prone GPU surface ring (~85% crop miss; that is what the lease exists
51836
51785
  * to replace).
@@ -51856,17 +51805,36 @@ var require_dist_DiScsb8j = __commonJS({
51856
51805
  * there is the signal that some caller names frames outside the inference set
51857
51806
  * and that this must go back to `all`.
51858
51807
  */
51859
- admission: NativeLeaseAdmissionSchema
51808
+ admission: NativeLeaseAdmissionSchema,
51809
+ /**
51810
+ * RAM ceiling per decode worker, in MB, for the SUBJECT TILES — the
51811
+ * compressed native crops the worker cuts at the moment a frame's detection
51812
+ * result arrives, and keeps long after the frame itself is freed.
51813
+ *
51814
+ * This is the knob that replaced the old retention window, and it buys about
51815
+ * three orders of magnitude more of it: a tile is one subject at native
51816
+ * resolution, JPEG-encoded (~60-120 KB on a 4K person), against ~24.9 MB for
51817
+ * the frame it was cut from. A frame on which nothing was detected costs
51818
+ * nothing at all, which is the real change — the old lease paid per FRAME and
51819
+ * was interrogated per SUBJECT.
51820
+ *
51821
+ * `0` DISABLES tiles, leaving only the hold window and the ≤640 RAM
51822
+ * fallback — i.e. the pre-2026-08-13 miss profile. Set it there only to
51823
+ * reproduce that.
51824
+ */
51825
+ tileBudgetMb: zod.z.number().int().min(0).max(1024)
51860
51826
  });
51861
51827
  var DEFAULT_NATIVE_LEASE_SETTINGS = {
51862
- ttlMs: 1200,
51828
+ holdFrames: 8,
51863
51829
  budgetMb: 1024,
51864
51830
  activityMs: 15e3,
51831
+ tileBudgetMb: 64,
51865
51832
  admission: "inferred"
51866
51833
  };
51867
- DEFAULT_NATIVE_LEASE_SETTINGS.ttlMs;
51834
+ DEFAULT_NATIVE_LEASE_SETTINGS.holdFrames;
51868
51835
  DEFAULT_NATIVE_LEASE_SETTINGS.budgetMb;
51869
51836
  DEFAULT_NATIVE_LEASE_SETTINGS.activityMs;
51837
+ DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb;
51870
51838
  DEFAULT_NATIVE_LEASE_SETTINGS.admission;
51871
51839
  var ADDON_ID_PREFIX = "addon:";
51872
51840
  function bareAddonId(id) {
@@ -52563,7 +52531,7 @@ var require_alerts_addon = __commonJS({
52563
52531
  [Symbol.toStringTag]: { value: "Module" }
52564
52532
  });
52565
52533
  require_chunk_Cek0wNdY();
52566
- var require_dist10 = require_dist_DiScsb8j();
52534
+ var require_dist10 = require_dist_BV5Bug9t();
52567
52535
  function selectExpired(alerts, cutoffMs) {
52568
52536
  return alerts.filter((a) => a.createdAt < cutoffMs).sort((a, b) => a.createdAt - b.createdAt).map((a) => a.id);
52569
52537
  }
@@ -53376,7 +53344,7 @@ var require_console_logging = __commonJS({
53376
53344
  [Symbol.toStringTag]: { value: "Module" }
53377
53345
  });
53378
53346
  require_chunk_Cek0wNdY();
53379
- var require_dist10 = require_dist_DiScsb8j();
53347
+ var require_dist10 = require_dist_BV5Bug9t();
53380
53348
  var require_formatter = require_formatter_DqAKDlvN();
53381
53349
  var LEVEL_RANK = {
53382
53350
  debug: 0,
@@ -53470,7 +53438,7 @@ var require_core_blocks_addon = __commonJS({
53470
53438
  "use strict";
53471
53439
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
53472
53440
  var require_chunk = require_chunk_Cek0wNdY();
53473
- var require_dist10 = require_dist_DiScsb8j();
53441
+ var require_dist10 = require_dist_BV5Bug9t();
53474
53442
  var node_crypto = __require("crypto");
53475
53443
  var node_fs_promises = __require("fs/promises");
53476
53444
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -56168,7 +56136,7 @@ var require_device_manager_addon = __commonJS({
56168
56136
  [Symbol.toStringTag]: { value: "Module" }
56169
56137
  });
56170
56138
  require_chunk_Cek0wNdY();
56171
- var require_dist10 = require_dist_DiScsb8j();
56139
+ var require_dist10 = require_dist_BV5Bug9t();
56172
56140
  var node_crypto = __require("crypto");
56173
56141
  var _camstack_types_node = require_node();
56174
56142
  var JOB_HISTORY = 20;
@@ -60050,7 +60018,7 @@ var require_hub_forwarder = __commonJS({
60050
60018
  [Symbol.toStringTag]: { value: "Module" }
60051
60019
  });
60052
60020
  require_chunk_Cek0wNdY();
60053
- var require_dist10 = require_dist_DiScsb8j();
60021
+ var require_dist10 = require_dist_BV5Bug9t();
60054
60022
  var require_formatter = require_formatter_DqAKDlvN();
60055
60023
  var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
60056
60024
  var HubForwarderDestination = class {
@@ -60187,7 +60155,7 @@ var require_liveness_monitor_addon = __commonJS({
60187
60155
  "use strict";
60188
60156
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
60189
60157
  require_chunk_Cek0wNdY();
60190
- var require_dist10 = require_dist_DiScsb8j();
60158
+ var require_dist10 = require_dist_BV5Bug9t();
60191
60159
  var NO_DEVICES = "liveness:no-devices";
60192
60160
  var ALL_OFFLINE = "liveness:all-devices-offline";
60193
60161
  var NO_FOOTAGE_PREFIX = "liveness:no-footage:";
@@ -60377,7 +60345,7 @@ var require_local_auth_addon = __commonJS({
60377
60345
  [Symbol.toStringTag]: { value: "Module" }
60378
60346
  });
60379
60347
  var require_chunk = require_chunk_Cek0wNdY();
60380
- var require_dist10 = require_dist_DiScsb8j();
60348
+ var require_dist10 = require_dist_BV5Bug9t();
60381
60349
  var node_crypto = __require("crypto");
60382
60350
  node_crypto = require_chunk.__toESM(node_crypto);
60383
60351
  var crypto$1 = __require("crypto");
@@ -68061,7 +68029,7 @@ var require_loki_logging = __commonJS({
68061
68029
  [Symbol.toStringTag]: { value: "Module" }
68062
68030
  });
68063
68031
  require_chunk_Cek0wNdY();
68064
- var require_dist10 = require_dist_DiScsb8j();
68032
+ var require_dist10 = require_dist_BV5Bug9t();
68065
68033
  function sanitizeLabelName(raw) {
68066
68034
  const replaced = raw.replaceAll(/[^a-zA-Z0-9_]/g, "_");
68067
68035
  return /^[a-zA-Z_]/.test(replaced) ? replaced : `_${replaced}`;
@@ -68626,7 +68594,7 @@ var require_native_metrics_addon = __commonJS({
68626
68594
  [Symbol.toStringTag]: { value: "Module" }
68627
68595
  });
68628
68596
  var require_chunk = require_chunk_Cek0wNdY();
68629
- var require_dist10 = require_dist_DiScsb8j();
68597
+ var require_dist10 = require_dist_BV5Bug9t();
68630
68598
  var node_child_process = __require("child_process");
68631
68599
  var node_util = __require("util");
68632
68600
  var node_os = __require("os");
@@ -69568,7 +69536,7 @@ var require_filesystem_storage_addon = __commonJS({
69568
69536
  [Symbol.toStringTag]: { value: "Module" }
69569
69537
  });
69570
69538
  var require_chunk = require_chunk_Cek0wNdY();
69571
- var require_dist10 = require_dist_DiScsb8j();
69539
+ var require_dist10 = require_dist_BV5Bug9t();
69572
69540
  var node_crypto = __require("crypto");
69573
69541
  var node_fs_promises = __require("fs/promises");
69574
69542
  var node_path = __require("path");
@@ -70684,7 +70652,7 @@ var require_sqlite_settings_addon = __commonJS({
70684
70652
  [Symbol.toStringTag]: { value: "Module" }
70685
70653
  });
70686
70654
  var require_chunk = require_chunk_Cek0wNdY();
70687
- var require_dist10 = require_dist_DiScsb8j();
70655
+ var require_dist10 = require_dist_BV5Bug9t();
70688
70656
  var node_crypto = __require("crypto");
70689
70657
  var node_fs = __require("fs");
70690
70658
  var node_module = __require("module");
@@ -72199,7 +72167,7 @@ var require_storage_orchestrator_addon = __commonJS({
72199
72167
  [Symbol.toStringTag]: { value: "Module" }
72200
72168
  });
72201
72169
  var require_chunk = require_chunk_Cek0wNdY();
72202
- var require_dist10 = require_dist_DiScsb8j();
72170
+ var require_dist10 = require_dist_BV5Bug9t();
72203
72171
  var node_crypto = __require("crypto");
72204
72172
  var node_fs_promises = __require("fs/promises");
72205
72173
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -74040,7 +74008,7 @@ var require_system_config_addon = __commonJS({
74040
74008
  [Symbol.toStringTag]: { value: "Module" }
74041
74009
  });
74042
74010
  require_chunk_Cek0wNdY();
74043
- var require_dist10 = require_dist_DiScsb8j();
74011
+ var require_dist10 = require_dist_BV5Bug9t();
74044
74012
  var SECTION_TITLES = {
74045
74013
  server: "Server",
74046
74014
  auth: "Authentication"
@@ -92101,7 +92069,7 @@ var require_winston_logging = __commonJS({
92101
92069
  [Symbol.toStringTag]: { value: "Module" }
92102
92070
  });
92103
92071
  var require_chunk = require_chunk_Cek0wNdY();
92104
- var require_dist10 = require_dist_DiScsb8j();
92072
+ var require_dist10 = require_dist_BV5Bug9t();
92105
92073
  var require_formatter = require_formatter_DqAKDlvN();
92106
92074
  var node_path = __require("path");
92107
92075
  node_path = require_chunk.__toESM(node_path);
@@ -114114,7 +114082,7 @@ var require_dist3 = __commonJS({
114114
114082
  "use strict";
114115
114083
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
114116
114084
  var require_chunk = require_chunk_Cek0wNdY();
114117
- var require_dist10 = require_dist_DiScsb8j();
114085
+ var require_dist10 = require_dist_BV5Bug9t();
114118
114086
  var require_builtins_alerts_alerts_addon = require_alerts_addon();
114119
114087
  require_alerts();
114120
114088
  var require_formatter = require_formatter_DqAKDlvN();
@@ -117666,23 +117634,15 @@ var require_dist3 = __commonJS({
117666
117634
  * installs from the admin UI go through `install()` instead, which
117667
117635
  * defaults to npm in production.
117668
117636
  *
117669
- * @param packages optional custom package list (default: REQUIRED_PACKAGES)
117670
- * @param pins — optional `name exact version` map. A named package is
117671
- * fetched at THAT version instead of the registry's `latest`.
117672
- *
117673
- * Preparation for [D45](../../../../docs/decisions/adr-0045.md) task 32: the
117674
- * image seed answers first today, so `latest` has never been the version a
117675
- * node actually got. Once the image stops baking an addon tree under `/opt`
117676
- * this call IS the answer, and it has to be the version the running closure was
117677
- * published with — otherwise a node fetches latest-of-everything and its
117678
- * addon set depends on the minute it first booted. Passing nothing keeps
117679
- * exactly today's behaviour, and `launcher.ts` passes nothing yet.
117637
+ * There is no version argument and there is deliberately no pin: the system is
117638
+ * addons-agnostic and `latest` is the whole contract at first boot (operator,
117639
+ * 2026-08-13). A copy already under the addon root is never replaced either —
117640
+ * bootstrap is seed-only, and overwriting a deployed bundle would be an
117641
+ * un-deploy ([D90](../../../../docs/decisions/adr-0090.md)).
117680
117642
  *
117681
- * A pin never triggers a re-install: bootstrap stays seed-only, so a copy
117682
- * already under the addon root is left alone whatever its version. Replacing
117683
- * it would be an un-deploy ([D90](../../../../docs/decisions/adr-0090.md)).
117643
+ * @param packages optional custom package list (default: REQUIRED_PACKAGES)
117684
117644
  */
117685
- async ensureRequiredPackages(packages, pins) {
117645
+ async ensureRequiredPackages(packages) {
117686
117646
  const pkgList = packages ?? AddonInstaller2.REQUIRED_PACKAGES;
117687
117647
  ensureDir(this.addonsDir);
117688
117648
  const isLocal = this.installSource !== "npm" && this.workspaceDir != null;
@@ -117710,7 +117670,7 @@ var require_dist3 = __commonJS({
117710
117670
  }
117711
117671
  this.logger.info(`${packageName} \u2014 not found locally, trying npm`);
117712
117672
  }
117713
- await this.installFromNpm(packageName, pins?.[packageName]);
117673
+ await this.installFromNpm(packageName);
117714
117674
  } catch (err) {
117715
117675
  const msg = require_dist10.errMsg(err);
117716
117676
  if (packageName === "@camstack/system") throw new Error(`Required package ${packageName} failed to install: ${msg}`, { cause: err });
@@ -233137,6 +233097,271 @@ var require_agent_http = __commonJS({
233137
233097
  }
233138
233098
  });
233139
233099
 
233100
+ // ../../server/backend/dist/single-copy-cleanup.js
233101
+ var require_single_copy_cleanup = __commonJS({
233102
+ "../../server/backend/dist/single-copy-cleanup.js"(exports) {
233103
+ "use strict";
233104
+ Object.defineProperty(exports, "__esModule", { value: true });
233105
+ exports.CLOSURE_PROVIDED_PACKAGES = void 0;
233106
+ exports.planSingleCopyCleanup = planSingleCopyCleanup;
233107
+ exports.executeSingleCopyCleanup = executeSingleCopyCleanup;
233108
+ exports.formatCleanupPlan = formatCleanupPlan;
233109
+ exports.discoverRedundantCopies = discoverRedundantCopies;
233110
+ exports.isCleanupEnabled = isCleanupEnabled;
233111
+ var IMAGE_PREFIX = "/opt/";
233112
+ function planSingleCopyCleanup(input) {
233113
+ const blockedReason = nodeWideBlock(input);
233114
+ if (blockedReason !== null) {
233115
+ return {
233116
+ remove: [],
233117
+ keep: input.candidates.map((candidate) => ({ candidate, reason: blockedReason })),
233118
+ blocked: true,
233119
+ blockedReason
233120
+ };
233121
+ }
233122
+ const remove = [];
233123
+ const keep = [];
233124
+ for (const candidate of input.candidates) {
233125
+ const refusal = perCandidateRefusal(candidate, input);
233126
+ if (refusal === null)
233127
+ remove.push(candidate);
233128
+ else
233129
+ keep.push({ candidate, reason: refusal });
233130
+ }
233131
+ return { remove, keep, blocked: false, blockedReason: null };
233132
+ }
233133
+ function nodeWideBlock(input) {
233134
+ if (!input.bootHealthy) {
233135
+ return "this boot is not confirmed healthy \u2014 the redundant copies are the recovery path and stay";
233136
+ }
233137
+ if (input.activeRoot === null) {
233138
+ return "baked mode: there is no active closure, so the node is running FROM the fallback tree";
233139
+ }
233140
+ if (input.closureResolvedFrom === null) {
233141
+ return "the process resolved no @camstack/system at all \u2014 nothing here is safe to remove";
233142
+ }
233143
+ if (!isInside(input.closureResolvedFrom, input.activeRoot)) {
233144
+ return `@camstack/system resolved from ${input.closureResolvedFrom}, which is OUTSIDE the active closure \u2014 the copy being removed could be the one in memory`;
233145
+ }
233146
+ return null;
233147
+ }
233148
+ function perCandidateRefusal(candidate, input) {
233149
+ if (input.activeRoot !== null && isInside(candidate.path, input.activeRoot)) {
233150
+ return "inside the active closure \u2014 this is the copy that runs, not a redundant one";
233151
+ }
233152
+ if (candidate.path.startsWith(IMAGE_PREFIX)) {
233153
+ return "an image tree \u2014 the operator keeps it as the first-boot and fallback source";
233154
+ }
233155
+ const onNodePath = input.nodePathEntries.some((entry) => entry === candidate.path || isInside(entry, candidate.path));
233156
+ if (onNodePath) {
233157
+ return "still on NODE_PATH \u2014 a live resolution path, whatever the boot mode says";
233158
+ }
233159
+ return null;
233160
+ }
233161
+ function isInside(child, parent) {
233162
+ const normalise = (p2) => p2.endsWith("/") ? p2.slice(0, -1) : p2;
233163
+ const c = normalise(child);
233164
+ const p = normalise(parent);
233165
+ return c === p || c.startsWith(`${p}/`);
233166
+ }
233167
+ async function executeSingleCopyCleanup(plan, fs, log) {
233168
+ if (plan.blocked) {
233169
+ log(`single-copy cleanup REFUSED \u2014 ${plan.blockedReason ?? "blocked"}`);
233170
+ return { removed: [], failed: [], refused: true };
233171
+ }
233172
+ const removed = [];
233173
+ const failed = [];
233174
+ for (const candidate of plan.remove) {
233175
+ if (!fs.exists(candidate.path))
233176
+ continue;
233177
+ const label = `${candidate.pkg ?? candidate.kind} ${candidate.version ?? "<unknown version>"}`;
233178
+ const aside = `${candidate.path}.removing-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
233179
+ try {
233180
+ await fs.rename(candidate.path, aside);
233181
+ } catch (err) {
233182
+ failed.push(candidate.path);
233183
+ log(`single-copy cleanup \u2014 could NOT remove ${candidate.path} (${label}): ${errMsg(err)}`);
233184
+ continue;
233185
+ }
233186
+ removed.push(candidate.path);
233187
+ log(`single-copy cleanup \u2014 removed ${candidate.path} (${label})`);
233188
+ try {
233189
+ await fs.remove(aside);
233190
+ } catch (err) {
233191
+ log(`single-copy cleanup \u2014 ${aside} still on disk (held open?): ${errMsg(err)}`);
233192
+ }
233193
+ }
233194
+ return { removed, failed, refused: false };
233195
+ }
233196
+ function errMsg(err) {
233197
+ return err instanceof Error ? err.message : String(err);
233198
+ }
233199
+ function formatCleanupPlan(plan) {
233200
+ const lines = [];
233201
+ if (plan.blocked) {
233202
+ lines.push(`single-copy cleanup blocked \u2014 ${plan.blockedReason ?? "unknown reason"}; ${plan.keep.length} copy(ies) kept`);
233203
+ } else {
233204
+ lines.push(`single-copy cleanup \u2014 ${plan.remove.length} copy(ies) to remove`);
233205
+ }
233206
+ for (const c of plan.remove) {
233207
+ lines.push(` remove ${c.path} \u2014 ${c.pkg ?? c.kind} ${c.version ?? "<unknown version>"}`);
233208
+ }
233209
+ for (const k of plan.keep) {
233210
+ lines.push(` keep ${k.candidate.path} \u2014 ${k.candidate.pkg ?? k.candidate.kind} ${k.candidate.version ?? "<unknown version>"}: ${k.reason}`);
233211
+ }
233212
+ return lines;
233213
+ }
233214
+ exports.CLOSURE_PROVIDED_PACKAGES = [
233215
+ "@camstack/system",
233216
+ "@camstack/types",
233217
+ "@camstack/sdk",
233218
+ "@camstack/shm-ring",
233219
+ "@camstack/ui-library"
233220
+ ];
233221
+ function discoverRedundantCopies(input, fs) {
233222
+ const found = [];
233223
+ const legacyFramework = `${trimSlash(input.dataDir)}/framework`;
233224
+ if (fs.exists(legacyFramework)) {
233225
+ found.push({
233226
+ kind: "legacy-framework-tree",
233227
+ path: legacyFramework,
233228
+ pkg: null,
233229
+ version: fs.readVersion(`${legacyFramework}/node_modules/@camstack/system`)
233230
+ });
233231
+ }
233232
+ for (const pkg of exports.CLOSURE_PROVIDED_PACKAGES) {
233233
+ if (!input.closureProvides(pkg))
233234
+ continue;
233235
+ const dir = `${trimSlash(input.addonRoot)}/${pkg}`;
233236
+ if (!fs.exists(dir))
233237
+ continue;
233238
+ found.push({
233239
+ kind: "addon-root-closure-copy",
233240
+ path: dir,
233241
+ pkg,
233242
+ version: fs.readVersion(dir)
233243
+ });
233244
+ }
233245
+ return found;
233246
+ }
233247
+ function trimSlash(p) {
233248
+ return p.endsWith("/") ? p.slice(0, -1) : p;
233249
+ }
233250
+ function isCleanupEnabled(env) {
233251
+ const raw = env["CAMSTACK_SINGLE_COPY_CLEANUP"]?.trim().toLowerCase();
233252
+ return raw !== "off" && raw !== "0" && raw !== "false";
233253
+ }
233254
+ }
233255
+ });
233256
+
233257
+ // ../../server/backend/dist/single-copy-cleanup-runner.js
233258
+ var require_single_copy_cleanup_runner = __commonJS({
233259
+ "../../server/backend/dist/single-copy-cleanup-runner.js"(exports) {
233260
+ "use strict";
233261
+ var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
233262
+ if (k2 === void 0) k2 = k;
233263
+ var desc = Object.getOwnPropertyDescriptor(m, k);
233264
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
233265
+ desc = { enumerable: true, get: function() {
233266
+ return m[k];
233267
+ } };
233268
+ }
233269
+ Object.defineProperty(o, k2, desc);
233270
+ }) : (function(o, m, k, k2) {
233271
+ if (k2 === void 0) k2 = k;
233272
+ o[k2] = m[k];
233273
+ }));
233274
+ var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? (function(o, v) {
233275
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
233276
+ }) : function(o, v) {
233277
+ o["default"] = v;
233278
+ });
233279
+ var __importStar = exports && exports.__importStar || /* @__PURE__ */ (function() {
233280
+ var ownKeys = function(o) {
233281
+ ownKeys = Object.getOwnPropertyNames || function(o2) {
233282
+ var ar = [];
233283
+ for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
233284
+ return ar;
233285
+ };
233286
+ return ownKeys(o);
233287
+ };
233288
+ return function(mod) {
233289
+ if (mod && mod.__esModule) return mod;
233290
+ var result = {};
233291
+ if (mod != null) {
233292
+ for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
233293
+ }
233294
+ __setModuleDefault(result, mod);
233295
+ return result;
233296
+ };
233297
+ })();
233298
+ Object.defineProperty(exports, "__esModule", { value: true });
233299
+ exports.runSingleCopyCleanup = runSingleCopyCleanup;
233300
+ var fs = __importStar(__require("fs"));
233301
+ var path = __importStar(__require("path"));
233302
+ var single_copy_cleanup_js_1 = require_single_copy_cleanup();
233303
+ var EMPTY_RESULT = { removed: [], failed: [], refused: true };
233304
+ async function runSingleCopyCleanup(opts) {
233305
+ try {
233306
+ if (!(0, single_copy_cleanup_js_1.isCleanupEnabled)(process.env)) {
233307
+ opts.log("single-copy cleanup disabled by CAMSTACK_SINGLE_COPY_CLEANUP \u2014 nothing removed");
233308
+ return EMPTY_RESULT;
233309
+ }
233310
+ const candidates = (0, single_copy_cleanup_js_1.discoverRedundantCopies)({
233311
+ dataDir: opts.dataDir,
233312
+ addonRoot: opts.addonRoot,
233313
+ closureProvides: (pkg) => {
233314
+ try {
233315
+ __require.resolve(`${pkg}/package.json`);
233316
+ return true;
233317
+ } catch {
233318
+ return false;
233319
+ }
233320
+ }
233321
+ }, {
233322
+ exists: (p) => fs.existsSync(p),
233323
+ readVersion: (dir) => readVersion(dir)
233324
+ });
233325
+ const plan = (0, single_copy_cleanup_js_1.planSingleCopyCleanup)({
233326
+ activeRoot: process.env["CAMSTACK_SERVER_ACTIVE_ROOT"] ?? null,
233327
+ closureResolvedFrom: resolveSystemPath(),
233328
+ bootHealthy: true,
233329
+ nodePathEntries: (process.env["NODE_PATH"] ?? "").split(process.platform === "win32" ? ";" : ":").map((entry) => entry.trim()).filter((entry) => entry.length > 0),
233330
+ candidates
233331
+ });
233332
+ for (const line of (0, single_copy_cleanup_js_1.formatCleanupPlan)(plan))
233333
+ opts.log(line);
233334
+ return await (0, single_copy_cleanup_js_1.executeSingleCopyCleanup)(plan, {
233335
+ exists: (p) => fs.existsSync(p),
233336
+ rename: (from, to) => fs.renameSync(from, to),
233337
+ remove: async (p) => {
233338
+ await fs.promises.rm(p, { recursive: true, force: true });
233339
+ }
233340
+ }, opts.log);
233341
+ } catch (err) {
233342
+ opts.log(`single-copy cleanup failed: ${err instanceof Error ? err.message : String(err)} \u2014 nothing was removed`);
233343
+ return EMPTY_RESULT;
233344
+ }
233345
+ }
233346
+ function resolveSystemPath() {
233347
+ try {
233348
+ return __require.resolve("@camstack/system/package.json");
233349
+ } catch {
233350
+ return null;
233351
+ }
233352
+ }
233353
+ function readVersion(packageDir) {
233354
+ try {
233355
+ const raw = JSON.parse(fs.readFileSync(path.join(packageDir, "package.json"), "utf-8"));
233356
+ const version = typeof raw === "object" && raw !== null ? raw.version : void 0;
233357
+ return typeof version === "string" ? version : null;
233358
+ } catch {
233359
+ return null;
233360
+ }
233361
+ }
233362
+ }
233363
+ });
233364
+
233140
233365
  // ../types/dist/enums.js
233141
233366
  var require_enums = __commonJS({
233142
233367
  "../types/dist/enums.js"(exports) {
@@ -266086,32 +266311,40 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
266086
266311
  };
266087
266312
  }
266088
266313
  var NATIVE_LEASE_SECTION_ID = "native-lease";
266089
- var NATIVE_LEASE_TTL_KEY = "nativeLeaseTtlMs";
266314
+ var NATIVE_LEASE_HOLD_KEY = "nativeLeaseHoldFrames";
266090
266315
  var NATIVE_LEASE_BUDGET_KEY = "nativeLeaseBudgetMb";
266091
266316
  var NATIVE_LEASE_ACTIVITY_KEY = "nativeLeaseActivityMs";
266092
266317
  var NATIVE_LEASE_ADMISSION_KEY = "nativeLeaseAdmission";
266318
+ var NATIVE_LEASE_TILE_BUDGET_KEY = "nativeTileBudgetMb";
266093
266319
  var NativeLeaseAdmissionSchema = zod.z.enum(["all", "inferred"]);
266094
266320
  var NativeLeaseSettingsSchema = zod.z.object({
266095
266321
  /**
266096
- * How long a retained native frame is served before it counts as a miss.
266322
+ * How many delivered frames the worker HOLDS at once, waiting for each one's
266323
+ * detection result.
266324
+ *
266325
+ * This replaced a TTL on 2026-08-13, and the replacement is the whole point:
266326
+ * a time window was never related to the event the pixels were waiting for.
266327
+ * A held frame now lives from delivery until the runner has its `FrameResult`
266328
+ * — at which moment the runner cuts the subject tiles it actually wanted and
266329
+ * releases the frame. The bound exists only so a runner that stops answering
266330
+ * cannot pin RAM: above it the OLDEST held frame is dropped and counted.
266097
266331
  *
266098
- * Must cover the FULL late-crop horizon: detection inference + the
266099
- * cross-process inference-result hop to hub post-analysis + tracking + the
266100
- * tRPC crop round-trip back. Below ~500 ms the busiest cameras' subject crops
266101
- * outrun it and fall back to the ≤640 detection frame; above ~3 s the resident
266102
- * RAM per busy camera grows linearly with no measured hit-rate gain.
266332
+ * Sizing: the steady state is `inferenceLatency × deliveredFps`, measured at
266333
+ * 40-160 ms × ≤25 fps = 1-4 frames. The default leaves headroom for a hiccup
266334
+ * without ever approaching the old resident set (43 frames × 24.9 MB at 4K).
266335
+ * Raising it does not buy hit rate it buys tolerance for a slow runner, and
266336
+ * `holdOverflow` on the metrics line is what says you need it.
266103
266337
  */
266104
- ttlMs: zod.z.number().int().min(250).max(1e4),
266338
+ holdFrames: zod.z.number().int().min(1).max(64),
266105
266339
  /**
266106
266340
  * Hard per-decode-worker RAM ceiling for retained native frames, in MB.
266107
266341
  *
266108
- * Intended as a SAFETY ceiling with the TTL as the effective cap — but check
266109
- * which one is actually binding before reasoning from that. At the shipped
266110
- * 1024 MB and a 2 800 ms TTL, a 4K camera hits the CEILING first (~43 frames
266111
- * at ~24 MB each) and the TTL never gets to expire anything; `leaseMb` /
266112
- * `leaseFrames` on the metrics line say which. When the ceiling binds, a
266113
- * change that admits fewer frames buys retention WINDOW at constant RAM
266114
- * rather than giving RAM back — lower this knob if RAM is what you wanted.
266342
+ * Since 2026-08-13 this is a SAFETY ceiling and nothing else: `holdFrames`
266343
+ * is what decides how much is held, and the ceiling is the number above which
266344
+ * something is wrong. Before that it was the effective cap at 1024 MB with
266345
+ * a 2 800 ms TTL a 4K camera sat pinned at `leaseMb:1020, leaseFrames:43`
266346
+ * with the TTL expiring nothing, which is exactly the confusion the hold
266347
+ * removes. `leaseMb` / `leaseFrames` still say what is resident.
266115
266348
  * `0` DISABLES the lease entirely and falls the worker back to the tiny
266116
266349
  * leak-prone GPU surface ring (~85% crop miss; that is what the lease exists
266117
266350
  * to replace).
@@ -266137,19 +266370,37 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
266137
266370
  * there is the signal that some caller names frames outside the inference set
266138
266371
  * and that this must go back to `all`.
266139
266372
  */
266140
- admission: NativeLeaseAdmissionSchema
266373
+ admission: NativeLeaseAdmissionSchema,
266374
+ /**
266375
+ * RAM ceiling per decode worker, in MB, for the SUBJECT TILES — the
266376
+ * compressed native crops the worker cuts at the moment a frame's detection
266377
+ * result arrives, and keeps long after the frame itself is freed.
266378
+ *
266379
+ * This is the knob that replaced the old retention window, and it buys about
266380
+ * three orders of magnitude more of it: a tile is one subject at native
266381
+ * resolution, JPEG-encoded (~60-120 KB on a 4K person), against ~24.9 MB for
266382
+ * the frame it was cut from. A frame on which nothing was detected costs
266383
+ * nothing at all, which is the real change — the old lease paid per FRAME and
266384
+ * was interrogated per SUBJECT.
266385
+ *
266386
+ * `0` DISABLES tiles, leaving only the hold window and the ≤640 RAM
266387
+ * fallback — i.e. the pre-2026-08-13 miss profile. Set it there only to
266388
+ * reproduce that.
266389
+ */
266390
+ tileBudgetMb: zod.z.number().int().min(0).max(1024)
266141
266391
  });
266142
266392
  var DEFAULT_NATIVE_LEASE_SETTINGS = {
266143
- ttlMs: 1200,
266393
+ holdFrames: 8,
266144
266394
  budgetMb: 1024,
266145
266395
  activityMs: 15e3,
266396
+ tileBudgetMb: 64,
266146
266397
  admission: "inferred"
266147
266398
  };
266148
- var NATIVE_LEASE_TTL_FIELD = {
266149
- min: 250,
266150
- max: 1e4,
266151
- step: 50,
266152
- default: DEFAULT_NATIVE_LEASE_SETTINGS.ttlMs
266399
+ var NATIVE_LEASE_HOLD_FIELD = {
266400
+ min: 1,
266401
+ max: 64,
266402
+ step: 1,
266403
+ default: DEFAULT_NATIVE_LEASE_SETTINGS.holdFrames
266153
266404
  };
266154
266405
  var NATIVE_LEASE_BUDGET_FIELD = {
266155
266406
  min: 0,
@@ -266163,6 +266414,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
266163
266414
  step: 1e3,
266164
266415
  default: DEFAULT_NATIVE_LEASE_SETTINGS.activityMs
266165
266416
  };
266417
+ var NATIVE_LEASE_TILE_BUDGET_FIELD = {
266418
+ min: 0,
266419
+ max: 1024,
266420
+ step: 16,
266421
+ default: DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb
266422
+ };
266166
266423
  var NATIVE_LEASE_ADMISSION_FIELD = {
266167
266424
  options: [{
266168
266425
  value: "all",
@@ -266184,25 +266441,28 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
266184
266441
  return parsed.data === DEFAULT_NATIVE_LEASE_SETTINGS.admission ? null : parsed.data;
266185
266442
  }
266186
266443
  function readNativeLeaseOverride(config) {
266187
- const ttlMs = readKnob("ttlMs", config[NATIVE_LEASE_TTL_KEY]);
266444
+ const holdFrames = readKnob("holdFrames", config[NATIVE_LEASE_HOLD_KEY]);
266188
266445
  const budgetMb = readKnob("budgetMb", config[NATIVE_LEASE_BUDGET_KEY]);
266189
266446
  const activityMs = readKnob("activityMs", config[NATIVE_LEASE_ACTIVITY_KEY]);
266190
266447
  const admission = readAdmissionKnob(config[NATIVE_LEASE_ADMISSION_KEY]);
266448
+ const tileBudgetMb = readKnob("tileBudgetMb", config[NATIVE_LEASE_TILE_BUDGET_KEY]);
266191
266449
  return {
266192
- ...ttlMs === null ? {} : { ttlMs },
266450
+ ...holdFrames === null ? {} : { holdFrames },
266193
266451
  ...budgetMb === null ? {} : { budgetMb },
266194
266452
  ...activityMs === null ? {} : { activityMs },
266195
- ...admission === null ? {} : { admission }
266453
+ ...admission === null ? {} : { admission },
266454
+ ...tileBudgetMb === null ? {} : { tileBudgetMb }
266196
266455
  };
266197
266456
  }
266198
266457
  function isHydratedField(entry) {
266199
266458
  return typeof entry === "object" && entry !== null && "key" in entry;
266200
266459
  }
266201
266460
  var LEASE_KEYS = [
266202
- NATIVE_LEASE_TTL_KEY,
266461
+ NATIVE_LEASE_HOLD_KEY,
266203
266462
  NATIVE_LEASE_BUDGET_KEY,
266204
266463
  NATIVE_LEASE_ACTIVITY_KEY,
266205
- NATIVE_LEASE_ADMISSION_KEY
266464
+ NATIVE_LEASE_ADMISSION_KEY,
266465
+ NATIVE_LEASE_TILE_BUDGET_KEY
266206
266466
  ];
266207
266467
  function pickNativeLeaseOverride(view) {
266208
266468
  if (view === null) return {};
@@ -267611,9 +267871,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
267611
267871
  exports.NATIVE_LEASE_ADMISSION_KEY = NATIVE_LEASE_ADMISSION_KEY;
267612
267872
  exports.NATIVE_LEASE_BUDGET_FIELD = NATIVE_LEASE_BUDGET_FIELD;
267613
267873
  exports.NATIVE_LEASE_BUDGET_KEY = NATIVE_LEASE_BUDGET_KEY;
267874
+ exports.NATIVE_LEASE_HOLD_FIELD = NATIVE_LEASE_HOLD_FIELD;
267875
+ exports.NATIVE_LEASE_HOLD_KEY = NATIVE_LEASE_HOLD_KEY;
267614
267876
  exports.NATIVE_LEASE_SECTION_ID = NATIVE_LEASE_SECTION_ID;
267615
- exports.NATIVE_LEASE_TTL_FIELD = NATIVE_LEASE_TTL_FIELD;
267616
- exports.NATIVE_LEASE_TTL_KEY = NATIVE_LEASE_TTL_KEY;
267877
+ exports.NATIVE_LEASE_TILE_BUDGET_FIELD = NATIVE_LEASE_TILE_BUDGET_FIELD;
267878
+ exports.NATIVE_LEASE_TILE_BUDGET_KEY = NATIVE_LEASE_TILE_BUDGET_KEY;
267617
267879
  exports.NC_ALARM_SYSTEM_EVENT_KINDS = NC_ALARM_SYSTEM_EVENT_KINDS;
267618
267880
  exports.NC_AUDIO_DBFS_FLOOR = NC_AUDIO_DBFS_FLOOR;
267619
267881
  exports.NC_AUTHORABLE_SYSTEM_EVENT_KINDS = NC_AUTHORABLE_SYSTEM_EVENT_KINDS;
@@ -362585,6 +362847,7 @@ var require_main2 = __commonJS({
362585
362847
  var fs = __importStar(__require("fs"));
362586
362848
  var path = __importStar(__require("path"));
362587
362849
  var agent_http_js_1 = require_agent_http();
362850
+ var single_copy_cleanup_runner_js_1 = require_single_copy_cleanup_runner();
362588
362851
  var derive_hub_url_js_1 = require_derive_hub_url();
362589
362852
  var system_1 = require_dist3();
362590
362853
  var types_1 = require_dist9();
@@ -362805,6 +363068,11 @@ var require_main2 = __commonJS({
362805
363068
  } catch (err) {
362806
363069
  consoleLogger.warn(`agent root boot confirmation failed: ${err instanceof Error ? err.message : String(err)}`);
362807
363070
  }
363071
+ void (0, single_copy_cleanup_runner_js_1.runSingleCopyCleanup)({
363072
+ dataDir: config.dataDir,
363073
+ addonRoot: config.addonsDir,
363074
+ log: (line) => consoleLogger.info(line)
363075
+ });
362808
363076
  };
362809
363077
  const loggerFactory = (addonId) => agentLogManager.createLogger().withTags({ addonId });
362810
363078
  const agentServiceSchema = (0, agent_service_js_1.createAgentService)({
@@ -397832,6 +398100,7 @@ var require_main4 = __commonJS({
397832
398100
  var fs = __importStar(__require("fs"));
397833
398101
  var path = __importStar(__require("path"));
397834
398102
  var node_child_process_1 = __require("child_process");
398103
+ var single_copy_cleanup_runner_js_1 = require_single_copy_cleanup_runner();
397835
398104
  var logging_service_1 = require_logging_service();
397836
398105
  var event_bus_service_1 = require_event_bus_service();
397837
398106
  var config_service_1 = require_config_service();
@@ -398684,6 +398953,11 @@ var require_main4 = __commonJS({
398684
398953
  meta: { error: err instanceof Error ? err.message : String(err) }
398685
398954
  });
398686
398955
  }
398956
+ void (0, single_copy_cleanup_runner_js_1.runSingleCopyCleanup)({
398957
+ dataDir: dataPath,
398958
+ addonRoot: process.env["CAMSTACK_ADDONS_DIR"] ?? path.join(dataPath, "addons"),
398959
+ log: (line) => logger.info(line)
398960
+ });
398687
398961
  try {
398688
398962
  const dmForBackfill = capabilityRegistry.getSingleton("device-manager");
398689
398963
  const integrationRegistry = addonRegistry.getIntegrationRegistry();
@@ -398982,11 +399256,11 @@ var require_launcher = __commonJS({
398982
399256
  const bootstrapRequired = readBootstrapRequiredAddons(dataDir, bootstrapSchema) ?? roleDefaultBootstrap;
398983
399257
  console.log(`[launcher] bootstrap (${role}): ${bootstrapRequired.length} required package(s)`);
398984
399258
  try {
398985
- const ownManifest = readOwnManifest();
399259
+ const closureNodeModules = path.resolve(__dirname, "..", "node_modules");
398986
399260
  const plan = (0, first_boot_addon_plan_js_1.planFirstBootAddons)({
398987
399261
  required: bootstrapRequired,
398988
- closurePins: ownManifest === null ? {} : (0, first_boot_addon_plan_js_1.bootstrapPinsFrom)(ownManifest),
398989
399262
  installed: readInstalledAddonVersions(addonsDir, bootstrapRequired),
399263
+ closureVersions: readInstalledAddonVersions(closureNodeModules, bootstrapRequired),
398990
399264
  // Mirrors `shouldSkipClosureProvidedSeed`: only `@camstack/system`, and
398991
399265
  // only while it actually resolves.
398992
399266
  closureProvided: (() => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "camstack",
3
- "version": "1.2.22",
3
+ "version": "1.2.23",
4
4
  "description": "CLI tool for managing and running CamStack server",
5
5
  "keywords": [
6
6
  "camstack",