@camstack/addon-post-analysis 1.2.177 → 1.2.179
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/{dist-B1cFmGC0.mjs → dist-NBkMwEZ0.mjs} +56 -5
- package/dist/{dist-BfdKgU7-.js → dist-QJ8XSy0F.js} +56 -5
- package/dist/embedding-encoder/index.js +1 -1
- package/dist/embedding-encoder/index.mjs +1 -1
- package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-MvTzBID6.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-BL6jNwq1.mjs} +3 -3
- package/dist/pipeline-analytics/{hostInit-DhLjhqAY.mjs → hostInit-z4IKWrJu.mjs} +3 -3
- package/dist/pipeline-analytics/index.js +144 -16
- package/dist/pipeline-analytics/index.mjs +144 -16
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +1 -1
|
@@ -13236,6 +13236,24 @@ method(_void(), _void(), { kind: "mutation" }), method(_void(), _void(), { kind:
|
|
|
13236
13236
|
kind: "mutation",
|
|
13237
13237
|
auth: "admin"
|
|
13238
13238
|
});
|
|
13239
|
+
/**
|
|
13240
|
+
* Device Manager capability — hub-side singleton that unifies device persistence,
|
|
13241
|
+
* live registry access, and all management operations into a single tRPC surface.
|
|
13242
|
+
*
|
|
13243
|
+
* Replaces:
|
|
13244
|
+
* - `device-persistence` capability (persistence methods absorbed here)
|
|
13245
|
+
* - `device-management.router.ts` (deleted in Phase 2)
|
|
13246
|
+
* - `device-ops.router.ts` (compat layer — deleted; device-provider ops absorbed here)
|
|
13247
|
+
*
|
|
13248
|
+
* All device provider addons (rtsp, onvif, frigate, …) are hub-local: they may
|
|
13249
|
+
* fork into separate processes but never run on remote cluster agents. Therefore:
|
|
13250
|
+
* - No nodeId routing needed — this is a pure hub singleton.
|
|
13251
|
+
* - The hub's DeviceRegistry is the single source of truth for all live devices.
|
|
13252
|
+
* - No shadow registry or cross-node aggregation required.
|
|
13253
|
+
*
|
|
13254
|
+
* Forked workers register devices back to the hub via `ctx.devices`
|
|
13255
|
+
* (DeviceManagerApi → ctx.api.deviceManager.registerDevice), same as today.
|
|
13256
|
+
*/
|
|
13239
13257
|
/** One child-placement directive on a container's `childLayout`. Structurally
|
|
13240
13258
|
* identical to `ChildLayoutEntry` in `device-management.ts` — the cap wire
|
|
13241
13259
|
* shape for the same field. The child is identified by its re-sync-stable
|
|
@@ -19626,6 +19644,9 @@ var RetrainStatusSchema = _enum([
|
|
|
19626
19644
|
*
|
|
19627
19645
|
* `debug` does NOT pin; it is attention, not durability.
|
|
19628
19646
|
*
|
|
19647
|
+
* `debugNote` is the operator's own words about WHAT should be checked on this
|
|
19648
|
+
* track, and it lives and dies with `debug` — see {@link MAX_TRACK_DEBUG_NOTE_LEN}.
|
|
19649
|
+
*
|
|
19629
19650
|
* `favourited` IS a BOOLEAN pin (durability bit), not a retrain lifecycle.
|
|
19630
19651
|
* A favourited track is skipped by retention the same way `staging` is, but
|
|
19631
19652
|
* it does not enter `none|staging|trained` and has no staging budget.
|
|
@@ -19636,6 +19657,21 @@ var TrackFlagFields = {
|
|
|
19636
19657
|
markForTrain: boolean().optional(),
|
|
19637
19658
|
/** Operator marked this track for diagnostic attention. */
|
|
19638
19659
|
debug: boolean().optional(),
|
|
19660
|
+
/**
|
|
19661
|
+
* What the operator wants CHECKED on this track, in their own words.
|
|
19662
|
+
*
|
|
19663
|
+
* The flag alone says "look at this" and nothing about what for; a debug set
|
|
19664
|
+
* reviewed hours later is a list of tracks with no question attached. Bound
|
|
19665
|
+
* to `debug` on the WRITE side — the body clears it when `debug` goes off,
|
|
19666
|
+
* and refuses it on a track whose debug is off — so a note can never outlive
|
|
19667
|
+
* the attention it belongs to.
|
|
19668
|
+
*
|
|
19669
|
+
* `''` is a real value ("marked, nothing to add"); the ABSENT key means
|
|
19670
|
+
* "leave whatever is stored alone", which is what lets a surface turn debug
|
|
19671
|
+
* on without a note (a cancelled prompt) and what lets it edit the note
|
|
19672
|
+
* without touching the flag.
|
|
19673
|
+
*/
|
|
19674
|
+
debugNote: string().max(500).optional(),
|
|
19639
19675
|
/** Operator favourited this track. Pins it against pruning. */
|
|
19640
19676
|
favourited: boolean().optional()
|
|
19641
19677
|
};
|
|
@@ -19662,6 +19698,12 @@ var TrackFlagsSchema = object({
|
|
|
19662
19698
|
trackId: string(),
|
|
19663
19699
|
markForTrain: boolean(),
|
|
19664
19700
|
debug: boolean(),
|
|
19701
|
+
/** The note as it STANDS after the write — never absent here (a track with no
|
|
19702
|
+
* note reports `''`), for the same reason the booleans are required: a
|
|
19703
|
+
* surface that has just written must be able to render the note it now owns
|
|
19704
|
+
* without a re-fetch, and an absent key would read as "unchanged" on a
|
|
19705
|
+
* screen that has no previous value to keep. */
|
|
19706
|
+
debugNote: string(),
|
|
19665
19707
|
favourited: boolean(),
|
|
19666
19708
|
/** The lifecycle state the boolean was derived from. Required here (unlike on
|
|
19667
19709
|
* a track row) because this shape is only ever produced by the write body,
|
|
@@ -20954,11 +20996,20 @@ var pipelineAnalyticsCapability = {
|
|
|
20954
20996
|
* staging is a deliberate action of the retrain page, which is also the only
|
|
20955
20997
|
* thing that produces `trained` in the first place.
|
|
20956
20998
|
*
|
|
20957
|
-
*
|
|
20958
|
-
*
|
|
20959
|
-
*
|
|
20960
|
-
*
|
|
20961
|
-
*
|
|
20999
|
+
* `debugNote` is the operator's sentence about WHAT to check on this track,
|
|
21000
|
+
* and it is bound to `debug`: writing `debug: false` clears it in the same
|
|
21001
|
+
* statement, and a note sent for a track whose debug is off (and is not
|
|
21002
|
+
* being turned on) is DROPPED with a warning rather than stored where
|
|
21003
|
+
* nothing will ever read it. An omitted `debugNote` leaves the stored one
|
|
21004
|
+
* alone — which is what lets a surface turn debug on when the operator
|
|
21005
|
+
* declined to type anything, without that refusal costing them the flag.
|
|
21006
|
+
*
|
|
21007
|
+
* Returns the RESOLVED state of all three flags (absent → `false`) plus the
|
|
21008
|
+
* note (absent → `''`) and the `retrainStatus` they were derived from, so a
|
|
21009
|
+
* caller can drive its toggle — and render a `trained` badge — without a
|
|
21010
|
+
* re-fetch. Rejects an unknown track, a new staging mark on a device already
|
|
21011
|
+
* holding its full budget, and any `markForTrain` write against a trained
|
|
21012
|
+
* track.
|
|
20962
21013
|
*/
|
|
20963
21014
|
setTrackFlags: method(object({
|
|
20964
21015
|
/** Log/audit scope only — the trackId is globally unique on its own. */
|
|
@@ -13267,6 +13267,24 @@ method(_void(), _void(), { kind: "mutation" }), method(_void(), _void(), { kind:
|
|
|
13267
13267
|
kind: "mutation",
|
|
13268
13268
|
auth: "admin"
|
|
13269
13269
|
});
|
|
13270
|
+
/**
|
|
13271
|
+
* Device Manager capability — hub-side singleton that unifies device persistence,
|
|
13272
|
+
* live registry access, and all management operations into a single tRPC surface.
|
|
13273
|
+
*
|
|
13274
|
+
* Replaces:
|
|
13275
|
+
* - `device-persistence` capability (persistence methods absorbed here)
|
|
13276
|
+
* - `device-management.router.ts` (deleted in Phase 2)
|
|
13277
|
+
* - `device-ops.router.ts` (compat layer — deleted; device-provider ops absorbed here)
|
|
13278
|
+
*
|
|
13279
|
+
* All device provider addons (rtsp, onvif, frigate, …) are hub-local: they may
|
|
13280
|
+
* fork into separate processes but never run on remote cluster agents. Therefore:
|
|
13281
|
+
* - No nodeId routing needed — this is a pure hub singleton.
|
|
13282
|
+
* - The hub's DeviceRegistry is the single source of truth for all live devices.
|
|
13283
|
+
* - No shadow registry or cross-node aggregation required.
|
|
13284
|
+
*
|
|
13285
|
+
* Forked workers register devices back to the hub via `ctx.devices`
|
|
13286
|
+
* (DeviceManagerApi → ctx.api.deviceManager.registerDevice), same as today.
|
|
13287
|
+
*/
|
|
13270
13288
|
/** One child-placement directive on a container's `childLayout`. Structurally
|
|
13271
13289
|
* identical to `ChildLayoutEntry` in `device-management.ts` — the cap wire
|
|
13272
13290
|
* shape for the same field. The child is identified by its re-sync-stable
|
|
@@ -19657,6 +19675,9 @@ var RetrainStatusSchema = _enum([
|
|
|
19657
19675
|
*
|
|
19658
19676
|
* `debug` does NOT pin; it is attention, not durability.
|
|
19659
19677
|
*
|
|
19678
|
+
* `debugNote` is the operator's own words about WHAT should be checked on this
|
|
19679
|
+
* track, and it lives and dies with `debug` — see {@link MAX_TRACK_DEBUG_NOTE_LEN}.
|
|
19680
|
+
*
|
|
19660
19681
|
* `favourited` IS a BOOLEAN pin (durability bit), not a retrain lifecycle.
|
|
19661
19682
|
* A favourited track is skipped by retention the same way `staging` is, but
|
|
19662
19683
|
* it does not enter `none|staging|trained` and has no staging budget.
|
|
@@ -19667,6 +19688,21 @@ var TrackFlagFields = {
|
|
|
19667
19688
|
markForTrain: boolean().optional(),
|
|
19668
19689
|
/** Operator marked this track for diagnostic attention. */
|
|
19669
19690
|
debug: boolean().optional(),
|
|
19691
|
+
/**
|
|
19692
|
+
* What the operator wants CHECKED on this track, in their own words.
|
|
19693
|
+
*
|
|
19694
|
+
* The flag alone says "look at this" and nothing about what for; a debug set
|
|
19695
|
+
* reviewed hours later is a list of tracks with no question attached. Bound
|
|
19696
|
+
* to `debug` on the WRITE side — the body clears it when `debug` goes off,
|
|
19697
|
+
* and refuses it on a track whose debug is off — so a note can never outlive
|
|
19698
|
+
* the attention it belongs to.
|
|
19699
|
+
*
|
|
19700
|
+
* `''` is a real value ("marked, nothing to add"); the ABSENT key means
|
|
19701
|
+
* "leave whatever is stored alone", which is what lets a surface turn debug
|
|
19702
|
+
* on without a note (a cancelled prompt) and what lets it edit the note
|
|
19703
|
+
* without touching the flag.
|
|
19704
|
+
*/
|
|
19705
|
+
debugNote: string().max(500).optional(),
|
|
19670
19706
|
/** Operator favourited this track. Pins it against pruning. */
|
|
19671
19707
|
favourited: boolean().optional()
|
|
19672
19708
|
};
|
|
@@ -19693,6 +19729,12 @@ var TrackFlagsSchema = object({
|
|
|
19693
19729
|
trackId: string(),
|
|
19694
19730
|
markForTrain: boolean(),
|
|
19695
19731
|
debug: boolean(),
|
|
19732
|
+
/** The note as it STANDS after the write — never absent here (a track with no
|
|
19733
|
+
* note reports `''`), for the same reason the booleans are required: a
|
|
19734
|
+
* surface that has just written must be able to render the note it now owns
|
|
19735
|
+
* without a re-fetch, and an absent key would read as "unchanged" on a
|
|
19736
|
+
* screen that has no previous value to keep. */
|
|
19737
|
+
debugNote: string(),
|
|
19696
19738
|
favourited: boolean(),
|
|
19697
19739
|
/** The lifecycle state the boolean was derived from. Required here (unlike on
|
|
19698
19740
|
* a track row) because this shape is only ever produced by the write body,
|
|
@@ -20985,11 +21027,20 @@ var pipelineAnalyticsCapability = {
|
|
|
20985
21027
|
* staging is a deliberate action of the retrain page, which is also the only
|
|
20986
21028
|
* thing that produces `trained` in the first place.
|
|
20987
21029
|
*
|
|
20988
|
-
*
|
|
20989
|
-
*
|
|
20990
|
-
*
|
|
20991
|
-
*
|
|
20992
|
-
*
|
|
21030
|
+
* `debugNote` is the operator's sentence about WHAT to check on this track,
|
|
21031
|
+
* and it is bound to `debug`: writing `debug: false` clears it in the same
|
|
21032
|
+
* statement, and a note sent for a track whose debug is off (and is not
|
|
21033
|
+
* being turned on) is DROPPED with a warning rather than stored where
|
|
21034
|
+
* nothing will ever read it. An omitted `debugNote` leaves the stored one
|
|
21035
|
+
* alone — which is what lets a surface turn debug on when the operator
|
|
21036
|
+
* declined to type anything, without that refusal costing them the flag.
|
|
21037
|
+
*
|
|
21038
|
+
* Returns the RESOLVED state of all three flags (absent → `false`) plus the
|
|
21039
|
+
* note (absent → `''`) and the `retrainStatus` they were derived from, so a
|
|
21040
|
+
* caller can drive its toggle — and render a `trained` badge — without a
|
|
21041
|
+
* re-fetch. Rejects an unknown track, a new staging mark on a device already
|
|
21042
|
+
* holding its full budget, and any `markForTrain` write against a trained
|
|
21043
|
+
* track.
|
|
20993
21044
|
*/
|
|
20994
21045
|
setTrackFlags: method(object({
|
|
20995
21046
|
/** Log/audit scope only — the trackId is globally unique on its own. */
|
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
5
|
+
const require_dist = require("../dist-QJ8XSy0F.js");
|
|
6
6
|
let node_fs = require("node:fs");
|
|
7
7
|
node_fs = require_dist.__toESM(node_fs);
|
|
8
8
|
let node_path = require("node:path");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { At as BaseAddon, F as PoolMemoryWatchdog, St as resolvePoolMemoryPolicy, at as embeddingEncoderCapability, gt as parseProcStatus, ut as hfModelUrl } from "../dist-
|
|
1
|
+
import { At as BaseAddon, F as PoolMemoryWatchdog, St as resolvePoolMemoryPolicy, at as embeddingEncoderCapability, gt as parseProcStatus, ut as hfModelUrl } from "../dist-NBkMwEZ0.mjs";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import * as fs from "node:fs";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
@@ -3,7 +3,7 @@ import "./dist-CYZr2fwk.mjs";
|
|
|
3
3
|
var e = {
|
|
4
4
|
"@camstack/sdk": {
|
|
5
5
|
name: "@camstack/sdk",
|
|
6
|
-
version: "1.2.
|
|
6
|
+
version: "1.2.67",
|
|
7
7
|
scope: ["default"],
|
|
8
8
|
loaded: !1,
|
|
9
9
|
from: "addon_pipeline_analytics_widgets",
|
|
@@ -18,7 +18,7 @@ var e = {
|
|
|
18
18
|
},
|
|
19
19
|
"@camstack/types": {
|
|
20
20
|
name: "@camstack/types",
|
|
21
|
-
version: "1.2.
|
|
21
|
+
version: "1.2.147",
|
|
22
22
|
scope: ["default"],
|
|
23
23
|
loaded: !1,
|
|
24
24
|
from: "addon_pipeline_analytics_widgets",
|
|
@@ -33,7 +33,7 @@ var e = {
|
|
|
33
33
|
},
|
|
34
34
|
"@camstack/ui-library": {
|
|
35
35
|
name: "@camstack/ui-library",
|
|
36
|
-
version: "1.2.
|
|
36
|
+
version: "1.2.113",
|
|
37
37
|
scope: ["default"],
|
|
38
38
|
loaded: !1,
|
|
39
39
|
from: "addon_pipeline_analytics_widgets",
|
|
@@ -36,7 +36,7 @@ async function r() {
|
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
"@camstack/types": {
|
|
39
|
-
version: "1.2.
|
|
39
|
+
version: "1.2.147",
|
|
40
40
|
scope: "default",
|
|
41
41
|
shareConfig: {
|
|
42
42
|
singleton: !0,
|
|
@@ -45,7 +45,7 @@ async function r() {
|
|
|
45
45
|
}
|
|
46
46
|
},
|
|
47
47
|
"@camstack/sdk": {
|
|
48
|
-
version: "1.2.
|
|
48
|
+
version: "1.2.67",
|
|
49
49
|
scope: "default",
|
|
50
50
|
shareConfig: {
|
|
51
51
|
singleton: !0,
|
|
@@ -81,7 +81,7 @@ async function r() {
|
|
|
81
81
|
}
|
|
82
82
|
},
|
|
83
83
|
"@camstack/ui-library": {
|
|
84
|
-
version: "1.2.
|
|
84
|
+
version: "1.2.113",
|
|
85
85
|
scope: "default",
|
|
86
86
|
shareConfig: {
|
|
87
87
|
singleton: !0,
|
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
5
|
+
const require_dist = require("../dist-QJ8XSy0F.js");
|
|
6
6
|
let node_fs = require("node:fs");
|
|
7
7
|
node_fs = require_dist.__toESM(node_fs, 1);
|
|
8
8
|
let node_path = require("node:path");
|
|
@@ -35839,16 +35839,43 @@ function positionsIntersectZone(positions, frameWidth, frameHeight, zone) {
|
|
|
35839
35839
|
}, zone.points)) return true;
|
|
35840
35840
|
return false;
|
|
35841
35841
|
}
|
|
35842
|
+
//#endregion
|
|
35843
|
+
//#region src/pipeline-analytics/track-lifecycle.ts
|
|
35844
|
+
/** Minimum confidence increase (vs last emit) that counts as a material
|
|
35845
|
+
* improvement. */
|
|
35846
|
+
var UPDATE_MIN_CONF_DELTA = .1;
|
|
35847
|
+
/** Debounce floor between two `update` emits for the same track (ms). */
|
|
35848
|
+
var UPDATE_MIN_INTERVAL_MS = 4e3;
|
|
35849
|
+
/** Minimum fractional bbox-area growth (vs last emit) counted as a
|
|
35850
|
+
* materially larger representative crop (e.g. 0.15 = 15% bigger). */
|
|
35851
|
+
var UPDATE_MIN_CROP_AREA_GROWTH = .15;
|
|
35852
|
+
/**
|
|
35853
|
+
* The label a `phase:'update'` SIGNAL and PAYLOAD carry, resolved from its
|
|
35854
|
+
* two possible sources in order: this frame's tiered patch (the frame path
|
|
35855
|
+
* wrote a label this very frame), then the track ROW's stored display label
|
|
35856
|
+
* (`subLabel ?? label`, as `trackStore.peekActive` exposes it).
|
|
35857
|
+
*
|
|
35858
|
+
* The fallback is not a nicety. The face recognizer assigns an identity over
|
|
35859
|
+
* the async detail plane and writes it to the row (`applyLabelCandidate`) —
|
|
35860
|
+
* never into a frame patch — so a signal reading only the patch can never
|
|
35861
|
+
* fire the identity trigger for a recognised face. Measured on the live hub
|
|
35862
|
+
* (2026-09-05, device 590): six of six face identities reached Home
|
|
35863
|
+
* Assistant only on the `end` event at track close + sweep (~lastSeen+33 s),
|
|
35864
|
+
* zero during the track's life, while the subject was still on camera.
|
|
35865
|
+
*/
|
|
35866
|
+
function resolveLifecycleUpdateLabel(labelPatch, storedDisplayLabel) {
|
|
35867
|
+
return patchDisplayLabel(labelPatch) ?? storedDisplayLabel;
|
|
35868
|
+
}
|
|
35842
35869
|
var DEFAULT_UPDATE_GATE_CONFIG = {
|
|
35843
|
-
minConfDelta:
|
|
35844
|
-
minIntervalMs:
|
|
35845
|
-
minCropAreaGrowth:
|
|
35870
|
+
minConfDelta: UPDATE_MIN_CONF_DELTA,
|
|
35871
|
+
minIntervalMs: UPDATE_MIN_INTERVAL_MS,
|
|
35872
|
+
minCropAreaGrowth: UPDATE_MIN_CROP_AREA_GROWTH
|
|
35846
35873
|
};
|
|
35847
35874
|
/**
|
|
35848
35875
|
* Decide whether a `phase:'update'` event should fire this frame.
|
|
35849
35876
|
*
|
|
35850
35877
|
* Priority of triggers: newly-resolved identity/plate > confidence
|
|
35851
|
-
* improvement > materially larger crop. All triggers are debounced by
|
|
35878
|
+
* improvement > newly-entered zone > materially larger crop. All triggers are debounced by
|
|
35852
35879
|
* `minIntervalMs` relative to the last emit. Deltas are measured against
|
|
35853
35880
|
* the LAST-EMITTED memory, so a run of sub-threshold new-bests accumulates
|
|
35854
35881
|
* and fires once it crosses `minConfDelta`.
|
|
@@ -35856,22 +35883,32 @@ var DEFAULT_UPDATE_GATE_CONFIG = {
|
|
|
35856
35883
|
function evaluateTrackLifecycleUpdate(signal, memory, config) {
|
|
35857
35884
|
const identityTrigger = signal.label !== void 0 && signal.label !== "" && (memory === void 0 || memory.lastLabel !== signal.label);
|
|
35858
35885
|
const confidenceTrigger = signal.isNewBest && (memory === void 0 || signal.confidence - memory.lastConfidence >= config.minConfDelta);
|
|
35886
|
+
const zoneTrigger = signal.zonesVisitedCount !== void 0 && memory?.lastZonesVisitedCount !== void 0 && signal.zonesVisitedCount > memory.lastZonesVisitedCount;
|
|
35859
35887
|
const cropTrigger = signal.bboxArea !== void 0 && memory?.lastBboxArea !== void 0 && memory.lastBboxArea > 0 && signal.bboxArea >= memory.lastBboxArea * (1 + config.minCropAreaGrowth);
|
|
35860
|
-
const reason = identityTrigger ? "identity" : confidenceTrigger ? "confidence" : cropTrigger ? "crop" : void 0;
|
|
35861
|
-
const keptMemory = memory
|
|
35888
|
+
const reason = identityTrigger ? "identity" : confidenceTrigger ? "confidence" : zoneTrigger ? "zone" : cropTrigger ? "crop" : void 0;
|
|
35889
|
+
const keptMemory = memory === void 0 ? {
|
|
35862
35890
|
lastConfidence: signal.confidence,
|
|
35863
|
-
lastEmitAt: signal.now
|
|
35864
|
-
|
|
35891
|
+
lastEmitAt: signal.now,
|
|
35892
|
+
...signal.zonesVisitedCount !== void 0 ? { lastZonesVisitedCount: signal.zonesVisitedCount } : {}
|
|
35893
|
+
} : memory.lastZonesVisitedCount === void 0 && signal.zonesVisitedCount !== void 0 ? {
|
|
35894
|
+
...memory,
|
|
35895
|
+
lastZonesVisitedCount: signal.zonesVisitedCount
|
|
35896
|
+
} : memory;
|
|
35865
35897
|
if (reason === void 0) return {
|
|
35866
35898
|
emit: false,
|
|
35867
35899
|
memory: keptMemory
|
|
35868
35900
|
};
|
|
35869
35901
|
if (memory !== void 0 && signal.now - memory.lastEmitAt < config.minIntervalMs) return {
|
|
35870
35902
|
emit: false,
|
|
35871
|
-
|
|
35903
|
+
suppressed: reason,
|
|
35904
|
+
memory: {
|
|
35905
|
+
...keptMemory,
|
|
35906
|
+
suppressedSinceEmit: (keptMemory.suppressedSinceEmit ?? 0) + 1
|
|
35907
|
+
}
|
|
35872
35908
|
};
|
|
35873
35909
|
const nextLabel = signal.label ?? memory?.lastLabel;
|
|
35874
35910
|
const nextBboxArea = signal.bboxArea ?? memory?.lastBboxArea;
|
|
35911
|
+
const nextZonesCount = signal.zonesVisitedCount ?? memory?.lastZonesVisitedCount;
|
|
35875
35912
|
return {
|
|
35876
35913
|
emit: true,
|
|
35877
35914
|
reason,
|
|
@@ -35879,7 +35916,8 @@ function evaluateTrackLifecycleUpdate(signal, memory, config) {
|
|
|
35879
35916
|
lastConfidence: memory === void 0 ? signal.confidence : Math.max(memory.lastConfidence, signal.confidence),
|
|
35880
35917
|
lastEmitAt: signal.now,
|
|
35881
35918
|
...nextLabel !== void 0 ? { lastLabel: nextLabel } : {},
|
|
35882
|
-
...nextBboxArea !== void 0 ? { lastBboxArea: nextBboxArea } : {}
|
|
35919
|
+
...nextBboxArea !== void 0 ? { lastBboxArea: nextBboxArea } : {},
|
|
35920
|
+
...nextZonesCount !== void 0 ? { lastZonesVisitedCount: nextZonesCount } : {}
|
|
35883
35921
|
}
|
|
35884
35922
|
};
|
|
35885
35923
|
}
|
|
@@ -39490,6 +39528,10 @@ var TRACKS_COLUMNS = [
|
|
|
39490
39528
|
name: "debug",
|
|
39491
39529
|
type: "BOOLEAN"
|
|
39492
39530
|
},
|
|
39531
|
+
{
|
|
39532
|
+
name: "debugNote",
|
|
39533
|
+
type: "TEXT"
|
|
39534
|
+
},
|
|
39493
39535
|
{
|
|
39494
39536
|
name: "favourited",
|
|
39495
39537
|
type: "BOOLEAN"
|
|
@@ -39685,6 +39727,7 @@ function cloneTrack(t) {
|
|
|
39685
39727
|
markForTrain: t.retrainStatus === "staging"
|
|
39686
39728
|
} : {},
|
|
39687
39729
|
...t.debug !== void 0 ? { debug: t.debug } : {},
|
|
39730
|
+
...t.debugNote !== void 0 ? { debugNote: t.debugNote } : {},
|
|
39688
39731
|
...t.favourited !== void 0 ? { favourited: t.favourited } : {},
|
|
39689
39732
|
...t.hasFace !== void 0 ? { hasFace: t.hasFace } : {},
|
|
39690
39733
|
...t.hasEmbeddedFace !== void 0 ? { hasEmbeddedFace: t.hasEmbeddedFace } : {},
|
|
@@ -39921,7 +39964,8 @@ var TrackStore = class {
|
|
|
39921
39964
|
* Cheap read of an active track's promotion-relevant fields WITHOUT the deep
|
|
39922
39965
|
* clone `getActiveByTrack` does — the returned `positions` is the live
|
|
39923
39966
|
* internal array (read-only; callers must not mutate). Feeds the per-frame
|
|
39924
|
-
* stationary-promotion check
|
|
39967
|
+
* stationary-promotion check AND the lifecycle update gate, both called at
|
|
39968
|
+
* inference fps. Null if unknown/expired.
|
|
39925
39969
|
*/
|
|
39926
39970
|
peekActive(trackId) {
|
|
39927
39971
|
const t = this.active.get(trackId);
|
|
@@ -39929,6 +39973,7 @@ var TrackStore = class {
|
|
|
39929
39973
|
return {
|
|
39930
39974
|
firstSeen: t.firstSeen,
|
|
39931
39975
|
positions: t.positions,
|
|
39976
|
+
zonesVisitedCount: t.zonesVisited.length,
|
|
39932
39977
|
...displayLabel(t) !== void 0 ? { label: displayLabel(t) } : {}
|
|
39933
39978
|
};
|
|
39934
39979
|
}
|
|
@@ -40073,12 +40118,14 @@ var TrackStore = class {
|
|
|
40073
40118
|
const nextStatus = patch.markForTrain === void 0 ? void 0 : patch.markForTrain ? "staging" : "none";
|
|
40074
40119
|
if (nextStatus !== void 0) data["retrainStatus"] = nextStatus;
|
|
40075
40120
|
if (patch.debug !== void 0) data["debug"] = patch.debug;
|
|
40121
|
+
if (patch.debugNote !== void 0) data["debugNote"] = patch.debugNote;
|
|
40076
40122
|
if (patch.favourited !== void 0) data["favourited"] = patch.favourited;
|
|
40077
40123
|
if (Object.keys(data).length === 0) return;
|
|
40078
40124
|
const active = this.active.get(trackId);
|
|
40079
40125
|
if (active) {
|
|
40080
40126
|
if (nextStatus !== void 0) active.retrainStatus = nextStatus;
|
|
40081
40127
|
if (patch.debug !== void 0) active.debug = patch.debug;
|
|
40128
|
+
if (patch.debugNote !== void 0) active.debugNote = patch.debugNote;
|
|
40082
40129
|
if (patch.favourited !== void 0) active.favourited = patch.favourited;
|
|
40083
40130
|
}
|
|
40084
40131
|
try {
|
|
@@ -40281,6 +40328,7 @@ var TrackStore = class {
|
|
|
40281
40328
|
if (active) return {
|
|
40282
40329
|
retrainStatus: active.retrainStatus ?? "none",
|
|
40283
40330
|
debug: active.debug === true,
|
|
40331
|
+
debugNote: active.debugNote ?? "",
|
|
40284
40332
|
favourited: active.favourited === true
|
|
40285
40333
|
};
|
|
40286
40334
|
const persisted = await this.getPersistedByTrackId(trackId);
|
|
@@ -40288,6 +40336,7 @@ var TrackStore = class {
|
|
|
40288
40336
|
return {
|
|
40289
40337
|
retrainStatus: persisted.retrainStatus ?? "none",
|
|
40290
40338
|
debug: persisted.debug === true,
|
|
40339
|
+
debugNote: persisted.debugNote ?? "",
|
|
40291
40340
|
favourited: persisted.favourited === true
|
|
40292
40341
|
};
|
|
40293
40342
|
}
|
|
@@ -41187,6 +41236,7 @@ var TrackStore = class {
|
|
|
41187
41236
|
...t.audioLabels !== void 0 ? { audioLabels: [...t.audioLabels] } : {},
|
|
41188
41237
|
...t.retrainStatus !== void 0 ? { retrainStatus: t.retrainStatus } : {},
|
|
41189
41238
|
...t.debug !== void 0 ? { debug: t.debug } : {},
|
|
41239
|
+
...t.debugNote !== void 0 ? { debugNote: t.debugNote } : {},
|
|
41190
41240
|
...t.favourited !== void 0 ? { favourited: t.favourited } : {},
|
|
41191
41241
|
...t.hasFace !== void 0 ? { hasFace: t.hasFace } : {},
|
|
41192
41242
|
...t.hasEmbeddedFace !== void 0 ? { hasEmbeddedFace: t.hasEmbeddedFace } : {},
|
|
@@ -41245,6 +41295,7 @@ var TrackStore = class {
|
|
|
41245
41295
|
const audioLabels = readAudioLabels(data["audioLabels"]);
|
|
41246
41296
|
const retrainParsed = require_dist.RetrainStatusSchema.safeParse(data["retrainStatus"]);
|
|
41247
41297
|
const debug = data["debug"];
|
|
41298
|
+
const debugNote = data["debugNote"];
|
|
41248
41299
|
const favourited = data["favourited"];
|
|
41249
41300
|
const hasFace = data["hasFace"];
|
|
41250
41301
|
/** Same read as `hasFace` — NULL / missing stays ABSENT, never `false`.
|
|
@@ -41293,6 +41344,7 @@ var TrackStore = class {
|
|
|
41293
41344
|
markForTrain: retrainParsed.data === "staging"
|
|
41294
41345
|
} : {},
|
|
41295
41346
|
...typeof debug === "boolean" ? { debug } : {},
|
|
41347
|
+
...typeof debugNote === "string" ? { debugNote } : {},
|
|
41296
41348
|
...typeof favourited === "boolean" ? { favourited } : {},
|
|
41297
41349
|
...typeof hasFace === "boolean" ? { hasFace } : {},
|
|
41298
41350
|
...typeof hasEmbeddedFace === "boolean" ? { hasEmbeddedFace } : {},
|
|
@@ -54864,6 +54916,47 @@ var TrackAlreadyTrainedError = class extends Error {
|
|
|
54864
54916
|
}
|
|
54865
54917
|
};
|
|
54866
54918
|
/**
|
|
54919
|
+
* The `debugNote` half of the patch — `{}` when nothing should be written.
|
|
54920
|
+
*
|
|
54921
|
+
* The note is not an independent column: it is the operator's sentence about
|
|
54922
|
+
* why `debug` is on, so it exists exactly as long as the flag does. Three
|
|
54923
|
+
* cases, and the order matters:
|
|
54924
|
+
*
|
|
54925
|
+
* 1. **`debug: false` in the patch → the note is CLEARED**, whatever the
|
|
54926
|
+
* caller sent with it. A note surviving the flag is a leftover that reads
|
|
54927
|
+
* as a live request, and the invariant belongs here rather than in the
|
|
54928
|
+
* three surfaces that write this patch — one of which is a browser grid
|
|
54929
|
+
* that has no note UI at all and would never think to clear it.
|
|
54930
|
+
* 2. **No note in the patch → nothing is written.** This is what makes a
|
|
54931
|
+
* cancelled prompt free: the app turns debug on, the operator declines to
|
|
54932
|
+
* type, and the flag still lands. Refusing to write a note must never cost
|
|
54933
|
+
* the capture that was asked for.
|
|
54934
|
+
* 3. **A note, on a track whose debug is off and is not being turned on →
|
|
54935
|
+
* DROPPED.** Storing it would put the operator's words somewhere no reader
|
|
54936
|
+
* of a debug set will ever look. Dropped work is logged, per-camera: a
|
|
54937
|
+
* branch that silently discards a sentence is indistinguishable from one
|
|
54938
|
+
* that stored it.
|
|
54939
|
+
*
|
|
54940
|
+
* `''` is a WRITE, not an absence — clearing a note the operator no longer
|
|
54941
|
+
* stands behind is a real edit.
|
|
54942
|
+
*/
|
|
54943
|
+
function resolveNotePatch(deps, input, current) {
|
|
54944
|
+
if (input.flags.debug === false) return { debugNote: "" };
|
|
54945
|
+
if (input.flags.debugNote === void 0) return {};
|
|
54946
|
+
if (!(input.flags.debug === true || current.debug)) {
|
|
54947
|
+
deps.logger.warn("setTrackFlags dropped a debug note — the track is not flagged for debug", {
|
|
54948
|
+
tags: { deviceId: input.deviceId },
|
|
54949
|
+
meta: {
|
|
54950
|
+
deviceId: input.deviceId,
|
|
54951
|
+
trackId: input.trackId,
|
|
54952
|
+
noteLength: input.flags.debugNote.length
|
|
54953
|
+
}
|
|
54954
|
+
});
|
|
54955
|
+
return {};
|
|
54956
|
+
}
|
|
54957
|
+
return { debugNote: input.flags.debugNote };
|
|
54958
|
+
}
|
|
54959
|
+
/**
|
|
54867
54960
|
* Apply a partial flag patch and report the RESOLVED state of both flags.
|
|
54868
54961
|
*
|
|
54869
54962
|
* Existence is checked BEFORE the write: a patch against a track that no longer
|
|
@@ -54924,7 +55017,8 @@ async function applyTrackFlags(deps, input) {
|
|
|
54924
55017
|
const patch = {
|
|
54925
55018
|
...input.flags.markForTrain !== void 0 ? { markForTrain: input.flags.markForTrain } : {},
|
|
54926
55019
|
...input.flags.debug !== void 0 ? { debug: input.flags.debug } : {},
|
|
54927
|
-
...input.flags.favourited !== void 0 ? { favourited: input.flags.favourited } : {}
|
|
55020
|
+
...input.flags.favourited !== void 0 ? { favourited: input.flags.favourited } : {},
|
|
55021
|
+
...resolveNotePatch(deps, input, current)
|
|
54928
55022
|
};
|
|
54929
55023
|
if (Object.keys(patch).length > 0) await store.setFlags(input.trackId, patch);
|
|
54930
55024
|
const retrainStatus = patch.markForTrain === void 0 ? current.retrainStatus : patch.markForTrain ? "staging" : "none";
|
|
@@ -54932,6 +55026,7 @@ async function applyTrackFlags(deps, input) {
|
|
|
54932
55026
|
trackId: input.trackId,
|
|
54933
55027
|
markForTrain: retrainStatus === "staging",
|
|
54934
55028
|
debug: patch.debug ?? current.debug,
|
|
55029
|
+
debugNote: patch.debugNote ?? current.debugNote,
|
|
54935
55030
|
favourited: patch.favourited ?? current.favourited,
|
|
54936
55031
|
retrainStatus
|
|
54937
55032
|
};
|
|
@@ -58661,6 +58756,13 @@ var ANALYTICS_COLLECTIONS = [
|
|
|
58661
58756
|
kind: "never-orphaned",
|
|
58662
58757
|
why: "declares `sourceTrackId`, which is a REFERENCE and not ownership — a parked object outliving the track that first saw it is the entire purpose of the registry. It has its own TTL sweep keyed on OBSERVED frame time, not wall clock. Classified by hand precisely because the derivation must not see it."
|
|
58663
58758
|
}
|
|
58759
|
+
},
|
|
58760
|
+
{
|
|
58761
|
+
collection: STATIONARY_EVIDENCE_COLLECTION,
|
|
58762
|
+
classification: {
|
|
58763
|
+
kind: "never-orphaned",
|
|
58764
|
+
why: "the candidate half of the registry above, and it inherits that entry's argument for the same reason: `sourceTrackId` is the PROVENANCE of whichever track happened to be looking, never ownership. It cannot be `track-owned` on the behaviour, not merely on the name — a candidate is fed by a SUCCESSION of tracks (`StationaryEvidenceLedger.observe` re-binds under D280, and `retainTracks` drops a binding the moment the tracker forgets the track) while the row itself survives, because agreement accumulating ACROSS tracks is the whole measurement. Cascading it on the first contributor's eviction would delete evidence still being gathered by tracks alive right now. Its bounds are its own and stay inside D61's one-clock rule: a candidate untouched for EVIDENCE_WINDOW_MS (6h) is dropped by `expire`, on the next OBSERVATION of that device and against the frame timestamp — the same observed-time clock the registry uses, never wall clock and never a sweep; a device is capped at EVIDENCE_MAX_CANDIDATES_PER_DEVICE (512, least-recently-touched evicted); a promotion deletes the candidate the instant the registry entry is born, so the two tables cannot both hold the object; and `clearDevice` takes the rest when a camera is removed. Deliberately NOT `owner-indirection`: that kind enrols a collection into `auditableCollections()`, and the audit has a resolver only for `pipeline-analytics:media`."
|
|
58765
|
+
}
|
|
58664
58766
|
}
|
|
58665
58767
|
];
|
|
58666
58768
|
/** The collections the orphan audit actually scans — everything with an owner. */
|
|
@@ -71158,15 +71260,41 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_dist.B
|
|
|
71158
71260
|
*/
|
|
71159
71261
|
maybeEmitTrackLifecycleUpdate(deviceId, t, timestamp, isNewBest) {
|
|
71160
71262
|
const memory = this.residents.lifecycleUpdateMem(t.trackId);
|
|
71263
|
+
/**
|
|
71264
|
+
* The signal's label reads the frame patch AND the track row: the face
|
|
71265
|
+
* recognizer writes a recognised identity to the ROW over the async
|
|
71266
|
+
* detail plane, never into a frame patch, and a patch-only read left the
|
|
71267
|
+
* identity trigger unable to fire for a face — every face name reached
|
|
71268
|
+
* the export surfaces only on the `end` event, ~30 s after the subject
|
|
71269
|
+
* left the frame (measured live 2026-09-05).
|
|
71270
|
+
*/
|
|
71271
|
+
const peeked = this.trackStore?.peekActive(t.trackId);
|
|
71272
|
+
const label = resolveLifecycleUpdateLabel(t.labelPatch, peeked?.label);
|
|
71161
71273
|
const decision = evaluateTrackLifecycleUpdate({
|
|
71162
71274
|
isNewBest,
|
|
71163
71275
|
confidence: t.confidence,
|
|
71164
71276
|
now: timestamp,
|
|
71165
|
-
...
|
|
71277
|
+
...label !== void 0 ? { label } : {},
|
|
71278
|
+
...peeked !== null && peeked !== void 0 ? { zonesVisitedCount: peeked.zonesVisitedCount } : {},
|
|
71166
71279
|
bboxArea: t.bbox.w * t.bbox.h
|
|
71167
71280
|
}, memory, DEFAULT_UPDATE_GATE_CONFIG);
|
|
71168
71281
|
this.residents.setLifecycleUpdateMem(deviceId, t.trackId, decision.memory);
|
|
71169
|
-
if (!decision.emit)
|
|
71282
|
+
if (!decision.emit) {
|
|
71283
|
+
/**
|
|
71284
|
+
* Dropped for cadence (debounce) — counted, never silent. The count
|
|
71285
|
+
* since the last emit rides the memory and this line; a throttle
|
|
71286
|
+
* with no ledger is how a 30 s delivery delay stayed invisible.
|
|
71287
|
+
*/
|
|
71288
|
+
if (decision.suppressed !== void 0) this.ctx.logger.debug("lifecycle update suppressed (debounce)", {
|
|
71289
|
+
tags: { deviceId },
|
|
71290
|
+
meta: {
|
|
71291
|
+
trackId: t.trackId,
|
|
71292
|
+
reason: decision.suppressed,
|
|
71293
|
+
suppressedSinceEmit: decision.memory.suppressedSinceEmit ?? 0
|
|
71294
|
+
}
|
|
71295
|
+
});
|
|
71296
|
+
return;
|
|
71297
|
+
}
|
|
71170
71298
|
const track = this.trackStore?.getActiveByTrack(t.trackId);
|
|
71171
71299
|
const keyFrameMediaKey = this.residents.keyFrameKey(t.trackId);
|
|
71172
71300
|
const payload = buildTrackLifecyclePayload({
|
|
@@ -71178,7 +71306,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_dist.B
|
|
|
71178
71306
|
bestConfidence: t.confidence,
|
|
71179
71307
|
firstSeen: track?.firstSeen ?? timestamp,
|
|
71180
71308
|
lastSeen: track?.lastSeen ?? timestamp,
|
|
71181
|
-
...
|
|
71309
|
+
...label !== void 0 ? { label } : {},
|
|
71182
71310
|
...t.plateText !== void 0 ? { plateText: t.plateText } : {},
|
|
71183
71311
|
...track?.zonesVisited !== void 0 ? { zonesVisited: track.zonesVisited } : {},
|
|
71184
71312
|
...track?.totalDistance !== void 0 ? { totalDistance: track.totalDistance } : {},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as audioModeOf, A as NcSnoozeSchema, At as BaseAddon, B as SCENE_DEFAULT_UNCOVERED_POLICY, Bt as boolean, C as NcConditionDescriptorSchema, Ct as sceneMonitorCapability, D as NcRuleTargetSchema, Dt as videoclipsCapability, E as NcRuleSchema, Et as vectorDimFromBase64, Ft as isDeviceScopedCap, G as TimelapseRulePatchSchema, Gt as partialRecord, H as SceneMonitorSchema, Ht as literal, I as RECORDING_EXPORT_MAX_READ_BYTES, It as nodePin, J as VISIT_MERGE_GAP_MS, Jt as unknown, K as TimelapseRuleSchema, Kt as record, L as RetrainStatusSchema, Lt as sleep$1, M as NcSystemEventKindSchema, Mt as DeviceType, N as NcTaxonomySchema, Nt as createEvent, O as NcScheduleSchema, Ot as zoneAnalyticsCapability, P as OpsLogEntrySchema, Pt as hydrateSchema, Q as audioMetricsCapability, Rt as _enum, S as NC_TAXONOMY, T as NcRulePatchSchema, Tt as systemEventFilterApplies, U as TIMELAPSE_DENSE_FLOOR_SEC, Ut as number, V as SCENE_DIVERGED, Vt as discriminatedUnion, W as TimelapseRuleInputSchema, Wt as object, X as alarmPanelCapability, Y as addonWidgetsSourceCapability, Yt as EventCategory, Z as assertTimelapseCadences, _ as MediaFileKindEnum, _t as pickClusterStepModels, a as DEFAULT_EVENT_COLOR, b as NC_DEFAULT_SNOOZE_MINUTES, bt as readDeviceStateFrom, c as DETECTION_MACRO_CLASSES, ct as faceGalleryCapability, d as EVENT_KIND_BY_CAP, dt as isDetectionMacroClass, et as buildEventKindDescriptor, f as EVENT_PAD_MS, ft as isScheduleActive, g as MACRO_LABELS, h as LabelAttributionSchema, ht as notificationRulesCapability, i as COCO_TO_MACRO, it as deriveRecordingMode, j as NcSnoozeSuppressedSchema, jt as CamProfileSchema, k as NcSnoozeInputSchema, kt as errMsg, lt as failureContributionCapability, m as FailureCounters, mt as kebabToCamel, n as BaseDevice, nt as customAction, ot as encodeVectorBase64, p as FULL_IMAGE_BBOX, pt as isSourceCap, q as TrackSourceSchema, qt as string, r as CLUSTER_MODEL_SCOPED_STEPS, rt as defineCustomActions, st as evaluateSensorEdge, t as AUDIO_MACRO_LABELS, tt as cosineSimilarity$1, u as DeclaredDevices, v as NC_ALARM_SYSTEM_EVENT_KINDS, vt as pipelineAnalyticsCapability, w as NcRuleInputSchema, wt as subKindsOf, xt as readTimelapseGeneratedAt, y as NC_CONDITION_CATALOG, yt as plateGalleryCapability, z as SCENE_DEFAULT_ANCHOR_THRESHOLD, zt as array } from "../dist-
|
|
1
|
+
import { $ as audioModeOf, A as NcSnoozeSchema, At as BaseAddon, B as SCENE_DEFAULT_UNCOVERED_POLICY, Bt as boolean, C as NcConditionDescriptorSchema, Ct as sceneMonitorCapability, D as NcRuleTargetSchema, Dt as videoclipsCapability, E as NcRuleSchema, Et as vectorDimFromBase64, Ft as isDeviceScopedCap, G as TimelapseRulePatchSchema, Gt as partialRecord, H as SceneMonitorSchema, Ht as literal, I as RECORDING_EXPORT_MAX_READ_BYTES, It as nodePin, J as VISIT_MERGE_GAP_MS, Jt as unknown, K as TimelapseRuleSchema, Kt as record, L as RetrainStatusSchema, Lt as sleep$1, M as NcSystemEventKindSchema, Mt as DeviceType, N as NcTaxonomySchema, Nt as createEvent, O as NcScheduleSchema, Ot as zoneAnalyticsCapability, P as OpsLogEntrySchema, Pt as hydrateSchema, Q as audioMetricsCapability, Rt as _enum, S as NC_TAXONOMY, T as NcRulePatchSchema, Tt as systemEventFilterApplies, U as TIMELAPSE_DENSE_FLOOR_SEC, Ut as number, V as SCENE_DIVERGED, Vt as discriminatedUnion, W as TimelapseRuleInputSchema, Wt as object, X as alarmPanelCapability, Y as addonWidgetsSourceCapability, Yt as EventCategory, Z as assertTimelapseCadences, _ as MediaFileKindEnum, _t as pickClusterStepModels, a as DEFAULT_EVENT_COLOR, b as NC_DEFAULT_SNOOZE_MINUTES, bt as readDeviceStateFrom, c as DETECTION_MACRO_CLASSES, ct as faceGalleryCapability, d as EVENT_KIND_BY_CAP, dt as isDetectionMacroClass, et as buildEventKindDescriptor, f as EVENT_PAD_MS, ft as isScheduleActive, g as MACRO_LABELS, h as LabelAttributionSchema, ht as notificationRulesCapability, i as COCO_TO_MACRO, it as deriveRecordingMode, j as NcSnoozeSuppressedSchema, jt as CamProfileSchema, k as NcSnoozeInputSchema, kt as errMsg, lt as failureContributionCapability, m as FailureCounters, mt as kebabToCamel, n as BaseDevice, nt as customAction, ot as encodeVectorBase64, p as FULL_IMAGE_BBOX, pt as isSourceCap, q as TrackSourceSchema, qt as string, r as CLUSTER_MODEL_SCOPED_STEPS, rt as defineCustomActions, st as evaluateSensorEdge, t as AUDIO_MACRO_LABELS, tt as cosineSimilarity$1, u as DeclaredDevices, v as NC_ALARM_SYSTEM_EVENT_KINDS, vt as pipelineAnalyticsCapability, w as NcRuleInputSchema, wt as subKindsOf, xt as readTimelapseGeneratedAt, y as NC_CONDITION_CATALOG, yt as plateGalleryCapability, z as SCENE_DEFAULT_ANCHOR_THRESHOLD, zt as array } from "../dist-NBkMwEZ0.mjs";
|
|
2
2
|
import { t as __exportAll } from "../embedding-encoder/index.mjs";
|
|
3
3
|
import * as fs from "node:fs";
|
|
4
4
|
import { promises } from "node:fs";
|
|
@@ -35814,16 +35814,43 @@ function positionsIntersectZone(positions, frameWidth, frameHeight, zone) {
|
|
|
35814
35814
|
}, zone.points)) return true;
|
|
35815
35815
|
return false;
|
|
35816
35816
|
}
|
|
35817
|
+
//#endregion
|
|
35818
|
+
//#region src/pipeline-analytics/track-lifecycle.ts
|
|
35819
|
+
/** Minimum confidence increase (vs last emit) that counts as a material
|
|
35820
|
+
* improvement. */
|
|
35821
|
+
var UPDATE_MIN_CONF_DELTA = .1;
|
|
35822
|
+
/** Debounce floor between two `update` emits for the same track (ms). */
|
|
35823
|
+
var UPDATE_MIN_INTERVAL_MS = 4e3;
|
|
35824
|
+
/** Minimum fractional bbox-area growth (vs last emit) counted as a
|
|
35825
|
+
* materially larger representative crop (e.g. 0.15 = 15% bigger). */
|
|
35826
|
+
var UPDATE_MIN_CROP_AREA_GROWTH = .15;
|
|
35827
|
+
/**
|
|
35828
|
+
* The label a `phase:'update'` SIGNAL and PAYLOAD carry, resolved from its
|
|
35829
|
+
* two possible sources in order: this frame's tiered patch (the frame path
|
|
35830
|
+
* wrote a label this very frame), then the track ROW's stored display label
|
|
35831
|
+
* (`subLabel ?? label`, as `trackStore.peekActive` exposes it).
|
|
35832
|
+
*
|
|
35833
|
+
* The fallback is not a nicety. The face recognizer assigns an identity over
|
|
35834
|
+
* the async detail plane and writes it to the row (`applyLabelCandidate`) —
|
|
35835
|
+
* never into a frame patch — so a signal reading only the patch can never
|
|
35836
|
+
* fire the identity trigger for a recognised face. Measured on the live hub
|
|
35837
|
+
* (2026-09-05, device 590): six of six face identities reached Home
|
|
35838
|
+
* Assistant only on the `end` event at track close + sweep (~lastSeen+33 s),
|
|
35839
|
+
* zero during the track's life, while the subject was still on camera.
|
|
35840
|
+
*/
|
|
35841
|
+
function resolveLifecycleUpdateLabel(labelPatch, storedDisplayLabel) {
|
|
35842
|
+
return patchDisplayLabel(labelPatch) ?? storedDisplayLabel;
|
|
35843
|
+
}
|
|
35817
35844
|
var DEFAULT_UPDATE_GATE_CONFIG = {
|
|
35818
|
-
minConfDelta:
|
|
35819
|
-
minIntervalMs:
|
|
35820
|
-
minCropAreaGrowth:
|
|
35845
|
+
minConfDelta: UPDATE_MIN_CONF_DELTA,
|
|
35846
|
+
minIntervalMs: UPDATE_MIN_INTERVAL_MS,
|
|
35847
|
+
minCropAreaGrowth: UPDATE_MIN_CROP_AREA_GROWTH
|
|
35821
35848
|
};
|
|
35822
35849
|
/**
|
|
35823
35850
|
* Decide whether a `phase:'update'` event should fire this frame.
|
|
35824
35851
|
*
|
|
35825
35852
|
* Priority of triggers: newly-resolved identity/plate > confidence
|
|
35826
|
-
* improvement > materially larger crop. All triggers are debounced by
|
|
35853
|
+
* improvement > newly-entered zone > materially larger crop. All triggers are debounced by
|
|
35827
35854
|
* `minIntervalMs` relative to the last emit. Deltas are measured against
|
|
35828
35855
|
* the LAST-EMITTED memory, so a run of sub-threshold new-bests accumulates
|
|
35829
35856
|
* and fires once it crosses `minConfDelta`.
|
|
@@ -35831,22 +35858,32 @@ var DEFAULT_UPDATE_GATE_CONFIG = {
|
|
|
35831
35858
|
function evaluateTrackLifecycleUpdate(signal, memory, config) {
|
|
35832
35859
|
const identityTrigger = signal.label !== void 0 && signal.label !== "" && (memory === void 0 || memory.lastLabel !== signal.label);
|
|
35833
35860
|
const confidenceTrigger = signal.isNewBest && (memory === void 0 || signal.confidence - memory.lastConfidence >= config.minConfDelta);
|
|
35861
|
+
const zoneTrigger = signal.zonesVisitedCount !== void 0 && memory?.lastZonesVisitedCount !== void 0 && signal.zonesVisitedCount > memory.lastZonesVisitedCount;
|
|
35834
35862
|
const cropTrigger = signal.bboxArea !== void 0 && memory?.lastBboxArea !== void 0 && memory.lastBboxArea > 0 && signal.bboxArea >= memory.lastBboxArea * (1 + config.minCropAreaGrowth);
|
|
35835
|
-
const reason = identityTrigger ? "identity" : confidenceTrigger ? "confidence" : cropTrigger ? "crop" : void 0;
|
|
35836
|
-
const keptMemory = memory
|
|
35863
|
+
const reason = identityTrigger ? "identity" : confidenceTrigger ? "confidence" : zoneTrigger ? "zone" : cropTrigger ? "crop" : void 0;
|
|
35864
|
+
const keptMemory = memory === void 0 ? {
|
|
35837
35865
|
lastConfidence: signal.confidence,
|
|
35838
|
-
lastEmitAt: signal.now
|
|
35839
|
-
|
|
35866
|
+
lastEmitAt: signal.now,
|
|
35867
|
+
...signal.zonesVisitedCount !== void 0 ? { lastZonesVisitedCount: signal.zonesVisitedCount } : {}
|
|
35868
|
+
} : memory.lastZonesVisitedCount === void 0 && signal.zonesVisitedCount !== void 0 ? {
|
|
35869
|
+
...memory,
|
|
35870
|
+
lastZonesVisitedCount: signal.zonesVisitedCount
|
|
35871
|
+
} : memory;
|
|
35840
35872
|
if (reason === void 0) return {
|
|
35841
35873
|
emit: false,
|
|
35842
35874
|
memory: keptMemory
|
|
35843
35875
|
};
|
|
35844
35876
|
if (memory !== void 0 && signal.now - memory.lastEmitAt < config.minIntervalMs) return {
|
|
35845
35877
|
emit: false,
|
|
35846
|
-
|
|
35878
|
+
suppressed: reason,
|
|
35879
|
+
memory: {
|
|
35880
|
+
...keptMemory,
|
|
35881
|
+
suppressedSinceEmit: (keptMemory.suppressedSinceEmit ?? 0) + 1
|
|
35882
|
+
}
|
|
35847
35883
|
};
|
|
35848
35884
|
const nextLabel = signal.label ?? memory?.lastLabel;
|
|
35849
35885
|
const nextBboxArea = signal.bboxArea ?? memory?.lastBboxArea;
|
|
35886
|
+
const nextZonesCount = signal.zonesVisitedCount ?? memory?.lastZonesVisitedCount;
|
|
35850
35887
|
return {
|
|
35851
35888
|
emit: true,
|
|
35852
35889
|
reason,
|
|
@@ -35854,7 +35891,8 @@ function evaluateTrackLifecycleUpdate(signal, memory, config) {
|
|
|
35854
35891
|
lastConfidence: memory === void 0 ? signal.confidence : Math.max(memory.lastConfidence, signal.confidence),
|
|
35855
35892
|
lastEmitAt: signal.now,
|
|
35856
35893
|
...nextLabel !== void 0 ? { lastLabel: nextLabel } : {},
|
|
35857
|
-
...nextBboxArea !== void 0 ? { lastBboxArea: nextBboxArea } : {}
|
|
35894
|
+
...nextBboxArea !== void 0 ? { lastBboxArea: nextBboxArea } : {},
|
|
35895
|
+
...nextZonesCount !== void 0 ? { lastZonesVisitedCount: nextZonesCount } : {}
|
|
35858
35896
|
}
|
|
35859
35897
|
};
|
|
35860
35898
|
}
|
|
@@ -39465,6 +39503,10 @@ var TRACKS_COLUMNS = [
|
|
|
39465
39503
|
name: "debug",
|
|
39466
39504
|
type: "BOOLEAN"
|
|
39467
39505
|
},
|
|
39506
|
+
{
|
|
39507
|
+
name: "debugNote",
|
|
39508
|
+
type: "TEXT"
|
|
39509
|
+
},
|
|
39468
39510
|
{
|
|
39469
39511
|
name: "favourited",
|
|
39470
39512
|
type: "BOOLEAN"
|
|
@@ -39660,6 +39702,7 @@ function cloneTrack(t) {
|
|
|
39660
39702
|
markForTrain: t.retrainStatus === "staging"
|
|
39661
39703
|
} : {},
|
|
39662
39704
|
...t.debug !== void 0 ? { debug: t.debug } : {},
|
|
39705
|
+
...t.debugNote !== void 0 ? { debugNote: t.debugNote } : {},
|
|
39663
39706
|
...t.favourited !== void 0 ? { favourited: t.favourited } : {},
|
|
39664
39707
|
...t.hasFace !== void 0 ? { hasFace: t.hasFace } : {},
|
|
39665
39708
|
...t.hasEmbeddedFace !== void 0 ? { hasEmbeddedFace: t.hasEmbeddedFace } : {},
|
|
@@ -39896,7 +39939,8 @@ var TrackStore = class {
|
|
|
39896
39939
|
* Cheap read of an active track's promotion-relevant fields WITHOUT the deep
|
|
39897
39940
|
* clone `getActiveByTrack` does — the returned `positions` is the live
|
|
39898
39941
|
* internal array (read-only; callers must not mutate). Feeds the per-frame
|
|
39899
|
-
* stationary-promotion check
|
|
39942
|
+
* stationary-promotion check AND the lifecycle update gate, both called at
|
|
39943
|
+
* inference fps. Null if unknown/expired.
|
|
39900
39944
|
*/
|
|
39901
39945
|
peekActive(trackId) {
|
|
39902
39946
|
const t = this.active.get(trackId);
|
|
@@ -39904,6 +39948,7 @@ var TrackStore = class {
|
|
|
39904
39948
|
return {
|
|
39905
39949
|
firstSeen: t.firstSeen,
|
|
39906
39950
|
positions: t.positions,
|
|
39951
|
+
zonesVisitedCount: t.zonesVisited.length,
|
|
39907
39952
|
...displayLabel(t) !== void 0 ? { label: displayLabel(t) } : {}
|
|
39908
39953
|
};
|
|
39909
39954
|
}
|
|
@@ -40048,12 +40093,14 @@ var TrackStore = class {
|
|
|
40048
40093
|
const nextStatus = patch.markForTrain === void 0 ? void 0 : patch.markForTrain ? "staging" : "none";
|
|
40049
40094
|
if (nextStatus !== void 0) data["retrainStatus"] = nextStatus;
|
|
40050
40095
|
if (patch.debug !== void 0) data["debug"] = patch.debug;
|
|
40096
|
+
if (patch.debugNote !== void 0) data["debugNote"] = patch.debugNote;
|
|
40051
40097
|
if (patch.favourited !== void 0) data["favourited"] = patch.favourited;
|
|
40052
40098
|
if (Object.keys(data).length === 0) return;
|
|
40053
40099
|
const active = this.active.get(trackId);
|
|
40054
40100
|
if (active) {
|
|
40055
40101
|
if (nextStatus !== void 0) active.retrainStatus = nextStatus;
|
|
40056
40102
|
if (patch.debug !== void 0) active.debug = patch.debug;
|
|
40103
|
+
if (patch.debugNote !== void 0) active.debugNote = patch.debugNote;
|
|
40057
40104
|
if (patch.favourited !== void 0) active.favourited = patch.favourited;
|
|
40058
40105
|
}
|
|
40059
40106
|
try {
|
|
@@ -40256,6 +40303,7 @@ var TrackStore = class {
|
|
|
40256
40303
|
if (active) return {
|
|
40257
40304
|
retrainStatus: active.retrainStatus ?? "none",
|
|
40258
40305
|
debug: active.debug === true,
|
|
40306
|
+
debugNote: active.debugNote ?? "",
|
|
40259
40307
|
favourited: active.favourited === true
|
|
40260
40308
|
};
|
|
40261
40309
|
const persisted = await this.getPersistedByTrackId(trackId);
|
|
@@ -40263,6 +40311,7 @@ var TrackStore = class {
|
|
|
40263
40311
|
return {
|
|
40264
40312
|
retrainStatus: persisted.retrainStatus ?? "none",
|
|
40265
40313
|
debug: persisted.debug === true,
|
|
40314
|
+
debugNote: persisted.debugNote ?? "",
|
|
40266
40315
|
favourited: persisted.favourited === true
|
|
40267
40316
|
};
|
|
40268
40317
|
}
|
|
@@ -41162,6 +41211,7 @@ var TrackStore = class {
|
|
|
41162
41211
|
...t.audioLabels !== void 0 ? { audioLabels: [...t.audioLabels] } : {},
|
|
41163
41212
|
...t.retrainStatus !== void 0 ? { retrainStatus: t.retrainStatus } : {},
|
|
41164
41213
|
...t.debug !== void 0 ? { debug: t.debug } : {},
|
|
41214
|
+
...t.debugNote !== void 0 ? { debugNote: t.debugNote } : {},
|
|
41165
41215
|
...t.favourited !== void 0 ? { favourited: t.favourited } : {},
|
|
41166
41216
|
...t.hasFace !== void 0 ? { hasFace: t.hasFace } : {},
|
|
41167
41217
|
...t.hasEmbeddedFace !== void 0 ? { hasEmbeddedFace: t.hasEmbeddedFace } : {},
|
|
@@ -41220,6 +41270,7 @@ var TrackStore = class {
|
|
|
41220
41270
|
const audioLabels = readAudioLabels(data["audioLabels"]);
|
|
41221
41271
|
const retrainParsed = RetrainStatusSchema.safeParse(data["retrainStatus"]);
|
|
41222
41272
|
const debug = data["debug"];
|
|
41273
|
+
const debugNote = data["debugNote"];
|
|
41223
41274
|
const favourited = data["favourited"];
|
|
41224
41275
|
const hasFace = data["hasFace"];
|
|
41225
41276
|
/** Same read as `hasFace` — NULL / missing stays ABSENT, never `false`.
|
|
@@ -41268,6 +41319,7 @@ var TrackStore = class {
|
|
|
41268
41319
|
markForTrain: retrainParsed.data === "staging"
|
|
41269
41320
|
} : {},
|
|
41270
41321
|
...typeof debug === "boolean" ? { debug } : {},
|
|
41322
|
+
...typeof debugNote === "string" ? { debugNote } : {},
|
|
41271
41323
|
...typeof favourited === "boolean" ? { favourited } : {},
|
|
41272
41324
|
...typeof hasFace === "boolean" ? { hasFace } : {},
|
|
41273
41325
|
...typeof hasEmbeddedFace === "boolean" ? { hasEmbeddedFace } : {},
|
|
@@ -54790,6 +54842,47 @@ var TrackAlreadyTrainedError = class extends Error {
|
|
|
54790
54842
|
}
|
|
54791
54843
|
};
|
|
54792
54844
|
/**
|
|
54845
|
+
* The `debugNote` half of the patch — `{}` when nothing should be written.
|
|
54846
|
+
*
|
|
54847
|
+
* The note is not an independent column: it is the operator's sentence about
|
|
54848
|
+
* why `debug` is on, so it exists exactly as long as the flag does. Three
|
|
54849
|
+
* cases, and the order matters:
|
|
54850
|
+
*
|
|
54851
|
+
* 1. **`debug: false` in the patch → the note is CLEARED**, whatever the
|
|
54852
|
+
* caller sent with it. A note surviving the flag is a leftover that reads
|
|
54853
|
+
* as a live request, and the invariant belongs here rather than in the
|
|
54854
|
+
* three surfaces that write this patch — one of which is a browser grid
|
|
54855
|
+
* that has no note UI at all and would never think to clear it.
|
|
54856
|
+
* 2. **No note in the patch → nothing is written.** This is what makes a
|
|
54857
|
+
* cancelled prompt free: the app turns debug on, the operator declines to
|
|
54858
|
+
* type, and the flag still lands. Refusing to write a note must never cost
|
|
54859
|
+
* the capture that was asked for.
|
|
54860
|
+
* 3. **A note, on a track whose debug is off and is not being turned on →
|
|
54861
|
+
* DROPPED.** Storing it would put the operator's words somewhere no reader
|
|
54862
|
+
* of a debug set will ever look. Dropped work is logged, per-camera: a
|
|
54863
|
+
* branch that silently discards a sentence is indistinguishable from one
|
|
54864
|
+
* that stored it.
|
|
54865
|
+
*
|
|
54866
|
+
* `''` is a WRITE, not an absence — clearing a note the operator no longer
|
|
54867
|
+
* stands behind is a real edit.
|
|
54868
|
+
*/
|
|
54869
|
+
function resolveNotePatch(deps, input, current) {
|
|
54870
|
+
if (input.flags.debug === false) return { debugNote: "" };
|
|
54871
|
+
if (input.flags.debugNote === void 0) return {};
|
|
54872
|
+
if (!(input.flags.debug === true || current.debug)) {
|
|
54873
|
+
deps.logger.warn("setTrackFlags dropped a debug note — the track is not flagged for debug", {
|
|
54874
|
+
tags: { deviceId: input.deviceId },
|
|
54875
|
+
meta: {
|
|
54876
|
+
deviceId: input.deviceId,
|
|
54877
|
+
trackId: input.trackId,
|
|
54878
|
+
noteLength: input.flags.debugNote.length
|
|
54879
|
+
}
|
|
54880
|
+
});
|
|
54881
|
+
return {};
|
|
54882
|
+
}
|
|
54883
|
+
return { debugNote: input.flags.debugNote };
|
|
54884
|
+
}
|
|
54885
|
+
/**
|
|
54793
54886
|
* Apply a partial flag patch and report the RESOLVED state of both flags.
|
|
54794
54887
|
*
|
|
54795
54888
|
* Existence is checked BEFORE the write: a patch against a track that no longer
|
|
@@ -54850,7 +54943,8 @@ async function applyTrackFlags(deps, input) {
|
|
|
54850
54943
|
const patch = {
|
|
54851
54944
|
...input.flags.markForTrain !== void 0 ? { markForTrain: input.flags.markForTrain } : {},
|
|
54852
54945
|
...input.flags.debug !== void 0 ? { debug: input.flags.debug } : {},
|
|
54853
|
-
...input.flags.favourited !== void 0 ? { favourited: input.flags.favourited } : {}
|
|
54946
|
+
...input.flags.favourited !== void 0 ? { favourited: input.flags.favourited } : {},
|
|
54947
|
+
...resolveNotePatch(deps, input, current)
|
|
54854
54948
|
};
|
|
54855
54949
|
if (Object.keys(patch).length > 0) await store.setFlags(input.trackId, patch);
|
|
54856
54950
|
const retrainStatus = patch.markForTrain === void 0 ? current.retrainStatus : patch.markForTrain ? "staging" : "none";
|
|
@@ -54858,6 +54952,7 @@ async function applyTrackFlags(deps, input) {
|
|
|
54858
54952
|
trackId: input.trackId,
|
|
54859
54953
|
markForTrain: retrainStatus === "staging",
|
|
54860
54954
|
debug: patch.debug ?? current.debug,
|
|
54955
|
+
debugNote: patch.debugNote ?? current.debugNote,
|
|
54861
54956
|
favourited: patch.favourited ?? current.favourited,
|
|
54862
54957
|
retrainStatus
|
|
54863
54958
|
};
|
|
@@ -58587,6 +58682,13 @@ var ANALYTICS_COLLECTIONS = [
|
|
|
58587
58682
|
kind: "never-orphaned",
|
|
58588
58683
|
why: "declares `sourceTrackId`, which is a REFERENCE and not ownership — a parked object outliving the track that first saw it is the entire purpose of the registry. It has its own TTL sweep keyed on OBSERVED frame time, not wall clock. Classified by hand precisely because the derivation must not see it."
|
|
58589
58684
|
}
|
|
58685
|
+
},
|
|
58686
|
+
{
|
|
58687
|
+
collection: STATIONARY_EVIDENCE_COLLECTION,
|
|
58688
|
+
classification: {
|
|
58689
|
+
kind: "never-orphaned",
|
|
58690
|
+
why: "the candidate half of the registry above, and it inherits that entry's argument for the same reason: `sourceTrackId` is the PROVENANCE of whichever track happened to be looking, never ownership. It cannot be `track-owned` on the behaviour, not merely on the name — a candidate is fed by a SUCCESSION of tracks (`StationaryEvidenceLedger.observe` re-binds under D280, and `retainTracks` drops a binding the moment the tracker forgets the track) while the row itself survives, because agreement accumulating ACROSS tracks is the whole measurement. Cascading it on the first contributor's eviction would delete evidence still being gathered by tracks alive right now. Its bounds are its own and stay inside D61's one-clock rule: a candidate untouched for EVIDENCE_WINDOW_MS (6h) is dropped by `expire`, on the next OBSERVATION of that device and against the frame timestamp — the same observed-time clock the registry uses, never wall clock and never a sweep; a device is capped at EVIDENCE_MAX_CANDIDATES_PER_DEVICE (512, least-recently-touched evicted); a promotion deletes the candidate the instant the registry entry is born, so the two tables cannot both hold the object; and `clearDevice` takes the rest when a camera is removed. Deliberately NOT `owner-indirection`: that kind enrols a collection into `auditableCollections()`, and the audit has a resolver only for `pipeline-analytics:media`."
|
|
58691
|
+
}
|
|
58590
58692
|
}
|
|
58591
58693
|
];
|
|
58592
58694
|
/** The collections the orphan audit actually scans — everything with an owner. */
|
|
@@ -71084,15 +71186,41 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
71084
71186
|
*/
|
|
71085
71187
|
maybeEmitTrackLifecycleUpdate(deviceId, t, timestamp, isNewBest) {
|
|
71086
71188
|
const memory = this.residents.lifecycleUpdateMem(t.trackId);
|
|
71189
|
+
/**
|
|
71190
|
+
* The signal's label reads the frame patch AND the track row: the face
|
|
71191
|
+
* recognizer writes a recognised identity to the ROW over the async
|
|
71192
|
+
* detail plane, never into a frame patch, and a patch-only read left the
|
|
71193
|
+
* identity trigger unable to fire for a face — every face name reached
|
|
71194
|
+
* the export surfaces only on the `end` event, ~30 s after the subject
|
|
71195
|
+
* left the frame (measured live 2026-09-05).
|
|
71196
|
+
*/
|
|
71197
|
+
const peeked = this.trackStore?.peekActive(t.trackId);
|
|
71198
|
+
const label = resolveLifecycleUpdateLabel(t.labelPatch, peeked?.label);
|
|
71087
71199
|
const decision = evaluateTrackLifecycleUpdate({
|
|
71088
71200
|
isNewBest,
|
|
71089
71201
|
confidence: t.confidence,
|
|
71090
71202
|
now: timestamp,
|
|
71091
|
-
...
|
|
71203
|
+
...label !== void 0 ? { label } : {},
|
|
71204
|
+
...peeked !== null && peeked !== void 0 ? { zonesVisitedCount: peeked.zonesVisitedCount } : {},
|
|
71092
71205
|
bboxArea: t.bbox.w * t.bbox.h
|
|
71093
71206
|
}, memory, DEFAULT_UPDATE_GATE_CONFIG);
|
|
71094
71207
|
this.residents.setLifecycleUpdateMem(deviceId, t.trackId, decision.memory);
|
|
71095
|
-
if (!decision.emit)
|
|
71208
|
+
if (!decision.emit) {
|
|
71209
|
+
/**
|
|
71210
|
+
* Dropped for cadence (debounce) — counted, never silent. The count
|
|
71211
|
+
* since the last emit rides the memory and this line; a throttle
|
|
71212
|
+
* with no ledger is how a 30 s delivery delay stayed invisible.
|
|
71213
|
+
*/
|
|
71214
|
+
if (decision.suppressed !== void 0) this.ctx.logger.debug("lifecycle update suppressed (debounce)", {
|
|
71215
|
+
tags: { deviceId },
|
|
71216
|
+
meta: {
|
|
71217
|
+
trackId: t.trackId,
|
|
71218
|
+
reason: decision.suppressed,
|
|
71219
|
+
suppressedSinceEmit: decision.memory.suppressedSinceEmit ?? 0
|
|
71220
|
+
}
|
|
71221
|
+
});
|
|
71222
|
+
return;
|
|
71223
|
+
}
|
|
71096
71224
|
const track = this.trackStore?.getActiveByTrack(t.trackId);
|
|
71097
71225
|
const keyFrameMediaKey = this.residents.keyFrameKey(t.trackId);
|
|
71098
71226
|
const payload = buildTrackLifecyclePayload({
|
|
@@ -71104,7 +71232,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
71104
71232
|
bestConfidence: t.confidence,
|
|
71105
71233
|
firstSeen: track?.firstSeen ?? timestamp,
|
|
71106
71234
|
lastSeen: track?.lastSeen ?? timestamp,
|
|
71107
|
-
...
|
|
71235
|
+
...label !== void 0 ? { label } : {},
|
|
71108
71236
|
...t.plateText !== void 0 ? { plateText: t.plateText } : {},
|
|
71109
71237
|
...track?.zonesVisited !== void 0 ? { zonesVisited: track.zonesVisited } : {},
|
|
71110
71238
|
...track?.totalDistance !== void 0 ? { totalDistance: track.totalDistance } : {},
|
|
@@ -30,7 +30,7 @@ async function d(e) {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
async function f() {
|
|
33
|
-
return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-
|
|
33
|
+
return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-BL6jNwq1.mjs")).catch((e) => {
|
|
34
34
|
throw l = void 0, e;
|
|
35
35
|
}), l;
|
|
36
36
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-post-analysis",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.179",
|
|
4
4
|
"description": "Post-Analysis bundle — enrichment, embedding-encoder, pipeline-analytics. Multi-entry npm package shipping addons that consume pipeline output.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|