@camstack/addon-post-analysis 1.2.627 → 1.2.628
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/{clip-model-registry-RSxtlgdN.js → clip-model-registry-CK0QHBLo.js} +77 -198
- package/dist/{clip-model-registry-CCMO8jrp.mjs → clip-model-registry-CXp8hOtz.mjs} +77 -198
- package/dist/embedding-encoder/index.js +1 -1
- package/dist/embedding-encoder/index.mjs +1 -1
- package/dist/pipeline-analytics/_stub.js +2 -2
- package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-CB62NeGh.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-BSMQI14W.mjs} +2 -2
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CC5fsXdm.mjs +26 -0
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DdDfkgWU.mjs +26 -0
- package/dist/pipeline-analytics/{hostInit-BUdkjx1s.mjs → hostInit-DZur54eI.mjs} +2 -2
- package/dist/pipeline-analytics/index.js +150 -118
- package/dist/pipeline-analytics/index.mjs +150 -118
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +1 -1
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DY-_tUCM.mjs +0 -26
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-_Ip2ZGVX.mjs +0 -26
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_clip_model_registry = require("../clip-model-registry-
|
|
5
|
+
const require_clip_model_registry = require("../clip-model-registry-CK0QHBLo.js");
|
|
6
6
|
let node_fs = require("node:fs");
|
|
7
7
|
node_fs = require_clip_model_registry.__toESM(node_fs, 1);
|
|
8
8
|
let node_path = require("node:path");
|
|
@@ -9913,7 +9913,6 @@ var SCENE_LATCH_SPEC = {
|
|
|
9913
9913
|
fromRecord: latchFromRecord,
|
|
9914
9914
|
deviceIdOf: (row) => row.deviceId
|
|
9915
9915
|
};
|
|
9916
|
-
SCENE_LATCH_SPEC.fromRecord, SCENE_LATCH_SPEC.toValue, SCENE_LATCH_SPEC.deviceIdOf;
|
|
9917
9916
|
/**
|
|
9918
9917
|
* The two ledgers behind one façade. Callers never see the split, but they can
|
|
9919
9918
|
* never accidentally write one when they meant the other either: the config
|
|
@@ -22328,6 +22327,8 @@ function proposalOrigin(source, index, facts) {
|
|
|
22328
22327
|
...facts.modelId !== void 0 ? { modelId: facts.modelId } : {}
|
|
22329
22328
|
};
|
|
22330
22329
|
}
|
|
22330
|
+
//#endregion
|
|
22331
|
+
//#region src/pipeline-analytics/retrain/retrain-taxonomy.ts
|
|
22331
22332
|
var MACRO_SET = new Set([
|
|
22332
22333
|
"person",
|
|
22333
22334
|
"vehicle",
|
|
@@ -25908,7 +25909,6 @@ var NC_ALERTS_SPEC = {
|
|
|
25908
25909
|
equalFact: (held, incoming) => held.alerting === incoming.alerting,
|
|
25909
25910
|
deviceIdOf: (row) => deviceIdOf(row.subject)
|
|
25910
25911
|
};
|
|
25911
|
-
NC_ALERTS_SPEC.fromRecord, NC_ALERTS_SPEC.toValue, NC_ALERTS_SPEC.deviceIdOf;
|
|
25912
25912
|
/**
|
|
25913
25913
|
* Which row the boot settle keeps for one subject observed inside the window
|
|
25914
25914
|
* (D698's rule, applied to the alert ledger).
|
|
@@ -30641,7 +30641,6 @@ var NC_DEVICE_PRUNES_SPEC = {
|
|
|
30641
30641
|
deviceIdOf: (row) => row.subjectKind === "device" ? Number(row.subject) : void 0,
|
|
30642
30642
|
loadLimit: LOAD_LIMIT$1
|
|
30643
30643
|
};
|
|
30644
|
-
NC_DEVICE_PRUNES_SPEC.fromRecord, NC_DEVICE_PRUNES_SPEC.toValue, NC_DEVICE_PRUNES_SPEC.deviceIdOf;
|
|
30645
30644
|
/** The outcomes that mean "this last reference was already dealt with". */
|
|
30646
30645
|
var KEPT_OUTCOMES = new Set(["kept-disabled", "kept"]);
|
|
30647
30646
|
var NcPruneLedger = class {
|
|
@@ -45648,7 +45647,6 @@ var NC_ALERT_EPISODES_SPEC = {
|
|
|
45648
45647
|
};
|
|
45649
45648
|
}
|
|
45650
45649
|
};
|
|
45651
|
-
NC_ALERT_EPISODES_SPEC.fromRecord, NC_ALERT_EPISODES_SPEC.toValue;
|
|
45652
45650
|
var NcAlertEpisodeLedger = class {
|
|
45653
45651
|
ledger;
|
|
45654
45652
|
constructor(deps) {
|
|
@@ -45806,6 +45804,8 @@ function occupancyClassWarning(className) {
|
|
|
45806
45804
|
if (className === void 0 || require_clip_model_registry.isDetectionMacroClass(className)) return null;
|
|
45807
45805
|
return `⚠ “${className}” is a sub-type, not a macro class: this counter is always 0 (use ${[...require_clip_model_registry.DETECTION_MACRO_CLASSES].join(" / ")})`;
|
|
45808
45806
|
}
|
|
45807
|
+
//#endregion
|
|
45808
|
+
//#region src/notification-center/occupancy-store.ts
|
|
45809
45809
|
/**
|
|
45810
45810
|
* The mechanics, declared once.
|
|
45811
45811
|
*
|
|
@@ -45957,7 +45957,6 @@ function recordToRow(key, data) {
|
|
|
45957
45957
|
updatedAt
|
|
45958
45958
|
};
|
|
45959
45959
|
}
|
|
45960
|
-
NC_OCCUPANCY_SPEC.fromRecord, NC_OCCUPANCY_SPEC.toValue, NC_OCCUPANCY_SPEC.deviceIdOf;
|
|
45961
45960
|
//#endregion
|
|
45962
45961
|
//#region src/notification-center/outbox.ts
|
|
45963
45962
|
/**
|
|
@@ -48428,7 +48427,6 @@ var NC_SNOOZES_SPEC = {
|
|
|
48428
48427
|
},
|
|
48429
48428
|
loadLimit: 1e3
|
|
48430
48429
|
};
|
|
48431
|
-
NC_SNOOZES_SPEC.fromRecord, NC_SNOOZES_SPEC.toValue;
|
|
48432
48430
|
var NcSnoozeStore = class {
|
|
48433
48431
|
windows;
|
|
48434
48432
|
/** The `snooze-suppressed` records kind (events.db): the counters. */
|
|
@@ -52526,7 +52524,6 @@ var NC_SYSTEM_STATE_SPEC = {
|
|
|
52526
52524
|
},
|
|
52527
52525
|
deviceIdOf: (row) => row.deviceId
|
|
52528
52526
|
};
|
|
52529
|
-
NC_SYSTEM_STATE_SPEC.fromRecord, NC_SYSTEM_STATE_SPEC.toValue, NC_SYSTEM_STATE_SPEC.deviceIdOf;
|
|
52530
52527
|
/** The hub's own node id when an update row names none. */
|
|
52531
52528
|
var HUB_NODE = "hub";
|
|
52532
52529
|
function isUpdateTarget(value) {
|
|
@@ -53612,6 +53609,8 @@ var NcStateSummaryScheduler = class {
|
|
|
53612
53609
|
}
|
|
53613
53610
|
}
|
|
53614
53611
|
};
|
|
53612
|
+
//#endregion
|
|
53613
|
+
//#region src/notification-center/state-summary/state-summary-stamps.ts
|
|
53615
53614
|
var SPEC = {
|
|
53616
53615
|
collection: "notification-center:state-summary-stamps",
|
|
53617
53616
|
columns: [
|
|
@@ -53659,7 +53658,6 @@ var SPEC = {
|
|
|
53659
53658
|
},
|
|
53660
53659
|
loadLimit: 1e4
|
|
53661
53660
|
};
|
|
53662
|
-
SPEC.fromRecord, SPEC.toValue;
|
|
53663
53661
|
var NcStateSummaryStampStore = class {
|
|
53664
53662
|
ledger;
|
|
53665
53663
|
constructor(deps) {
|
|
@@ -74888,8 +74886,8 @@ var TrackCloser = class {
|
|
|
74888
74886
|
}
|
|
74889
74887
|
});
|
|
74890
74888
|
}
|
|
74891
|
-
/** Emit the
|
|
74892
|
-
*
|
|
74889
|
+
/** Emit the thin `TrackEnded` event + the unified lifecycle `end` event
|
|
74890
|
+
* (the FULL final summary — fires ONCE per real track). */
|
|
74893
74891
|
emitEndEvents(t, duration, trackerPeakConfidence, keyFrameMediaId, summary) {
|
|
74894
74892
|
this.deps.emitTrackEnded({
|
|
74895
74893
|
deviceId: t.deviceId,
|
|
@@ -79215,22 +79213,22 @@ function buildTapeDeleteDeps(src) {
|
|
|
79215
79213
|
removeFile: src.removeFile
|
|
79216
79214
|
};
|
|
79217
79215
|
}
|
|
79218
|
-
function unavailable(reason) {
|
|
79216
|
+
function unavailable$1(reason) {
|
|
79219
79217
|
return {
|
|
79220
79218
|
status: "unavailable",
|
|
79221
79219
|
reason
|
|
79222
79220
|
};
|
|
79223
79221
|
}
|
|
79224
79222
|
async function releaseOrUnavailable(deps, tapeId, queue) {
|
|
79225
|
-
if (typeof deps === "string") return unavailable(deps);
|
|
79223
|
+
if (typeof deps === "string") return unavailable$1(deps);
|
|
79226
79224
|
return queue.run((signal) => releaseTape(deps, tapeId, signal), { name: "release" });
|
|
79227
79225
|
}
|
|
79228
79226
|
async function deleteOrUnavailable(deps, tapeId, queue) {
|
|
79229
|
-
if (typeof deps === "string") return unavailable(deps);
|
|
79227
|
+
if (typeof deps === "string") return unavailable$1(deps);
|
|
79230
79228
|
return queue.run((signal) => deleteTape(deps, tapeId, signal), { name: "delete" });
|
|
79231
79229
|
}
|
|
79232
79230
|
async function reconcileOrUnavailable(deps, queue) {
|
|
79233
|
-
if (typeof deps === "string") return unavailable(deps);
|
|
79231
|
+
if (typeof deps === "string") return unavailable$1(deps);
|
|
79234
79232
|
return queue.run((signal) => reconcileTapePins(deps, signal), { name: "reconcile" });
|
|
79235
79233
|
}
|
|
79236
79234
|
/**
|
|
@@ -83794,6 +83792,9 @@ function isConfirmationCompatible(trackClassName, detectionMacroClass) {
|
|
|
83794
83792
|
if (track === "other" || det === "other") return true;
|
|
83795
83793
|
return track === det;
|
|
83796
83794
|
}
|
|
83795
|
+
function isSessionDetectorUnavailable(answer) {
|
|
83796
|
+
return answer !== null && "unavailable" in answer;
|
|
83797
|
+
}
|
|
83797
83798
|
var undecided = (candidate, reason) => ({
|
|
83798
83799
|
trackId: candidate.trackId,
|
|
83799
83800
|
verdict: "undecided",
|
|
@@ -83816,7 +83817,7 @@ async function runConfirmation(candidate, config, deps, exhausted) {
|
|
|
83816
83817
|
const carried = candidate.evidenceCrop ?? null;
|
|
83817
83818
|
if (carried) {
|
|
83818
83819
|
const verdict = await measure(candidate, carried, config, deps, "carried");
|
|
83819
|
-
if (verdict.verdict === "confirmed" || verdict.reason === "redetect-error") return verdict;
|
|
83820
|
+
if (verdict.verdict === "confirmed" || verdict.reason === "redetect-error" || verdict.reason === "session-device-unavailable") return verdict;
|
|
83820
83821
|
}
|
|
83821
83822
|
let crop = await deps.fetchCrop(candidate);
|
|
83822
83823
|
let cropSource = "native";
|
|
@@ -83838,32 +83839,26 @@ async function measure(candidate, crop, config, deps, cropSource) {
|
|
|
83838
83839
|
deps.keepCrop?.(candidate, crop, cropSource);
|
|
83839
83840
|
const detections = await deps.redetect(crop);
|
|
83840
83841
|
if (detections === null) return undecided(candidate, "redetect-error");
|
|
83842
|
+
if (isSessionDetectorUnavailable(detections)) return undecided(candidate, "session-device-unavailable");
|
|
83841
83843
|
let best;
|
|
83842
83844
|
let bestIncompatible;
|
|
83843
|
-
|
|
83844
|
-
|
|
83845
|
-
|
|
83846
|
-
if (d.
|
|
83847
|
-
if (compatible && (!bestRefused || d.score > bestRefused.score)) bestRefused = d;
|
|
83848
|
-
continue;
|
|
83849
|
-
}
|
|
83850
|
-
if (compatible) {
|
|
83851
|
-
if (!best || d.score > best.score) best = d;
|
|
83852
|
-
} else if (!bestIncompatible || d.score > bestIncompatible.score) bestIncompatible = d;
|
|
83845
|
+
for (const d of detections) if (isConfirmationCompatible(candidate.className, d.macroClass)) {
|
|
83846
|
+
if (!best || d.score > best.score) best = d;
|
|
83847
|
+
} else if (d.refusedByDetectorFloor !== true) {
|
|
83848
|
+
if (!bestIncompatible || d.score > bestIncompatible.score) bestIncompatible = d;
|
|
83853
83849
|
}
|
|
83854
83850
|
const bar = barFor(candidate, config, deps);
|
|
83855
83851
|
const confirmed = best !== void 0 && best.score >= bar;
|
|
83856
83852
|
if (!confirmed && cropSource !== "native") return undecided(candidate, cropSource === "fallback" ? "fallback-inconclusive" : "carried-inconclusive");
|
|
83857
83853
|
const secondary = bestIncompatible ? promoteSecondary(candidate, bestIncompatible, bar, deps) : null;
|
|
83858
|
-
const scored = best ?? bestRefused;
|
|
83859
83854
|
return {
|
|
83860
83855
|
trackId: candidate.trackId,
|
|
83861
83856
|
verdict: confirmed ? "confirmed" : "suppressed",
|
|
83862
|
-
reason: confirmed ? "confirmed" : suppressionReason(best,
|
|
83857
|
+
reason: confirmed ? "confirmed" : suppressionReason(best, bestIncompatible),
|
|
83863
83858
|
className: candidate.className,
|
|
83864
83859
|
appliedMinConfidence: bar,
|
|
83865
83860
|
cropSource,
|
|
83866
|
-
...
|
|
83861
|
+
...best ? { bestScore: best.score } : {},
|
|
83867
83862
|
...bestIncompatible ? {
|
|
83868
83863
|
bestIncompatibleClass: bestIncompatible.macroClass,
|
|
83869
83864
|
bestIncompatibleScore: bestIncompatible.score
|
|
@@ -83871,10 +83866,13 @@ async function measure(candidate, crop, config, deps, cropSource) {
|
|
|
83871
83866
|
...secondary ? { secondary } : {}
|
|
83872
83867
|
};
|
|
83873
83868
|
}
|
|
83874
|
-
/**
|
|
83875
|
-
|
|
83876
|
-
|
|
83877
|
-
|
|
83869
|
+
/**
|
|
83870
|
+
* Why a measured native crop said no — first matching rule wins (D922). The
|
|
83871
|
+
* best compatible box is under the gate's bar either way; `below-detector-floor`
|
|
83872
|
+
* says the detector's own floor had refused it too (D925).
|
|
83873
|
+
*/
|
|
83874
|
+
function suppressionReason(best, bestIncompatible) {
|
|
83875
|
+
if (best !== void 0) return best.refusedByDetectorFloor === true ? "below-detector-floor" : "scored-below-threshold";
|
|
83878
83876
|
if (bestIncompatible !== void 0) return "incompatible-class";
|
|
83879
83877
|
return "no-detection";
|
|
83880
83878
|
}
|
|
@@ -86624,11 +86622,9 @@ function faceSizeScore(detectionFrameShortSidePx) {
|
|
|
86624
86622
|
return detectionFrameShortSidePx / FACE_SIZE_SCORE_REFERENCE_PX;
|
|
86625
86623
|
}
|
|
86626
86624
|
//#endregion
|
|
86627
|
-
//#region src/pipeline-analytics/face-
|
|
86625
|
+
//#region src/pipeline-analytics/face-recognizer.ts
|
|
86628
86626
|
/** The recognizer's step id — the attribution a face identity label carries. */
|
|
86629
86627
|
var FACE_RECOGNIZER_STEP_ID = "face-recognizer";
|
|
86630
|
-
//#endregion
|
|
86631
|
-
//#region src/pipeline-analytics/face-recognizer.ts
|
|
86632
86628
|
/** At most one "dropping imageless track" log per this interval, per recognizer. */
|
|
86633
86629
|
var FACE_IMAGELESS_LOG_THROTTLE_MS = 6e4;
|
|
86634
86630
|
/** At most one 'embedding magnitude' sample line per device per this interval. */
|
|
@@ -93068,6 +93064,9 @@ function buildBirthDecisionRecord(input) {
|
|
|
93068
93064
|
bestScore: input.bestScore ?? null,
|
|
93069
93065
|
appliedMinConfidence: input.appliedMinConfidence ?? null,
|
|
93070
93066
|
cropSource: input.cropSource ?? null,
|
|
93067
|
+
detectorModelId: input.detector?.modelId ?? null,
|
|
93068
|
+
detectorDeviceKey: input.detector?.deviceKey ?? null,
|
|
93069
|
+
detectorNodeId: input.detector?.nodeId ?? null,
|
|
93071
93070
|
firstSeen,
|
|
93072
93071
|
...latency
|
|
93073
93072
|
};
|
|
@@ -93098,6 +93097,85 @@ function toConfirmationDetections(result) {
|
|
|
93098
93097
|
return [...kept, ...refused];
|
|
93099
93098
|
}
|
|
93100
93099
|
//#endregion
|
|
93100
|
+
//#region src/pipeline-analytics/confirmation-session-detector.ts
|
|
93101
|
+
/**
|
|
93102
|
+
* The detector the birth confirmation gate re-judges a birth WITH: the
|
|
93103
|
+
* session's own (D925).
|
|
93104
|
+
*
|
|
93105
|
+
* A birth is a claim made by one detector — the root model of the session that
|
|
93106
|
+
* produced the frame, on the inference-device pool it ran on. The gate asks
|
|
93107
|
+
* whether that claim holds on better pixels, so it must ask the SAME detector:
|
|
93108
|
+
* a different model has a different score scale and a different floor, and its
|
|
93109
|
+
* "no" says nothing about the claim. It used to ask the node's global default
|
|
93110
|
+
* (`getGlobalSteps`), which on a Coral node meant a CPU `yolov9t` re-judging an
|
|
93111
|
+
* `edgetpu` model's births.
|
|
93112
|
+
*
|
|
93113
|
+
* The identity rides the frame result (`rootStepId` / `rootModelId` /
|
|
93114
|
+
* `rootDeviceKey`, stamped by the executor with what it RAN), and the node is
|
|
93115
|
+
* the frame handle's — the same node the crop is cut on, so no new bytes cross
|
|
93116
|
+
* anywhere.
|
|
93117
|
+
*
|
|
93118
|
+
* When that detector cannot answer — no identity on the frame (an onboard
|
|
93119
|
+
* detector), the device in backoff or failed, or the executor running anything
|
|
93120
|
+
* other than exactly that model on exactly that pool — the answer is
|
|
93121
|
+
* `session-device-unavailable`: NO measurement. The gate defers the birth and
|
|
93122
|
+
* admits it once the deferral is exhausted. Another model is never asked.
|
|
93123
|
+
*
|
|
93124
|
+
* PURE apart from the injected `run`, so the matrix is testable without an
|
|
93125
|
+
* executor.
|
|
93126
|
+
*/
|
|
93127
|
+
/** The session detector named by a frame, or `null` when the frame names none in full. */
|
|
93128
|
+
function sessionDetectorOf(frame, nodeId) {
|
|
93129
|
+
const { rootStepId, rootModelId, rootDeviceKey } = frame;
|
|
93130
|
+
if (!rootStepId || !rootModelId || !rootDeviceKey || !nodeId) return null;
|
|
93131
|
+
return {
|
|
93132
|
+
stepId: rootStepId,
|
|
93133
|
+
modelId: rootModelId,
|
|
93134
|
+
deviceKey: rootDeviceKey,
|
|
93135
|
+
nodeId
|
|
93136
|
+
};
|
|
93137
|
+
}
|
|
93138
|
+
/**
|
|
93139
|
+
* The executor's refusal of a device it will not dispatch to: the liveness
|
|
93140
|
+
* refusal (`InferenceDeviceUnusableError`), a device key whose backend this
|
|
93141
|
+
* node does not know, or a pinned pool that cannot serve. Read from the
|
|
93142
|
+
* message because the error crosses a process boundary without its class.
|
|
93143
|
+
*/
|
|
93144
|
+
var DEVICE_REFUSAL = /inference device ".+" is (failed|backoff)|unknown backend|device-not-servable|model-not-servable/;
|
|
93145
|
+
/** Re-detect a crop with the session detector, or say why it could not. */
|
|
93146
|
+
async function redetectWithSessionDetector(detector, cropJpeg, deviceId, run) {
|
|
93147
|
+
if (detector === null) return unavailable("the frame names no session detector");
|
|
93148
|
+
let result;
|
|
93149
|
+
try {
|
|
93150
|
+
result = await run({
|
|
93151
|
+
steps: [{
|
|
93152
|
+
addonId: detector.stepId,
|
|
93153
|
+
modelId: detector.modelId,
|
|
93154
|
+
enabled: true
|
|
93155
|
+
}],
|
|
93156
|
+
image: new Uint8Array(cropJpeg),
|
|
93157
|
+
deviceId,
|
|
93158
|
+
plane: "frame",
|
|
93159
|
+
deviceKey: detector.deviceKey
|
|
93160
|
+
}, detector.nodeId);
|
|
93161
|
+
} catch (err) {
|
|
93162
|
+
const message = require_clip_model_registry.errMsg(err);
|
|
93163
|
+
if (DEVICE_REFUSAL.test(message)) return unavailable(message);
|
|
93164
|
+
return {
|
|
93165
|
+
answer: null,
|
|
93166
|
+
error: message
|
|
93167
|
+
};
|
|
93168
|
+
}
|
|
93169
|
+
if (result !== null && (result.rootModelId !== detector.modelId || result.rootDeviceKey !== detector.deviceKey)) return unavailable(`ran ${result.rootModelId ?? "an unnamed model"} on ${result.rootDeviceKey ?? "an unnamed pool"}, not ${detector.modelId} on ${detector.deviceKey}`);
|
|
93170
|
+
return { answer: toConfirmationDetections(result) };
|
|
93171
|
+
}
|
|
93172
|
+
function unavailable(detail) {
|
|
93173
|
+
return { answer: {
|
|
93174
|
+
unavailable: "session-device-unavailable",
|
|
93175
|
+
detail
|
|
93176
|
+
} };
|
|
93177
|
+
}
|
|
93178
|
+
//#endregion
|
|
93101
93179
|
//#region src/pipeline-analytics/pipeline/birth-evidence-store.ts
|
|
93102
93180
|
/**
|
|
93103
93181
|
* The pixels a birth arrived with, held for as long as its deferral can last —
|
|
@@ -94007,7 +94085,6 @@ var PHANTOM_CELLS_SPEC = {
|
|
|
94007
94085
|
},
|
|
94008
94086
|
deviceIdOf: (row) => row.deviceId
|
|
94009
94087
|
};
|
|
94010
|
-
PHANTOM_CELLS_SPEC.fromRecord, PHANTOM_CELLS_SPEC.toValue, PHANTOM_CELLS_SPEC.deviceIdOf;
|
|
94011
94088
|
/**
|
|
94012
94089
|
* The durable cell memory. Reads answer from RAM only (D49) — a gate that
|
|
94013
94090
|
* consulted SQLite would be a gate that fails when SQLite is slow.
|
|
@@ -94207,7 +94284,6 @@ var PACKAGE_BACKGROUND_SPEC = {
|
|
|
94207
94284
|
},
|
|
94208
94285
|
deviceIdOf: (row) => row.deviceId
|
|
94209
94286
|
};
|
|
94210
|
-
PACKAGE_BACKGROUND_SPEC.fromRecord, PACKAGE_BACKGROUND_SPEC.toValue, PACKAGE_BACKGROUND_SPEC.deviceIdOf;
|
|
94211
94287
|
/**
|
|
94212
94288
|
* The durable ghost-cycle memory. Reads answer from RAM only (D49); writes go
|
|
94213
94289
|
* write-behind — a lost write costs one under-counted cycle, which is the
|
|
@@ -96772,7 +96848,6 @@ var STATIONARY_EVIDENCE_SPEC = {
|
|
|
96772
96848
|
},
|
|
96773
96849
|
deviceIdOf: (row) => row.deviceId
|
|
96774
96850
|
};
|
|
96775
|
-
STATIONARY_EVIDENCE_SPEC.fromRecord, STATIONARY_EVIDENCE_SPEC.toValue, STATIONARY_EVIDENCE_SPEC.deviceIdOf;
|
|
96776
96851
|
var StationaryEvidenceLedger = class {
|
|
96777
96852
|
ledger;
|
|
96778
96853
|
spec = STATIONARY_EVIDENCE_SPEC;
|
|
@@ -97307,7 +97382,6 @@ var STATIONARY_SPEC = {
|
|
|
97307
97382
|
fromRecord: rowToEntry,
|
|
97308
97383
|
deviceIdOf: (entry) => entry.deviceId
|
|
97309
97384
|
};
|
|
97310
|
-
STATIONARY_SPEC.fromRecord, STATIONARY_SPEC.toValue, STATIONARY_SPEC.deviceIdOf;
|
|
97311
97385
|
var StationaryObjectRegistry = class {
|
|
97312
97386
|
/** Entry ids per device — an INDEX over the ledger's mirror, not a second
|
|
97313
97387
|
* copy of it. The entries themselves live in exactly one place. */
|
|
@@ -113388,9 +113462,6 @@ var KEYFRAME_CROP_MIN_SUBJECT_IOU = .5;
|
|
|
113388
113462
|
* evidence" and the temporal bound takes over. */
|
|
113389
113463
|
var KEYFRAME_CROP_MAX_SAMPLE_GAP_MS = 1e3;
|
|
113390
113464
|
var SETTINGS_CACHE_TTL_MS = 5e3;
|
|
113391
|
-
/** TTL for the per-node confirmation-gate detector-step cache (the node's
|
|
113392
|
-
* default object-detector step rarely changes). */
|
|
113393
|
-
var CONFIRMATION_DETECTOR_CACHE_TTL_MS = 6e4;
|
|
113394
113465
|
/** Padding applied to a birth box before re-detecting it — a little context
|
|
113395
113466
|
* around the subject improves the confirmation detector's recall. */
|
|
113396
113467
|
var CONFIRMATION_CROP_PADDING = .15;
|
|
@@ -114178,11 +114249,6 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
114178
114249
|
trackingSettingsCache = this.settingsCaches.registerDeviceCache("tracking", SETTINGS_CACHE_TTL_MS);
|
|
114179
114250
|
/** Per-device confirmation-gate settings cache (default off), TTL-mirrored. */
|
|
114180
114251
|
confirmationGateSettingsCache = this.settingsCaches.registerDeviceCache("confirmation-gate", SETTINGS_CACHE_TTL_MS);
|
|
114181
|
-
/** Per-node detector-step cache for the confirmation gate's re-detection —
|
|
114182
|
-
* the node's default root object-detector reduced to a single childless
|
|
114183
|
-
* step, resolved lazily from `pipelineExecutor.getGlobalSteps` and reused.
|
|
114184
|
-
* NOT part of the settings-cache hub: node-keyed, not device-keyed. */
|
|
114185
|
-
confirmationDetectorStepByNode = /* @__PURE__ */ new Map();
|
|
114186
114252
|
faceSettingsCache = this.settingsCaches.registerDeviceCache("face", SETTINGS_CACHE_TTL_MS);
|
|
114187
114253
|
/** GLOBAL face-recognition master switch (addon store), TTL-cached. */
|
|
114188
114254
|
faceGlobalEnabledCache = this.settingsCaches.registerGlobalCache("face-global-enabled", SETTINGS_CACHE_TTL_MS);
|
|
@@ -118452,7 +118518,6 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
118452
118518
|
this.settingsCaches.clearAll();
|
|
118453
118519
|
this.rawDeviceBlobMirror.invalidateAll();
|
|
118454
118520
|
this.rawGlobalStoreMirror.invalidate();
|
|
118455
|
-
this.confirmationDetectorStepByNode.clear();
|
|
118456
118521
|
this.trackStore?.clearAll();
|
|
118457
118522
|
this.stationaryRegistry = null;
|
|
118458
118523
|
this.bindingCache?.clearAll();
|
|
@@ -119110,6 +119175,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
119110
119175
|
this.birthEvidence.remember(key, id, Buffer.from(t.birthEvidence.jpegBase64, "base64"), exhaustionNowMs);
|
|
119111
119176
|
}
|
|
119112
119177
|
const withBirthEvidence = /* @__PURE__ */ new Set();
|
|
119178
|
+
const sessionDetector = frameHandle ? sessionDetectorOf(frame, frameHandle.nodeId) : null;
|
|
119113
119179
|
const run = await this.confirmTrackBirths(bornCandidates.map(({ id, t }) => {
|
|
119114
119180
|
const evidenceCrop = this.birthEvidence.get(key, id, exhaustionNowMs);
|
|
119115
119181
|
if (evidenceCrop !== null) withBirthEvidence.add(id);
|
|
@@ -119125,7 +119191,9 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
119125
119191
|
source,
|
|
119126
119192
|
frameHandle,
|
|
119127
119193
|
frameWidth: result.frameWidth,
|
|
119128
|
-
frameHeight: result.frameHeight
|
|
119194
|
+
frameHeight: result.frameHeight,
|
|
119195
|
+
sessionDetector,
|
|
119196
|
+
attemptsFor: (trackId) => this.deferredBirths.attemptsFor(key, trackId)
|
|
119129
119197
|
}, exhaustedIds);
|
|
119130
119198
|
const outcome = run.outcome;
|
|
119131
119199
|
const gateNowMs = Date.now();
|
|
@@ -119180,6 +119248,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
119180
119248
|
matchedThisFrame: t.matchedThisFrame,
|
|
119181
119249
|
birthEvidenceAvailable: withBirthEvidence.has(id),
|
|
119182
119250
|
decision: run.decisions.get(id),
|
|
119251
|
+
sessionDetector,
|
|
119183
119252
|
decidedAtMs: gateNowMs,
|
|
119184
119253
|
firstSeen: this.trackStore?.peekActive(id)?.firstSeen ?? null
|
|
119185
119254
|
});
|
|
@@ -119949,74 +120018,30 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
119949
120018
|
return this.confirmationGateSettingsCache.get(deviceId, (id) => this.readDeviceSettings(id, resolveConfirmationGateSettings));
|
|
119950
120019
|
}
|
|
119951
120020
|
/**
|
|
119952
|
-
*
|
|
119953
|
-
*
|
|
119954
|
-
*
|
|
119955
|
-
*
|
|
119956
|
-
|
|
119957
|
-
|
|
119958
|
-
const api = this.ctx?.api;
|
|
119959
|
-
if (!api) return void 0;
|
|
119960
|
-
return api.pipelineExecutor;
|
|
119961
|
-
}
|
|
119962
|
-
/**
|
|
119963
|
-
* Resolve (and cache) the confirmation gate's re-detection step for a node:
|
|
119964
|
-
* the node's DEFAULT root object-detector (from `getGlobalSteps`) reduced to a
|
|
119965
|
-
* single CHILDLESS step, so the confirmation run does detection ONLY — no
|
|
119966
|
-
* crop/classifier subtree. Cached per node (TTL) since the node default rarely
|
|
119967
|
-
* changes. `null` ⇒ no detector available ⇒ the gate fails open.
|
|
120021
|
+
* Re-run object detection on a confirmation crop JPEG with the SESSION'S
|
|
120022
|
+
* detector (D925): the root model the birth's frame ran, on the device pool
|
|
120023
|
+
* it ran on, pinned to that frame's node — the node the crop is cut on, so
|
|
120024
|
+
* no new bytes cross anywhere. A session detector that cannot answer is
|
|
120025
|
+
* `session-device-unavailable` (no measurement, the birth defers); another
|
|
120026
|
+
* model is never asked. An inference failure is `null` (`redetect-error`).
|
|
119968
120027
|
*/
|
|
119969
|
-
async
|
|
119970
|
-
const
|
|
119971
|
-
|
|
119972
|
-
|
|
119973
|
-
|
|
119974
|
-
|
|
119975
|
-
|
|
119976
|
-
|
|
119977
|
-
|
|
119978
|
-
|
|
119979
|
-
|
|
119980
|
-
|
|
119981
|
-
|
|
119982
|
-
|
|
119983
|
-
|
|
119984
|
-
this.ctx.logger.debug("confirmation gate: getGlobalSteps failed", { meta: {
|
|
119985
|
-
nodeId,
|
|
119986
|
-
error: require_clip_model_registry.errMsg(err)
|
|
119987
|
-
} });
|
|
119988
|
-
}
|
|
119989
|
-
this.confirmationDetectorStepByNode.set(nodeId, {
|
|
119990
|
-
step,
|
|
119991
|
-
expiresAt: now + CONFIRMATION_DETECTOR_CACHE_TTL_MS
|
|
120028
|
+
async redetectCropForConfirmation(detector, deviceId, cropJpeg) {
|
|
120029
|
+
const outcome = await redetectWithSessionDetector(detector, cropJpeg, deviceId, (request, nodeId) => this.ctx.api.pipelineExecutor.runPipeline.mutate({
|
|
120030
|
+
...request,
|
|
120031
|
+
steps: [...request.steps]
|
|
120032
|
+
}, require_clip_model_registry.nodePin(nodeId)));
|
|
120033
|
+
if (outcome.error !== void 0) this.ctx.logger.warn("confirmation gate: re-detection failed — birth deferred", {
|
|
120034
|
+
tags: { deviceId },
|
|
120035
|
+
meta: {
|
|
120036
|
+
error: outcome.error,
|
|
120037
|
+
...detector !== null ? {
|
|
120038
|
+
modelId: detector.modelId,
|
|
120039
|
+
deviceKey: detector.deviceKey,
|
|
120040
|
+
node: detector.nodeId
|
|
120041
|
+
} : {}
|
|
120042
|
+
}
|
|
119992
120043
|
});
|
|
119993
|
-
return
|
|
119994
|
-
}
|
|
119995
|
-
/**
|
|
119996
|
-
* Re-run object detection on a confirmation crop JPEG via the frame-owning
|
|
119997
|
-
* node's `pipelineExecutor` (pinned by `nodeId`, matching the native-crop
|
|
119998
|
-
* fetch). Returns the crop's detections, or `null` on any unavailability /
|
|
119999
|
-
* error so the gate fails open.
|
|
120000
|
-
*/
|
|
120001
|
-
async redetectCropForConfirmation(nodeId, deviceId, cropJpeg) {
|
|
120002
|
-
const step = await this.resolveConfirmationDetectorStep(nodeId);
|
|
120003
|
-
if (!step) return null;
|
|
120004
|
-
const executor = this.pipelineExecutorApi();
|
|
120005
|
-
if (!executor?.runPipeline) return null;
|
|
120006
|
-
try {
|
|
120007
|
-
return toConfirmationDetections(await executor.runPipeline.mutate({
|
|
120008
|
-
steps: [step],
|
|
120009
|
-
image: new Uint8Array(cropJpeg),
|
|
120010
|
-
deviceId,
|
|
120011
|
-
plane: "frame"
|
|
120012
|
-
}, require_clip_model_registry.nodePin(nodeId)));
|
|
120013
|
-
} catch (err) {
|
|
120014
|
-
this.ctx.logger.debug("confirmation gate: re-detection failed — fail-open", {
|
|
120015
|
-
tags: { deviceId },
|
|
120016
|
-
meta: { error: require_clip_model_registry.errMsg(err) }
|
|
120017
|
-
});
|
|
120018
|
-
return null;
|
|
120019
|
-
}
|
|
120044
|
+
return outcome.answer;
|
|
120020
120045
|
}
|
|
120021
120046
|
/**
|
|
120022
120047
|
* Confirm a batch of track-birth candidates before they are created. Returns
|
|
@@ -120071,6 +120096,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
120071
120096
|
bestScore: decision?.bestScore ?? null,
|
|
120072
120097
|
appliedMinConfidence: decision?.appliedMinConfidence ?? null,
|
|
120073
120098
|
cropSource: decision?.cropSource ?? null,
|
|
120099
|
+
detector: decision !== void 0 && (decision.cropSource !== void 0 || decision.reason === "session-device-unavailable") ? input.sessionDetector ?? null : null,
|
|
120074
120100
|
decidedAtMs: input.decidedAtMs,
|
|
120075
120101
|
firstSeen: input.firstSeen,
|
|
120076
120102
|
motionOnsetAtMs,
|
|
@@ -120108,7 +120134,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
120108
120134
|
});
|
|
120109
120135
|
return allConfirmed();
|
|
120110
120136
|
}
|
|
120111
|
-
const
|
|
120137
|
+
const { sessionDetector } = params;
|
|
120112
120138
|
const candidateNativeRecovery = /* @__PURE__ */ new Map();
|
|
120113
120139
|
for (const c of candidates) if (c.nativeRecovery !== void 0) candidateNativeRecovery.set(c.trackId, c.nativeRecovery);
|
|
120114
120140
|
return {
|
|
@@ -120135,7 +120161,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
120135
120161
|
h: candidate.bbox.h
|
|
120136
120162
|
}, frameWidth, frameHeight, CONFIRMATION_CROP_PADDING, candidate.trackId, CONFIRMATION_CROP_MAX_WIDTH);
|
|
120137
120163
|
},
|
|
120138
|
-
redetect: (cropJpeg) => this.redetectCropForConfirmation(
|
|
120164
|
+
redetect: (cropJpeg) => this.redetectCropForConfirmation(sessionDetector, deviceId, cropJpeg),
|
|
120139
120165
|
keepCrop: (candidate, cropJpeg) => {
|
|
120140
120166
|
offeredCrops.set(candidate.trackId, cropJpeg);
|
|
120141
120167
|
},
|
|
@@ -120160,6 +120186,12 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
120160
120186
|
reason: decision.reason,
|
|
120161
120187
|
className: decision.className,
|
|
120162
120188
|
...decision.bestScore !== void 0 ? { bestScore: decision.bestScore } : {},
|
|
120189
|
+
...sessionDetector !== null ? {
|
|
120190
|
+
modelId: sessionDetector.modelId,
|
|
120191
|
+
deviceKey: sessionDetector.deviceKey,
|
|
120192
|
+
node: sessionDetector.nodeId
|
|
120193
|
+
} : {},
|
|
120194
|
+
attempts: params.attemptsFor(decision.trackId),
|
|
120163
120195
|
...decision.bestIncompatibleClass !== void 0 ? {
|
|
120164
120196
|
bestIncompatibleClass: decision.bestIncompatibleClass,
|
|
120165
120197
|
bestIncompatibleScore: decision.bestIncompatibleScore
|