@camstack/addon-provider-gree 0.2.13 → 0.2.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/addon.js CHANGED
@@ -25144,13 +25144,24 @@ method(object({
25144
25144
  /** Playback-speed multiplier for the render (1 = realtime). */
25145
25145
  var ExportSpeedSchema = number().min(.25).max(32);
25146
25146
  /**
25147
- * One dense interval, in SECONDS FROM THE EXPORT'S OWN `fromMs`.
25147
+ * One dense interval, in WALL-CLOCK SECONDS FROM THE EXPORT'S OWN `fromMs`.
25148
25148
  *
25149
- * Relative and not absolute epoch on purpose: the renderer's frame-select
25150
- * expression sees ffmpeg's `t`, which starts at 0 for the export's source
25151
- * playlist. Handing it absolute epochs would make every call site responsible
25152
- * for the same subtraction, and the one that forgot would emit a filter that
25153
- * selects nothing silently, as a uniform timelapse.
25149
+ * **Wall clock, not ffmpeg's `t`** and the recorder translates. A caller
25150
+ * derives these bounds from things that happened at a TIME (a track's
25151
+ * `firstSeen`), while `t` runs over the source playlist: the concatenation of
25152
+ * every segment present for the range, with each recording GAP removed. The
25153
+ * two agree only on a window that recorded without one interruption, and only
25154
+ * the render side knows the segments, so the translation lives there
25155
+ * (`export-dense-map.ts`, addon-pipeline).
25156
+ *
25157
+ * It was not always so. These seconds were fed to `between(t,…)` verbatim, and
25158
+ * on a 10 h window holding 29,393 s of footage every range landed late by the
25159
+ * gap accumulated before it — up to 6,607 s, well past EOF. Nothing matched,
25160
+ * the video was a uniform timelapse, and the log line reported the five ranges
25161
+ * that had been ASKED for (2026-08-13, export `57d14363`, camera 615).
25162
+ *
25163
+ * Relative and not absolute epoch, because an absolute epoch would make every
25164
+ * call site responsible for the same subtraction.
25154
25165
  */
25155
25166
  var ExportDenseRangeSchema = object({
25156
25167
  fromSec: number().nonnegative(),
@@ -33764,25 +33775,32 @@ object({
33764
33775
  var NativeLeaseAdmissionSchema = _enum(["all", "inferred"]);
33765
33776
  object({
33766
33777
  /**
33767
- * How long a retained native frame is served before it counts as a miss.
33778
+ * How many delivered frames the worker HOLDS at once, waiting for each one's
33779
+ * detection result.
33768
33780
  *
33769
- * Must cover the FULL late-crop horizon: detection inference + the
33770
- * cross-process inference-result hop to hub post-analysis + tracking + the
33771
- * tRPC crop round-trip back. Below ~500 ms the busiest cameras' subject crops
33772
- * outrun it and fall back to the ≤640 detection frame; above ~3 s the resident
33773
- * RAM per busy camera grows linearly with no measured hit-rate gain.
33781
+ * This replaced a TTL on 2026-08-13, and the replacement is the whole point:
33782
+ * a time window was never related to the event the pixels were waiting for.
33783
+ * A held frame now lives from delivery until the runner has its `FrameResult`
33784
+ * at which moment the runner cuts the subject tiles it actually wanted and
33785
+ * releases the frame. The bound exists only so a runner that stops answering
33786
+ * cannot pin RAM: above it the OLDEST held frame is dropped and counted.
33787
+ *
33788
+ * Sizing: the steady state is `inferenceLatency × deliveredFps`, measured at
33789
+ * 40-160 ms × ≤25 fps = 1-4 frames. The default leaves headroom for a hiccup
33790
+ * without ever approaching the old resident set (43 frames × 24.9 MB at 4K).
33791
+ * Raising it does not buy hit rate — it buys tolerance for a slow runner, and
33792
+ * `holdOverflow` on the metrics line is what says you need it.
33774
33793
  */
33775
- ttlMs: number().int().min(250).max(1e4),
33794
+ holdFrames: number().int().min(1).max(64),
33776
33795
  /**
33777
33796
  * Hard per-decode-worker RAM ceiling for retained native frames, in MB.
33778
33797
  *
33779
- * Intended as a SAFETY ceiling with the TTL as the effective cap — but check
33780
- * which one is actually binding before reasoning from that. At the shipped
33781
- * 1024 MB and a 2 800 ms TTL, a 4K camera hits the CEILING first (~43 frames
33782
- * at ~24 MB each) and the TTL never gets to expire anything; `leaseMb` /
33783
- * `leaseFrames` on the metrics line say which. When the ceiling binds, a
33784
- * change that admits fewer frames buys retention WINDOW at constant RAM
33785
- * rather than giving RAM back — lower this knob if RAM is what you wanted.
33798
+ * Since 2026-08-13 this is a SAFETY ceiling and nothing else: `holdFrames`
33799
+ * is what decides how much is held, and the ceiling is the number above which
33800
+ * something is wrong. Before that it was the effective cap at 1024 MB with
33801
+ * a 2 800 ms TTL a 4K camera sat pinned at `leaseMb:1020, leaseFrames:43`
33802
+ * with the TTL expiring nothing, which is exactly the confusion the hold
33803
+ * removes. `leaseMb` / `leaseFrames` still say what is resident.
33786
33804
  * `0` DISABLES the lease entirely and falls the worker back to the tiny
33787
33805
  * leak-prone GPU surface ring (~85% crop miss; that is what the lease exists
33788
33806
  * to replace).
@@ -33808,22 +33826,45 @@ object({
33808
33826
  * there is the signal that some caller names frames outside the inference set
33809
33827
  * and that this must go back to `all`.
33810
33828
  */
33811
- admission: NativeLeaseAdmissionSchema
33829
+ admission: NativeLeaseAdmissionSchema,
33830
+ /**
33831
+ * RAM ceiling per decode worker, in MB, for the SUBJECT TILES — the
33832
+ * compressed native crops the worker cuts at the moment a frame's detection
33833
+ * result arrives, and keeps long after the frame itself is freed.
33834
+ *
33835
+ * This is the knob that replaced the old retention window, and it buys about
33836
+ * three orders of magnitude more of it: a tile is one subject at native
33837
+ * resolution, JPEG-encoded (~60-120 KB on a 4K person), against ~24.9 MB for
33838
+ * the frame it was cut from. A frame on which nothing was detected costs
33839
+ * nothing at all, which is the real change — the old lease paid per FRAME and
33840
+ * was interrogated per SUBJECT.
33841
+ *
33842
+ * `0` DISABLES tiles, leaving only the hold window and the ≤640 RAM
33843
+ * fallback — i.e. the pre-2026-08-13 miss profile. Set it there only to
33844
+ * reproduce that.
33845
+ */
33846
+ tileBudgetMb: number().int().min(0).max(1024)
33812
33847
  });
33813
33848
  /**
33814
- * The values in force when the operator has set nothing — byte-for-byte the
33815
- * constants the decode worker shipped with as env-var defaults, so making these
33816
- * settings changed no behaviour on the day it landed.
33849
+ * The values in force when the operator has set nothing.
33850
+ *
33851
+ * `budgetMb` stays at 1024 on the day the hold landed, deliberately: it stopped
33852
+ * being the retention window and became the OOM ceiling, and lowering a ceiling
33853
+ * in the same change that redefines it would make a regression and a retune
33854
+ * indistinguishable. Cut it once `tileHits` / `holdOverflow` have been read on
33855
+ * live traffic.
33817
33856
  */
33818
33857
  var DEFAULT_NATIVE_LEASE_SETTINGS = {
33819
- ttlMs: 1200,
33858
+ holdFrames: 8,
33820
33859
  budgetMb: 1024,
33821
33860
  activityMs: 15e3,
33861
+ tileBudgetMb: 64,
33822
33862
  admission: "inferred"
33823
33863
  };
33824
- DEFAULT_NATIVE_LEASE_SETTINGS.ttlMs;
33864
+ DEFAULT_NATIVE_LEASE_SETTINGS.holdFrames;
33825
33865
  DEFAULT_NATIVE_LEASE_SETTINGS.budgetMb;
33826
33866
  DEFAULT_NATIVE_LEASE_SETTINGS.activityMs;
33867
+ DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb;
33827
33868
  DEFAULT_NATIVE_LEASE_SETTINGS.admission;
33828
33869
  //#endregion
33829
33870
  //#region src/config.ts
package/dist/addon.mjs CHANGED
@@ -25143,13 +25143,24 @@ method(object({
25143
25143
  /** Playback-speed multiplier for the render (1 = realtime). */
25144
25144
  var ExportSpeedSchema = number().min(.25).max(32);
25145
25145
  /**
25146
- * One dense interval, in SECONDS FROM THE EXPORT'S OWN `fromMs`.
25146
+ * One dense interval, in WALL-CLOCK SECONDS FROM THE EXPORT'S OWN `fromMs`.
25147
25147
  *
25148
- * Relative and not absolute epoch on purpose: the renderer's frame-select
25149
- * expression sees ffmpeg's `t`, which starts at 0 for the export's source
25150
- * playlist. Handing it absolute epochs would make every call site responsible
25151
- * for the same subtraction, and the one that forgot would emit a filter that
25152
- * selects nothing silently, as a uniform timelapse.
25148
+ * **Wall clock, not ffmpeg's `t`** and the recorder translates. A caller
25149
+ * derives these bounds from things that happened at a TIME (a track's
25150
+ * `firstSeen`), while `t` runs over the source playlist: the concatenation of
25151
+ * every segment present for the range, with each recording GAP removed. The
25152
+ * two agree only on a window that recorded without one interruption, and only
25153
+ * the render side knows the segments, so the translation lives there
25154
+ * (`export-dense-map.ts`, addon-pipeline).
25155
+ *
25156
+ * It was not always so. These seconds were fed to `between(t,…)` verbatim, and
25157
+ * on a 10 h window holding 29,393 s of footage every range landed late by the
25158
+ * gap accumulated before it — up to 6,607 s, well past EOF. Nothing matched,
25159
+ * the video was a uniform timelapse, and the log line reported the five ranges
25160
+ * that had been ASKED for (2026-08-13, export `57d14363`, camera 615).
25161
+ *
25162
+ * Relative and not absolute epoch, because an absolute epoch would make every
25163
+ * call site responsible for the same subtraction.
25153
25164
  */
25154
25165
  var ExportDenseRangeSchema = object({
25155
25166
  fromSec: number().nonnegative(),
@@ -33763,25 +33774,32 @@ object({
33763
33774
  var NativeLeaseAdmissionSchema = _enum(["all", "inferred"]);
33764
33775
  object({
33765
33776
  /**
33766
- * How long a retained native frame is served before it counts as a miss.
33777
+ * How many delivered frames the worker HOLDS at once, waiting for each one's
33778
+ * detection result.
33767
33779
  *
33768
- * Must cover the FULL late-crop horizon: detection inference + the
33769
- * cross-process inference-result hop to hub post-analysis + tracking + the
33770
- * tRPC crop round-trip back. Below ~500 ms the busiest cameras' subject crops
33771
- * outrun it and fall back to the ≤640 detection frame; above ~3 s the resident
33772
- * RAM per busy camera grows linearly with no measured hit-rate gain.
33780
+ * This replaced a TTL on 2026-08-13, and the replacement is the whole point:
33781
+ * a time window was never related to the event the pixels were waiting for.
33782
+ * A held frame now lives from delivery until the runner has its `FrameResult`
33783
+ * at which moment the runner cuts the subject tiles it actually wanted and
33784
+ * releases the frame. The bound exists only so a runner that stops answering
33785
+ * cannot pin RAM: above it the OLDEST held frame is dropped and counted.
33786
+ *
33787
+ * Sizing: the steady state is `inferenceLatency × deliveredFps`, measured at
33788
+ * 40-160 ms × ≤25 fps = 1-4 frames. The default leaves headroom for a hiccup
33789
+ * without ever approaching the old resident set (43 frames × 24.9 MB at 4K).
33790
+ * Raising it does not buy hit rate — it buys tolerance for a slow runner, and
33791
+ * `holdOverflow` on the metrics line is what says you need it.
33773
33792
  */
33774
- ttlMs: number().int().min(250).max(1e4),
33793
+ holdFrames: number().int().min(1).max(64),
33775
33794
  /**
33776
33795
  * Hard per-decode-worker RAM ceiling for retained native frames, in MB.
33777
33796
  *
33778
- * Intended as a SAFETY ceiling with the TTL as the effective cap — but check
33779
- * which one is actually binding before reasoning from that. At the shipped
33780
- * 1024 MB and a 2 800 ms TTL, a 4K camera hits the CEILING first (~43 frames
33781
- * at ~24 MB each) and the TTL never gets to expire anything; `leaseMb` /
33782
- * `leaseFrames` on the metrics line say which. When the ceiling binds, a
33783
- * change that admits fewer frames buys retention WINDOW at constant RAM
33784
- * rather than giving RAM back — lower this knob if RAM is what you wanted.
33797
+ * Since 2026-08-13 this is a SAFETY ceiling and nothing else: `holdFrames`
33798
+ * is what decides how much is held, and the ceiling is the number above which
33799
+ * something is wrong. Before that it was the effective cap at 1024 MB with
33800
+ * a 2 800 ms TTL a 4K camera sat pinned at `leaseMb:1020, leaseFrames:43`
33801
+ * with the TTL expiring nothing, which is exactly the confusion the hold
33802
+ * removes. `leaseMb` / `leaseFrames` still say what is resident.
33785
33803
  * `0` DISABLES the lease entirely and falls the worker back to the tiny
33786
33804
  * leak-prone GPU surface ring (~85% crop miss; that is what the lease exists
33787
33805
  * to replace).
@@ -33807,22 +33825,45 @@ object({
33807
33825
  * there is the signal that some caller names frames outside the inference set
33808
33826
  * and that this must go back to `all`.
33809
33827
  */
33810
- admission: NativeLeaseAdmissionSchema
33828
+ admission: NativeLeaseAdmissionSchema,
33829
+ /**
33830
+ * RAM ceiling per decode worker, in MB, for the SUBJECT TILES — the
33831
+ * compressed native crops the worker cuts at the moment a frame's detection
33832
+ * result arrives, and keeps long after the frame itself is freed.
33833
+ *
33834
+ * This is the knob that replaced the old retention window, and it buys about
33835
+ * three orders of magnitude more of it: a tile is one subject at native
33836
+ * resolution, JPEG-encoded (~60-120 KB on a 4K person), against ~24.9 MB for
33837
+ * the frame it was cut from. A frame on which nothing was detected costs
33838
+ * nothing at all, which is the real change — the old lease paid per FRAME and
33839
+ * was interrogated per SUBJECT.
33840
+ *
33841
+ * `0` DISABLES tiles, leaving only the hold window and the ≤640 RAM
33842
+ * fallback — i.e. the pre-2026-08-13 miss profile. Set it there only to
33843
+ * reproduce that.
33844
+ */
33845
+ tileBudgetMb: number().int().min(0).max(1024)
33811
33846
  });
33812
33847
  /**
33813
- * The values in force when the operator has set nothing — byte-for-byte the
33814
- * constants the decode worker shipped with as env-var defaults, so making these
33815
- * settings changed no behaviour on the day it landed.
33848
+ * The values in force when the operator has set nothing.
33849
+ *
33850
+ * `budgetMb` stays at 1024 on the day the hold landed, deliberately: it stopped
33851
+ * being the retention window and became the OOM ceiling, and lowering a ceiling
33852
+ * in the same change that redefines it would make a regression and a retune
33853
+ * indistinguishable. Cut it once `tileHits` / `holdOverflow` have been read on
33854
+ * live traffic.
33816
33855
  */
33817
33856
  var DEFAULT_NATIVE_LEASE_SETTINGS = {
33818
- ttlMs: 1200,
33857
+ holdFrames: 8,
33819
33858
  budgetMb: 1024,
33820
33859
  activityMs: 15e3,
33860
+ tileBudgetMb: 64,
33821
33861
  admission: "inferred"
33822
33862
  };
33823
- DEFAULT_NATIVE_LEASE_SETTINGS.ttlMs;
33863
+ DEFAULT_NATIVE_LEASE_SETTINGS.holdFrames;
33824
33864
  DEFAULT_NATIVE_LEASE_SETTINGS.budgetMb;
33825
33865
  DEFAULT_NATIVE_LEASE_SETTINGS.activityMs;
33866
+ DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb;
33826
33867
  DEFAULT_NATIVE_LEASE_SETTINGS.admission;
33827
33868
  //#endregion
33828
33869
  //#region src/config.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-gree",
3
- "version": "0.2.13",
3
+ "version": "0.2.14",
4
4
  "description": "Gree air-conditioner device-provider addon for CamStack — wraps the @apocaliss92/nodegree local-UDP client (LAN discovery + AES control), exposing climate-control and fan-control",
5
5
  "keywords": [
6
6
  "camstack",