@camstack/addon-post-analysis 1.2.193 → 1.2.195
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-CJKdyCag.js → dist-C15zOWA2.js} +71 -40
- package/dist/{dist-CoI1xhsw.mjs → dist-DE64ld3c.mjs} +71 -40
- package/dist/embedding-encoder/index.js +1 -1
- package/dist/embedding-encoder/index.mjs +1 -1
- package/dist/pipeline-analytics/_stub.js +1 -1
- package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-BmbhUxPs.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-if_wK4QI.mjs} +3 -3
- package/dist/pipeline-analytics/{_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BK6J3Mhb.mjs → _virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-CJb6-kIP.mjs} +1 -1
- package/dist/pipeline-analytics/{hostInit-qRtMpIyP.mjs → hostInit-D-5Zg6MO.mjs} +3 -3
- package/dist/pipeline-analytics/index.js +218 -80
- package/dist/pipeline-analytics/index.mjs +218 -80
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +1 -1
|
@@ -36,7 +36,7 @@ async function r() {
|
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
"@camstack/types": {
|
|
39
|
-
version: "1.2.
|
|
39
|
+
version: "1.2.160",
|
|
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.80",
|
|
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.128",
|
|
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-C15zOWA2.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");
|
|
@@ -35241,6 +35241,7 @@ var FrameProcessor = class {
|
|
|
35241
35241
|
const plateByBbox = /* @__PURE__ */ new Map();
|
|
35242
35242
|
const maskByBbox = /* @__PURE__ */ new Map();
|
|
35243
35243
|
const nativeRecoveryByBbox = /* @__PURE__ */ new Map();
|
|
35244
|
+
const birthEvidenceByBbox = /* @__PURE__ */ new Map();
|
|
35244
35245
|
const flatDetections = frame.detections.filter((d) => d.kind === "first-level").map((det) => {
|
|
35245
35246
|
const bbox = {
|
|
35246
35247
|
x: det.bbox.x,
|
|
@@ -35256,6 +35257,7 @@ var FrameProcessor = class {
|
|
|
35256
35257
|
...det.nativeRecovery !== void 0 ? { nativeRecovery: det.nativeRecovery } : {}
|
|
35257
35258
|
};
|
|
35258
35259
|
if (det.nativeRecovery !== void 0) nativeRecoveryByBbox.set(bbox, det.nativeRecovery);
|
|
35260
|
+
if (det.birthEvidence !== void 0) birthEvidenceByBbox.set(bbox, det.birthEvidence);
|
|
35259
35261
|
if (det.labels.length > 0) labelsByBbox.set(bbox, det.labels);
|
|
35260
35262
|
if (det.debug?.originalClassTier !== void 0) originalClassTierByBbox.set(bbox, det.debug.originalClassTier);
|
|
35261
35263
|
if (det.embedding !== void 0) embeddingByBbox.set(bbox, {
|
|
@@ -35481,6 +35483,7 @@ var FrameProcessor = class {
|
|
|
35481
35483
|
const plate = plateByBbox.get(td.bbox);
|
|
35482
35484
|
const sourceDetectionId = sourceIdByBbox.get(td.bbox);
|
|
35483
35485
|
const nativeRecovery = td.matchedThisFrame !== false ? nativeRecoveryByBbox.get(td.bbox) : void 0;
|
|
35486
|
+
const birthEvidence = td.matchedThisFrame !== false ? birthEvidenceByBbox.get(td.bbox) : void 0;
|
|
35484
35487
|
return {
|
|
35485
35488
|
trackId: td.trackId,
|
|
35486
35489
|
...sourceDetectionId !== void 0 ? { sourceDetectionId } : {},
|
|
@@ -35504,7 +35507,8 @@ var FrameProcessor = class {
|
|
|
35504
35507
|
plateScore: plate.score,
|
|
35505
35508
|
plateBbox: plate.bbox
|
|
35506
35509
|
} : {},
|
|
35507
|
-
...nativeRecovery !== void 0 ? { nativeRecovery } : {}
|
|
35510
|
+
...nativeRecovery !== void 0 ? { nativeRecovery } : {},
|
|
35511
|
+
...birthEvidence !== void 0 ? { birthEvidence } : {}
|
|
35508
35512
|
};
|
|
35509
35513
|
});
|
|
35510
35514
|
this.lastLabelWriteRefusals = refusals;
|
|
@@ -45355,9 +45359,28 @@ function withTimeout$2(promise, timeoutMs) {
|
|
|
45355
45359
|
});
|
|
45356
45360
|
}
|
|
45357
45361
|
async function runConfirmation(candidate, config, deps, exhausted) {
|
|
45362
|
+
const carried = candidate.evidenceCrop ?? null;
|
|
45363
|
+
if (carried) {
|
|
45364
|
+
const verdict = await measure(candidate, carried, config, deps, "carried");
|
|
45365
|
+
if (verdict.verdict === "confirmed" || verdict.reason === "redetect-error") return verdict;
|
|
45366
|
+
}
|
|
45358
45367
|
let crop = await deps.fetchCrop(candidate);
|
|
45359
|
-
|
|
45368
|
+
let cropSource = "native";
|
|
45369
|
+
if (!crop && exhausted && deps.fetchFallbackCrop) {
|
|
45370
|
+
crop = await deps.fetchFallbackCrop(candidate);
|
|
45371
|
+
cropSource = "fallback";
|
|
45372
|
+
}
|
|
45360
45373
|
if (!crop) return undecided(candidate, "no-crop");
|
|
45374
|
+
return measure(candidate, crop, config, deps, cropSource);
|
|
45375
|
+
}
|
|
45376
|
+
/**
|
|
45377
|
+
* Re-detect on ONE crop and turn the result into a verdict.
|
|
45378
|
+
*
|
|
45379
|
+
* Shared by all three sources so a crop can never be judged by two slightly
|
|
45380
|
+
* different rules depending on where it came from — the `cropSource` argument
|
|
45381
|
+
* is the ONLY thing that varies, and it varies in exactly one place below.
|
|
45382
|
+
*/
|
|
45383
|
+
async function measure(candidate, crop, config, deps, cropSource) {
|
|
45361
45384
|
const detections = await deps.redetect(crop);
|
|
45362
45385
|
if (detections === null) return undecided(candidate, "redetect-error");
|
|
45363
45386
|
let best;
|
|
@@ -45367,6 +45390,7 @@ async function runConfirmation(candidate, config, deps, exhausted) {
|
|
|
45367
45390
|
} else if (!bestIncompatible || d.score > bestIncompatible.score) bestIncompatible = d;
|
|
45368
45391
|
const bar = barFor(candidate, config, deps);
|
|
45369
45392
|
const confirmed = best !== void 0 && best.score >= bar;
|
|
45393
|
+
if (!confirmed && cropSource !== "native") return undecided(candidate, cropSource === "fallback" ? "fallback-inconclusive" : "carried-inconclusive");
|
|
45370
45394
|
const secondary = bestIncompatible ? promoteSecondary(candidate, bestIncompatible, bar, deps) : null;
|
|
45371
45395
|
return {
|
|
45372
45396
|
trackId: candidate.trackId,
|
|
@@ -45374,6 +45398,7 @@ async function runConfirmation(candidate, config, deps, exhausted) {
|
|
|
45374
45398
|
reason: confirmed ? "confirmed" : "suppressed",
|
|
45375
45399
|
className: candidate.className,
|
|
45376
45400
|
appliedMinConfidence: bar,
|
|
45401
|
+
cropSource,
|
|
45377
45402
|
...best ? { bestScore: best.score } : {},
|
|
45378
45403
|
...bestIncompatible ? {
|
|
45379
45404
|
bestIncompatibleClass: bestIncompatible.macroClass,
|
|
@@ -51886,6 +51911,97 @@ async function normalizePhotoOrientation(photo) {
|
|
|
51886
51911
|
if (orientation === void 0 || orientation === EXIF_UPRIGHT) return photo;
|
|
51887
51912
|
return (0, sharp.default)(photo).rotate().jpeg({ quality: 95 }).toBuffer();
|
|
51888
51913
|
}
|
|
51914
|
+
/**
|
|
51915
|
+
* How long one birth's evidence is kept. Twice `confirmationGateMaxDeferralMs`
|
|
51916
|
+
* (2 000 ms default) — the longest a deferred birth can still be re-offered.
|
|
51917
|
+
*/
|
|
51918
|
+
var BIRTH_EVIDENCE_TTL_MS = 4e3;
|
|
51919
|
+
var BirthEvidenceStore = class {
|
|
51920
|
+
slotsPerCamera;
|
|
51921
|
+
ttlMs;
|
|
51922
|
+
byDevice = /* @__PURE__ */ new Map();
|
|
51923
|
+
constructor(slotsPerCamera = 8, ttlMs = BIRTH_EVIDENCE_TTL_MS) {
|
|
51924
|
+
this.slotsPerCamera = slotsPerCamera;
|
|
51925
|
+
this.ttlMs = ttlMs;
|
|
51926
|
+
}
|
|
51927
|
+
/**
|
|
51928
|
+
* Keep this birth's crop.
|
|
51929
|
+
*
|
|
51930
|
+
* The FIRST crop for an id wins. A later frame's crop of the same track is a
|
|
51931
|
+
* different instant, and this store exists precisely to preserve the instant
|
|
51932
|
+
* the birth was measured on — overwriting it would quietly reintroduce the
|
|
51933
|
+
* defect the fallback asymmetry exists to distrust.
|
|
51934
|
+
*/
|
|
51935
|
+
remember(deviceKey, trackId, crop, nowMs) {
|
|
51936
|
+
let slots = this.byDevice.get(deviceKey);
|
|
51937
|
+
if (!slots) {
|
|
51938
|
+
slots = /* @__PURE__ */ new Map();
|
|
51939
|
+
this.byDevice.set(deviceKey, slots);
|
|
51940
|
+
}
|
|
51941
|
+
if (slots.has(trackId)) return;
|
|
51942
|
+
slots.set(trackId, {
|
|
51943
|
+
crop,
|
|
51944
|
+
atMs: nowMs
|
|
51945
|
+
});
|
|
51946
|
+
this.evict(deviceKey, slots, nowMs);
|
|
51947
|
+
}
|
|
51948
|
+
/** This birth's crop, or `null` when it was never kept or has aged out. */
|
|
51949
|
+
get(deviceKey, trackId, nowMs) {
|
|
51950
|
+
const entry = this.byDevice.get(deviceKey)?.get(trackId);
|
|
51951
|
+
if (!entry) return null;
|
|
51952
|
+
if (nowMs - entry.atMs > this.ttlMs) {
|
|
51953
|
+
this.resolve(deviceKey, trackId);
|
|
51954
|
+
return null;
|
|
51955
|
+
}
|
|
51956
|
+
return entry.crop;
|
|
51957
|
+
}
|
|
51958
|
+
/** A verdict finally arrived — the crop is dead weight from here. */
|
|
51959
|
+
resolve(deviceKey, trackId) {
|
|
51960
|
+
const slots = this.byDevice.get(deviceKey);
|
|
51961
|
+
if (!slots) return;
|
|
51962
|
+
slots.delete(trackId);
|
|
51963
|
+
if (slots.size === 0) this.byDevice.delete(deviceKey);
|
|
51964
|
+
}
|
|
51965
|
+
/**
|
|
51966
|
+
* Forget every id the tracker is no longer carrying — the same per-frame
|
|
51967
|
+
* contract as `DeferredBirthRegistry.retain`. An id the tracker dropped can
|
|
51968
|
+
* never be decided, so holding its pixels only leaks.
|
|
51969
|
+
*/
|
|
51970
|
+
retain(deviceKey, currentTrackIds) {
|
|
51971
|
+
const slots = this.byDevice.get(deviceKey);
|
|
51972
|
+
if (!slots) return;
|
|
51973
|
+
for (const id of [...slots.keys()]) if (!currentTrackIds.has(id)) slots.delete(id);
|
|
51974
|
+
if (slots.size === 0) this.byDevice.delete(deviceKey);
|
|
51975
|
+
}
|
|
51976
|
+
/** Crops held for one camera (diagnostics and tests). */
|
|
51977
|
+
size(deviceKey) {
|
|
51978
|
+
return this.byDevice.get(deviceKey)?.size ?? 0;
|
|
51979
|
+
}
|
|
51980
|
+
/** Bytes held across every camera — the declared budget, checkable. */
|
|
51981
|
+
totalBytes() {
|
|
51982
|
+
let total = 0;
|
|
51983
|
+
for (const slots of this.byDevice.values()) for (const entry of slots.values()) total += entry.crop.byteLength;
|
|
51984
|
+
return total;
|
|
51985
|
+
}
|
|
51986
|
+
/** Drop a camera's reserve wholesale (device removed / pipeline reset). */
|
|
51987
|
+
clearDevice(deviceKey) {
|
|
51988
|
+
this.byDevice.delete(deviceKey);
|
|
51989
|
+
}
|
|
51990
|
+
/**
|
|
51991
|
+
* Age first, then the quota — and only ever inside THIS camera's slots.
|
|
51992
|
+
* `Map` keeps insertion order and a crop is inserted once, so the first key
|
|
51993
|
+
* is always the oldest.
|
|
51994
|
+
*/
|
|
51995
|
+
evict(deviceKey, slots, nowMs) {
|
|
51996
|
+
for (const [id, entry] of [...slots]) if (nowMs - entry.atMs > this.ttlMs) slots.delete(id);
|
|
51997
|
+
while (slots.size > this.slotsPerCamera) {
|
|
51998
|
+
const oldest = slots.keys().next().value;
|
|
51999
|
+
if (oldest === void 0) break;
|
|
52000
|
+
slots.delete(oldest);
|
|
52001
|
+
}
|
|
52002
|
+
if (slots.size === 0) this.byDevice.delete(deviceKey);
|
|
52003
|
+
}
|
|
52004
|
+
};
|
|
51889
52005
|
//#endregion
|
|
51890
52006
|
//#region src/pipeline-analytics/pipeline/deferred-births.ts
|
|
51891
52007
|
var DeferredBirthRegistry = class {
|
|
@@ -54042,6 +54158,77 @@ function personOverVehicle(person, neighbours, threshold = CONTAINMENT_THRESHOLD
|
|
|
54042
54158
|
return best >= threshold ? best : null;
|
|
54043
54159
|
}
|
|
54044
54160
|
//#endregion
|
|
54161
|
+
//#region src/pipeline-analytics/pipeline/started-births.ts
|
|
54162
|
+
/**
|
|
54163
|
+
* Memory of births whose ritual has already RUN, per device+source.
|
|
54164
|
+
*
|
|
54165
|
+
* A birth is a decision, and a decision is taken once. Until 2026-09-07 it
|
|
54166
|
+
* could be taken twice, on camera 615 it routinely was, and the second vote
|
|
54167
|
+
* won:
|
|
54168
|
+
*
|
|
54169
|
+
* 04:59:38.335Z confirmation gate: birth confirmed {trackId=f585b2ee…
|
|
54170
|
+
* className=animal bestScore=0.7068}
|
|
54171
|
+
* 04:59:38.335Z track started {trackId=f585b2ee…}
|
|
54172
|
+
* 04:59:38.821Z confirmation gate: birth suppressed (false positive)
|
|
54173
|
+
* {trackId=f585b2ee… className=animal} ← no bestScore:
|
|
54174
|
+
* the second crop held no compatible detection AT ALL
|
|
54175
|
+
* 04:59:38.821Z birth suppressed — track record retracted
|
|
54176
|
+
*
|
|
54177
|
+
* TWO conditions have to meet, and both are structural:
|
|
54178
|
+
*
|
|
54179
|
+
* 1. `processFrame` reads `lastActiveTrackIds` at the top and writes it at the
|
|
54180
|
+
* bottom, and AWAITS the confirmation gate in between (a crop round trip to
|
|
54181
|
+
* the frame's node plus a re-detection: 130–490 ms measured on this camera,
|
|
54182
|
+
* against 100 ms frame spacing). Several frames are therefore in flight at
|
|
54183
|
+
* once and each of them sees the same fresh id as unjudged.
|
|
54184
|
+
* 2. The other birth discriminator, `positionsCount > 1`, does not close the
|
|
54185
|
+
* gap either: a COASTED frame deliberately appends no position
|
|
54186
|
+
* (`TrackStore.upsert`, `matched: false`), so a track the full-frame pass
|
|
54187
|
+
* cannot see — which is the entire premise of the small-subject recovery —
|
|
54188
|
+
* keeps exactly one position for as long as it coasts, and
|
|
54189
|
+
* `classifyTrackAppearance` keeps answering `birth`.
|
|
54190
|
+
*
|
|
54191
|
+
* So the id that has already been born is remembered HERE, and both halves of
|
|
54192
|
+
* the birth path consult it: it is not offered to the gate again, and a verdict
|
|
54193
|
+
* that arrives for it anyway cannot retract it. Same lifetime discipline as
|
|
54194
|
+
* {@link SuppressedBirthRegistry} — held while the tracker still carries the
|
|
54195
|
+
* id, forgotten the frame it stops.
|
|
54196
|
+
*/
|
|
54197
|
+
var StartedBirthRegistry = class {
|
|
54198
|
+
byDevice = /* @__PURE__ */ new Map();
|
|
54199
|
+
/** Record that this id's birth ritual ran — `start`, firstFrame, the lot. */
|
|
54200
|
+
markStarted(deviceKey, trackId) {
|
|
54201
|
+
let ids = this.byDevice.get(deviceKey);
|
|
54202
|
+
if (!ids) {
|
|
54203
|
+
ids = /* @__PURE__ */ new Set();
|
|
54204
|
+
this.byDevice.set(deviceKey, ids);
|
|
54205
|
+
}
|
|
54206
|
+
ids.add(trackId);
|
|
54207
|
+
}
|
|
54208
|
+
hasStarted(deviceKey, trackId) {
|
|
54209
|
+
return this.byDevice.get(deviceKey)?.has(trackId) === true;
|
|
54210
|
+
}
|
|
54211
|
+
/**
|
|
54212
|
+
* Forget every started id the tracker is no longer carrying. Called once per
|
|
54213
|
+
* frame with the ids present THIS frame — an id the tracker has dropped can
|
|
54214
|
+
* never be re-offered as a birth, so holding it serves nothing.
|
|
54215
|
+
*/
|
|
54216
|
+
retain(deviceKey, currentTrackIds) {
|
|
54217
|
+
const ids = this.byDevice.get(deviceKey);
|
|
54218
|
+
if (!ids) return;
|
|
54219
|
+
for (const id of ids) if (!currentTrackIds.has(id)) ids.delete(id);
|
|
54220
|
+
if (ids.size === 0) this.byDevice.delete(deviceKey);
|
|
54221
|
+
}
|
|
54222
|
+
/** Started ids currently held for a device — diagnostics and tests. */
|
|
54223
|
+
size(deviceKey) {
|
|
54224
|
+
return this.byDevice.get(deviceKey)?.size ?? 0;
|
|
54225
|
+
}
|
|
54226
|
+
/** Drop a device's memory wholesale (device removed / pipeline reset). */
|
|
54227
|
+
clearDevice(deviceKey) {
|
|
54228
|
+
this.byDevice.delete(deviceKey);
|
|
54229
|
+
}
|
|
54230
|
+
};
|
|
54231
|
+
//#endregion
|
|
54045
54232
|
//#region src/pipeline-analytics/pipeline/stationary/stationary-evidence.ts
|
|
54046
54233
|
/**
|
|
54047
54234
|
* stationary-evidence — how a parked object EARNS a registry entry.
|
|
@@ -55314,77 +55501,6 @@ function rowToEntry(id, data) {
|
|
|
55314
55501
|
};
|
|
55315
55502
|
}
|
|
55316
55503
|
//#endregion
|
|
55317
|
-
//#region src/pipeline-analytics/pipeline/started-births.ts
|
|
55318
|
-
/**
|
|
55319
|
-
* Memory of births whose ritual has already RUN, per device+source.
|
|
55320
|
-
*
|
|
55321
|
-
* A birth is a decision, and a decision is taken once. Until 2026-09-07 it
|
|
55322
|
-
* could be taken twice, on camera 615 it routinely was, and the second vote
|
|
55323
|
-
* won:
|
|
55324
|
-
*
|
|
55325
|
-
* 04:59:38.335Z confirmation gate: birth confirmed {trackId=f585b2ee…
|
|
55326
|
-
* className=animal bestScore=0.7068}
|
|
55327
|
-
* 04:59:38.335Z track started {trackId=f585b2ee…}
|
|
55328
|
-
* 04:59:38.821Z confirmation gate: birth suppressed (false positive)
|
|
55329
|
-
* {trackId=f585b2ee… className=animal} ← no bestScore:
|
|
55330
|
-
* the second crop held no compatible detection AT ALL
|
|
55331
|
-
* 04:59:38.821Z birth suppressed — track record retracted
|
|
55332
|
-
*
|
|
55333
|
-
* TWO conditions have to meet, and both are structural:
|
|
55334
|
-
*
|
|
55335
|
-
* 1. `processFrame` reads `lastActiveTrackIds` at the top and writes it at the
|
|
55336
|
-
* bottom, and AWAITS the confirmation gate in between (a crop round trip to
|
|
55337
|
-
* the frame's node plus a re-detection: 130–490 ms measured on this camera,
|
|
55338
|
-
* against 100 ms frame spacing). Several frames are therefore in flight at
|
|
55339
|
-
* once and each of them sees the same fresh id as unjudged.
|
|
55340
|
-
* 2. The other birth discriminator, `positionsCount > 1`, does not close the
|
|
55341
|
-
* gap either: a COASTED frame deliberately appends no position
|
|
55342
|
-
* (`TrackStore.upsert`, `matched: false`), so a track the full-frame pass
|
|
55343
|
-
* cannot see — which is the entire premise of the small-subject recovery —
|
|
55344
|
-
* keeps exactly one position for as long as it coasts, and
|
|
55345
|
-
* `classifyTrackAppearance` keeps answering `birth`.
|
|
55346
|
-
*
|
|
55347
|
-
* So the id that has already been born is remembered HERE, and both halves of
|
|
55348
|
-
* the birth path consult it: it is not offered to the gate again, and a verdict
|
|
55349
|
-
* that arrives for it anyway cannot retract it. Same lifetime discipline as
|
|
55350
|
-
* {@link SuppressedBirthRegistry} — held while the tracker still carries the
|
|
55351
|
-
* id, forgotten the frame it stops.
|
|
55352
|
-
*/
|
|
55353
|
-
var StartedBirthRegistry = class {
|
|
55354
|
-
byDevice = /* @__PURE__ */ new Map();
|
|
55355
|
-
/** Record that this id's birth ritual ran — `start`, firstFrame, the lot. */
|
|
55356
|
-
markStarted(deviceKey, trackId) {
|
|
55357
|
-
let ids = this.byDevice.get(deviceKey);
|
|
55358
|
-
if (!ids) {
|
|
55359
|
-
ids = /* @__PURE__ */ new Set();
|
|
55360
|
-
this.byDevice.set(deviceKey, ids);
|
|
55361
|
-
}
|
|
55362
|
-
ids.add(trackId);
|
|
55363
|
-
}
|
|
55364
|
-
hasStarted(deviceKey, trackId) {
|
|
55365
|
-
return this.byDevice.get(deviceKey)?.has(trackId) === true;
|
|
55366
|
-
}
|
|
55367
|
-
/**
|
|
55368
|
-
* Forget every started id the tracker is no longer carrying. Called once per
|
|
55369
|
-
* frame with the ids present THIS frame — an id the tracker has dropped can
|
|
55370
|
-
* never be re-offered as a birth, so holding it serves nothing.
|
|
55371
|
-
*/
|
|
55372
|
-
retain(deviceKey, currentTrackIds) {
|
|
55373
|
-
const ids = this.byDevice.get(deviceKey);
|
|
55374
|
-
if (!ids) return;
|
|
55375
|
-
for (const id of ids) if (!currentTrackIds.has(id)) ids.delete(id);
|
|
55376
|
-
if (ids.size === 0) this.byDevice.delete(deviceKey);
|
|
55377
|
-
}
|
|
55378
|
-
/** Started ids currently held for a device — diagnostics and tests. */
|
|
55379
|
-
size(deviceKey) {
|
|
55380
|
-
return this.byDevice.get(deviceKey)?.size ?? 0;
|
|
55381
|
-
}
|
|
55382
|
-
/** Drop a device's memory wholesale (device removed / pipeline reset). */
|
|
55383
|
-
clearDevice(deviceKey) {
|
|
55384
|
-
this.byDevice.delete(deviceKey);
|
|
55385
|
-
}
|
|
55386
|
-
};
|
|
55387
|
-
//#endregion
|
|
55388
55504
|
//#region src/pipeline-analytics/pipeline/suppressed-births.ts
|
|
55389
55505
|
/**
|
|
55390
55506
|
* Memory of births the confirmation gate rejected, per device.
|
|
@@ -67750,6 +67866,17 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_dist.B
|
|
|
67750
67866
|
/** Births the gate could not MEASURE, awaiting another look on a later frame. */
|
|
67751
67867
|
deferredBirths = new DeferredBirthRegistry();
|
|
67752
67868
|
/**
|
|
67869
|
+
* The pixels each deferred birth arrived with — a RESERVE per camera, evicted
|
|
67870
|
+
* by age inside that camera's own quota (D379).
|
|
67871
|
+
*
|
|
67872
|
+
* Not a shared cap. The path this replaces was one node-wide 4 096-entry LRU
|
|
67873
|
+
* measured pinned full in 6 814 of 6 849 samples over three hours, in which a
|
|
67874
|
+
* busy camera evicted a quiet one's proof and every camera added shortened
|
|
67875
|
+
* every other camera's window. See `pipeline/birth-evidence-store.ts` for the
|
|
67876
|
+
* two measurements the slot count and the TTL are taken from.
|
|
67877
|
+
*/
|
|
67878
|
+
birthEvidence = new BirthEvidenceStore();
|
|
67879
|
+
/**
|
|
67753
67880
|
* Subjects the confirmation gate found in a birth's crop BESIDES the birth
|
|
67754
67881
|
* itself (a dog in a person's crop), waiting to ride the next frame of the
|
|
67755
67882
|
* same (device, source) as detections — `pipeline/secondary-subjects.ts`.
|
|
@@ -71003,12 +71130,20 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_dist.B
|
|
|
71003
71130
|
const exhaustionNowMs = Date.now();
|
|
71004
71131
|
const exhaustedIds = /* @__PURE__ */ new Set();
|
|
71005
71132
|
for (const { id } of bornCandidates) if (this.deferredBirths.exhausted(key, id, exhaustionNowMs, gateSettings.maxAttempts, gateSettings.maxDeferralMs)) exhaustedIds.add(id);
|
|
71006
|
-
const
|
|
71007
|
-
|
|
71008
|
-
|
|
71009
|
-
|
|
71010
|
-
|
|
71011
|
-
|
|
71133
|
+
for (const { id, t } of bornCandidates) {
|
|
71134
|
+
if (t.birthEvidence === void 0) continue;
|
|
71135
|
+
this.birthEvidence.remember(key, id, Buffer.from(t.birthEvidence.jpegBase64, "base64"), exhaustionNowMs);
|
|
71136
|
+
}
|
|
71137
|
+
const outcome = await this.confirmTrackBirths(bornCandidates.map(({ id, t }) => {
|
|
71138
|
+
const evidenceCrop = this.birthEvidence.get(key, id, exhaustionNowMs);
|
|
71139
|
+
return {
|
|
71140
|
+
trackId: id,
|
|
71141
|
+
className: t.className,
|
|
71142
|
+
bbox: t.bbox,
|
|
71143
|
+
...t.nativeRecovery !== void 0 ? { nativeRecovery: t.nativeRecovery } : {},
|
|
71144
|
+
...evidenceCrop !== null ? { evidenceCrop } : {}
|
|
71145
|
+
};
|
|
71146
|
+
}), {
|
|
71012
71147
|
deviceId,
|
|
71013
71148
|
source,
|
|
71014
71149
|
frameHandle,
|
|
@@ -71032,6 +71167,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_dist.B
|
|
|
71032
71167
|
const deferredForMs = this.deferredBirths.elapsedMs(key, id, gateNowMs);
|
|
71033
71168
|
const deferredAttempts = this.deferredBirths.attemptsFor(key, id);
|
|
71034
71169
|
this.deferredBirths.resolve(key, id);
|
|
71170
|
+
this.birthEvidence.resolve(key, id);
|
|
71035
71171
|
if (this.startedBirths.hasStarted(key, id)) {
|
|
71036
71172
|
this.deferredBirths.resolve(key, id);
|
|
71037
71173
|
log.info("late birth verdict ignored — the track was already born", { meta: {
|
|
@@ -71149,6 +71285,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_dist.B
|
|
|
71149
71285
|
this.suppressedBirths.retain(key, currentTrackIds);
|
|
71150
71286
|
this.startedBirths.retain(key, currentTrackIds);
|
|
71151
71287
|
this.deferredBirths.retain(key, currentTrackIds);
|
|
71288
|
+
this.birthEvidence.retain(key, currentTrackIds);
|
|
71152
71289
|
this.lastActiveTrackIds.set(key, currentTrackIds);
|
|
71153
71290
|
if (currentTrackIds.size > 0) this.lastTrackActivityMs.set(deviceId, Date.now());
|
|
71154
71291
|
const stationarySettings = this.stationarySettingsFromCache(deviceId);
|
|
@@ -71778,6 +71915,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_dist.B
|
|
|
71778
71915
|
bestIncompatibleScore: decision.bestIncompatibleScore
|
|
71779
71916
|
} : {},
|
|
71780
71917
|
minConfidence: config.minConfidence,
|
|
71918
|
+
...decision.cropSource !== void 0 ? { cropSource: decision.cropSource } : {},
|
|
71781
71919
|
...decision.reason === "native-pass" ? {
|
|
71782
71920
|
nativeRecoveryCropSidePx: candidateNativeRecovery.get(decision.trackId)?.cropSidePx,
|
|
71783
71921
|
nativeRecoveryViewPx: candidateNativeRecovery.get(decision.trackId)?.viewPx
|