@camstack/addon-post-analysis 1.2.652 → 1.2.654
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/CHANGELOG.md +13 -0
- package/dist/{clip-model-registry-BrazZJvr.mjs → clip-model-registry-BX6j2lnF.mjs} +997 -147
- package/dist/{clip-model-registry-Bz1uQvQ8.js → clip-model-registry-CFQBxtE2.js} +997 -147
- 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-D6DnF6Vk.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-Vag6rhEh.mjs} +2 -2
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BUwWKfHC.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-DXQUFp7P.mjs +26 -0
- package/dist/pipeline-analytics/{hostInit-DtrcY1yz.mjs → hostInit-CnvnZsmk.mjs} +2 -2
- package/dist/pipeline-analytics/index.js +293 -15
- package/dist/pipeline-analytics/index.mjs +293 -15
- 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-BKMr4IqL.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-CtNyIYsM.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-CFQBxtE2.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");
|
|
@@ -9063,6 +9063,7 @@ var en_default = {
|
|
|
9063
9063
|
"system.node-offline.body.agent": "Agent {{nodeName}} is offline",
|
|
9064
9064
|
"system.node-offline.body.agent.connection-lost": "Agent {{nodeName}} lost its connection to the hub",
|
|
9065
9065
|
"system.node-offline.body.agent.shutdown": "Agent {{nodeName}} shut down",
|
|
9066
|
+
"system.node-offline.body.agent.updating": "Agent {{nodeName}} went offline while updating and has not come back after {{graceMin}} minutes",
|
|
9066
9067
|
"system.node-inference-unavailable.title": "Node cannot infer — {{nodeId}}",
|
|
9067
9068
|
"system.node-inference-unavailable.body": "Node {{nodeId}} can no longer run inference — every enabled device is unavailable ({{devices}}). It will not receive cameras until one returns.",
|
|
9068
9069
|
"system.addon-crash-loop.title": "Addon crash-loop — {{nodeId}}",
|
|
@@ -9467,6 +9468,7 @@ var it_default = {
|
|
|
9467
9468
|
"system.node-offline.body.agent": "L'agent {{nodeName}} è offline",
|
|
9468
9469
|
"system.node-offline.body.agent.connection-lost": "L'agent {{nodeName}} ha perso la connessione con l'hub",
|
|
9469
9470
|
"system.node-offline.body.agent.shutdown": "L'agent {{nodeName}} si è spento",
|
|
9471
|
+
"system.node-offline.body.agent.updating": "L'agent {{nodeName}} è andato offline durante un aggiornamento e non è tornato dopo {{graceMin}} minuti",
|
|
9470
9472
|
"system.node-inference-unavailable.title": "Nodo senza inferenza — {{nodeId}}",
|
|
9471
9473
|
"system.node-inference-unavailable.body": "Il nodo {{nodeId}} non può più eseguire inferenza — tutti i dispositivi abilitati non sono disponibili ({{devices}}). Non riceverà camere finché uno non torna disponibile.",
|
|
9472
9474
|
"system.addon-crash-loop.title": "Crash-loop addon — {{nodeId}}",
|
|
@@ -54721,6 +54723,12 @@ var FrameState = class {
|
|
|
54721
54723
|
* per 5 minutes, not one per governor round (the wedge re-sights all
|
|
54722
54724
|
* night; ~300 identical lines would bury the log it exists to serve). */
|
|
54723
54725
|
packageOversizeLogAt = /* @__PURE__ */ new Map();
|
|
54726
|
+
/**
|
|
54727
|
+
* The newest frame the package path held per camera — the picture a parcel
|
|
54728
|
+
* promoted from a raw look is stored from (`package-still-capture.ts`). The
|
|
54729
|
+
* scene path concludes without a frame of its own, so it reads this.
|
|
54730
|
+
*/
|
|
54731
|
+
packageLookFrames = /* @__PURE__ */ new Map();
|
|
54724
54732
|
/** Reasons logged on the previous package look — episode helper for drops. */
|
|
54725
54733
|
packageLookDropReasons = /* @__PURE__ */ new Map();
|
|
54726
54734
|
};
|
|
@@ -59025,6 +59033,89 @@ function sweepOne(deps, deviceId) {
|
|
|
59025
59033
|
if (outcome.departed.length > 0 || outcome.departedWithoutActivity.length > 0 || outcome.expired.length > 0) deps.onOutcome(deviceId, outcome, deps.now);
|
|
59026
59034
|
}
|
|
59027
59035
|
//#endregion
|
|
59036
|
+
//#region src/pipeline-analytics/pipeline/package/package-still-capture.ts
|
|
59037
|
+
/** A held look frame older than this is not the parcel's picture any more. */
|
|
59038
|
+
var PACKAGE_LOOK_FRAME_MAX_AGE_MS = 15e3;
|
|
59039
|
+
async function jpegOf(reply) {
|
|
59040
|
+
if (reply.tier === "ram-fullframe") return "preview-only";
|
|
59041
|
+
if (reply.jpegBytes !== void 0 && reply.jpegBytes.byteLength > 0) return reply.jpegBytes;
|
|
59042
|
+
if (reply.bytes !== void 0 && reply.bytes.length === reply.width * reply.height * 3) return encodeRgbCropToJpeg(reply.bytes, reply.width, reply.height);
|
|
59043
|
+
return "empty-frame";
|
|
59044
|
+
}
|
|
59045
|
+
/**
|
|
59046
|
+
* The entry carrying its still's `keyFrameMediaId`, or the entry unchanged when
|
|
59047
|
+
* it already had one or none could be stored (said, with the reason).
|
|
59048
|
+
*/
|
|
59049
|
+
async function withParcelStill(input) {
|
|
59050
|
+
const { entry, logger } = input;
|
|
59051
|
+
if (entry.keyFrameMediaId !== void 0) return entry;
|
|
59052
|
+
const miss = (reason, detail) => {
|
|
59053
|
+
logger.warn("package still NOT stored — the delivery ships without a picture of the parcel", {
|
|
59054
|
+
tags: { deviceId: entry.deviceId },
|
|
59055
|
+
meta: {
|
|
59056
|
+
entryId: entry.id,
|
|
59057
|
+
reason,
|
|
59058
|
+
...detail !== void 0 ? { error: detail } : {}
|
|
59059
|
+
}
|
|
59060
|
+
});
|
|
59061
|
+
return entry;
|
|
59062
|
+
};
|
|
59063
|
+
if (input.handle === null) return miss("no-frame-handle");
|
|
59064
|
+
if (input.writer === null) return miss("no-media-store");
|
|
59065
|
+
try {
|
|
59066
|
+
const reply = await input.query({
|
|
59067
|
+
handle: input.handle,
|
|
59068
|
+
bbox: {
|
|
59069
|
+
x: 0,
|
|
59070
|
+
y: 0,
|
|
59071
|
+
w: entry.frameWidth,
|
|
59072
|
+
h: entry.frameHeight
|
|
59073
|
+
},
|
|
59074
|
+
acceptJpegBytes: true,
|
|
59075
|
+
encodeJpeg: true,
|
|
59076
|
+
pin: require_clip_model_registry.nodePin(input.handle.nodeId)
|
|
59077
|
+
});
|
|
59078
|
+
if (reply === null) return miss("native-miss");
|
|
59079
|
+
const jpeg = await jpegOf(reply);
|
|
59080
|
+
if (typeof jpeg === "string") return miss(jpeg);
|
|
59081
|
+
const keyFrameMediaId = await input.writer.putReplacing({
|
|
59082
|
+
deviceId: entry.deviceId,
|
|
59083
|
+
ownerKind: "track",
|
|
59084
|
+
ownerId: entry.id,
|
|
59085
|
+
kind: "keyFrame",
|
|
59086
|
+
timestamp: input.timestamp,
|
|
59087
|
+
data: Buffer.from(jpeg),
|
|
59088
|
+
subjectBox: {
|
|
59089
|
+
x: entry.bbox.x,
|
|
59090
|
+
y: entry.bbox.y,
|
|
59091
|
+
w: entry.bbox.w,
|
|
59092
|
+
h: entry.bbox.h,
|
|
59093
|
+
frameWidth: entry.frameWidth,
|
|
59094
|
+
frameHeight: entry.frameHeight
|
|
59095
|
+
}
|
|
59096
|
+
});
|
|
59097
|
+
return {
|
|
59098
|
+
...entry,
|
|
59099
|
+
keyFrameMediaId
|
|
59100
|
+
};
|
|
59101
|
+
} catch (err) {
|
|
59102
|
+
return miss("write-failed", require_clip_model_registry.errMsg(err));
|
|
59103
|
+
}
|
|
59104
|
+
}
|
|
59105
|
+
/**
|
|
59106
|
+
* One promotion, in the order that matters: the still is stored FIRST, then the
|
|
59107
|
+
* detector emits `delivered` — the notification centre reads the still when the
|
|
59108
|
+
* event arrives, so a picture written after it is a picture nobody sees.
|
|
59109
|
+
*/
|
|
59110
|
+
async function promoteWithStill(input) {
|
|
59111
|
+
const entry = await withParcelStill(input);
|
|
59112
|
+
await input.detector.onStationaryChange({
|
|
59113
|
+
phase: "appeared",
|
|
59114
|
+
entry,
|
|
59115
|
+
timestamp: input.entry.becameStationaryAt
|
|
59116
|
+
});
|
|
59117
|
+
}
|
|
59118
|
+
//#endregion
|
|
59028
59119
|
//#region src/pipeline-analytics/pipeline/person-over-vehicle.ts
|
|
59029
59120
|
/**
|
|
59030
59121
|
* How much of the PERSON box must sit inside a vehicle box to be counted.
|
|
@@ -70514,7 +70605,12 @@ Object.freeze({
|
|
|
70514
70605
|
"listSupportedEntityKinds"
|
|
70515
70606
|
],
|
|
70516
70607
|
"device-extension": ["listSlots", "listSources"],
|
|
70517
|
-
"device-provider": [
|
|
70608
|
+
"device-provider": [
|
|
70609
|
+
"classifyDiscoveryHits",
|
|
70610
|
+
"discoverDevices",
|
|
70611
|
+
"getDevices",
|
|
70612
|
+
"getDiscoveryModes"
|
|
70613
|
+
],
|
|
70518
70614
|
"device-removal-hook": ["listDeviceData"],
|
|
70519
70615
|
"failure-contribution": ["list"],
|
|
70520
70616
|
"llm": [
|
|
@@ -90273,13 +90369,17 @@ var DeviceLivenessHoldoff = class {
|
|
|
90273
90369
|
rememberIfAbsent(subject, state) {
|
|
90274
90370
|
if (!this.lastNotified.has(subject)) this.lastNotified.set(subject, state);
|
|
90275
90371
|
}
|
|
90276
|
-
/**
|
|
90277
|
-
|
|
90372
|
+
/**
|
|
90373
|
+
* A real ledger flip. Starts / resets the trailing timer. `delayMs` replaces
|
|
90374
|
+
* the default delay for THIS arm only (a node's planned-update grace).
|
|
90375
|
+
*/
|
|
90376
|
+
arm(subject, incoming, delayMs) {
|
|
90377
|
+
const delay = delayMs ?? this.delayMs;
|
|
90278
90378
|
this.pending.set(subject, incoming);
|
|
90279
90379
|
this.trackDeparture(subject, incoming);
|
|
90280
90380
|
const existing = this.timers.get(subject);
|
|
90281
90381
|
if (existing !== void 0) this.cancel(existing);
|
|
90282
|
-
if (
|
|
90382
|
+
if (delay <= 0) {
|
|
90283
90383
|
this.timers.delete(subject);
|
|
90284
90384
|
this.fire(subject);
|
|
90285
90385
|
return;
|
|
@@ -90287,7 +90387,7 @@ var DeviceLivenessHoldoff = class {
|
|
|
90287
90387
|
const id = this.schedule(() => {
|
|
90288
90388
|
this.timers.delete(subject);
|
|
90289
90389
|
this.fire(subject);
|
|
90290
|
-
},
|
|
90390
|
+
}, delay);
|
|
90291
90391
|
this.timers.set(subject, id);
|
|
90292
90392
|
}
|
|
90293
90393
|
dispose() {
|
|
@@ -92934,6 +93034,71 @@ var NcRuleStore = class NcRuleStore {
|
|
|
92934
93034
|
}
|
|
92935
93035
|
};
|
|
92936
93036
|
//#endregion
|
|
93037
|
+
//#region src/notification-center/planned-update-window.ts
|
|
93038
|
+
/**
|
|
93039
|
+
* A node that ANNOUNCED an update is expected to go offline — the window that
|
|
93040
|
+
* says so lives here.
|
|
93041
|
+
*
|
|
93042
|
+
* `system.restarting` becomes `node-updating` / `node-restarting`; the centre
|
|
93043
|
+
* records the announcement per node (RAM, refreshed by the event, never by a
|
|
93044
|
+
* read — D49). An offline for that node inside {@link PLANNED_UPDATE_OFFLINE_GRACE_MS}
|
|
93045
|
+
* of the announcement is held for the whole window instead of the usual 60 s
|
|
93046
|
+
* hold-off: back in time means no offline notification at all, not back means
|
|
93047
|
+
* one offline that says it happened during an update. A lost announcement
|
|
93048
|
+
* (events may be dropped, D8) simply behaves as before.
|
|
93049
|
+
*/
|
|
93050
|
+
/** How long after an announcement an offline is held, and how long the announcement counts. */
|
|
93051
|
+
var PLANNED_UPDATE_OFFLINE_GRACE_MS = 10 * 6e4;
|
|
93052
|
+
var NC_PLANNED_UPDATE_NODES_MAX = 256;
|
|
93053
|
+
var NcPlannedUpdateWindow = class {
|
|
93054
|
+
graceMs;
|
|
93055
|
+
/** Insertion-ordered: the oldest node is evicted first. */
|
|
93056
|
+
announcedAt = /* @__PURE__ */ new Map();
|
|
93057
|
+
/** When an offline was put on hold, per node. */
|
|
93058
|
+
heldAt = /* @__PURE__ */ new Map();
|
|
93059
|
+
constructor(graceMs = PLANNED_UPDATE_OFFLINE_GRACE_MS) {
|
|
93060
|
+
this.graceMs = graceMs;
|
|
93061
|
+
}
|
|
93062
|
+
get windowMs() {
|
|
93063
|
+
return this.graceMs;
|
|
93064
|
+
}
|
|
93065
|
+
get graceMinutes() {
|
|
93066
|
+
return Math.round(this.graceMs / 6e4);
|
|
93067
|
+
}
|
|
93068
|
+
/** Feed every system subject the intake accepted; only the two announcements are kept. */
|
|
93069
|
+
observe(system, atMs) {
|
|
93070
|
+
if (system.kind !== "node-updating" && system.kind !== "node-restarting") return;
|
|
93071
|
+
const nodeId = system.nodeId;
|
|
93072
|
+
if (nodeId === void 0) return;
|
|
93073
|
+
this.announcedAt.delete(nodeId);
|
|
93074
|
+
this.announcedAt.set(nodeId, atMs);
|
|
93075
|
+
while (this.announcedAt.size > NC_PLANNED_UPDATE_NODES_MAX) {
|
|
93076
|
+
const oldest = this.announcedAt.keys().next();
|
|
93077
|
+
if (oldest.done === true) break;
|
|
93078
|
+
this.announcedAt.delete(oldest.value);
|
|
93079
|
+
}
|
|
93080
|
+
}
|
|
93081
|
+
/** True when the node announced an update no longer than the window ago. */
|
|
93082
|
+
isPlanned(nodeId, atMs) {
|
|
93083
|
+
const at = this.announcedAt.get(nodeId);
|
|
93084
|
+
return at !== void 0 && atMs - at <= this.graceMs;
|
|
93085
|
+
}
|
|
93086
|
+
/** An offline was put on hold for this node. */
|
|
93087
|
+
hold(nodeId, atMs) {
|
|
93088
|
+
this.heldAt.set(nodeId, atMs);
|
|
93089
|
+
}
|
|
93090
|
+
/**
|
|
93091
|
+
* The node is back: seconds the held offline lasted, or `null` when no offline
|
|
93092
|
+
* was held, or its window already ran out (the offline was sent).
|
|
93093
|
+
*/
|
|
93094
|
+
release(nodeId, atMs) {
|
|
93095
|
+
const at = this.heldAt.get(nodeId);
|
|
93096
|
+
if (at === void 0) return null;
|
|
93097
|
+
this.heldAt.delete(nodeId);
|
|
93098
|
+
return atMs - at < this.graceMs ? Math.round((atMs - at) / 1e3) : null;
|
|
93099
|
+
}
|
|
93100
|
+
};
|
|
93101
|
+
//#endregion
|
|
92937
93102
|
//#region src/notification-center/restart-supersede.ts
|
|
92938
93103
|
/** How many landings are remembered — one per node per update, so a fleet's worth. */
|
|
92939
93104
|
var NC_UPDATE_LANDINGS_MAX = 256;
|
|
@@ -97243,6 +97408,15 @@ var NcSystemStateLedger = class {
|
|
|
97243
97408
|
closeLegacyStreamKeys() {
|
|
97244
97409
|
this.closeWhere("legacy-stream-keys", (row) => row.key.startsWith("stream:") && !DEVICE_STREAM_KEY.test(row.key), "legacy-stream-key");
|
|
97245
97410
|
}
|
|
97411
|
+
/**
|
|
97412
|
+
* Is this device switched off RIGHT NOW (an open `device-disabled` row)?
|
|
97413
|
+
* D62: the switch outranks the device's liveness and its streams — a device
|
|
97414
|
+
* somebody turned off is reported off, never as offline. `false` while the
|
|
97415
|
+
* store has never answered (unknown is never "disabled").
|
|
97416
|
+
*/
|
|
97417
|
+
isDeviceDisabled(deviceId) {
|
|
97418
|
+
return (this.openRows() ?? []).some((row) => row.kind === "device-disabled" && row.deviceId === deviceId);
|
|
97419
|
+
}
|
|
97246
97420
|
/** The open rows, or `null` while the store has never answered. */
|
|
97247
97421
|
openRows() {
|
|
97248
97422
|
return this.deps.rows.answered() ? this.deps.rows.all() : null;
|
|
@@ -97749,6 +97923,7 @@ function readRaw(section, ports, nowMs) {
|
|
|
97749
97923
|
reason: UNREAD_STATE
|
|
97750
97924
|
};
|
|
97751
97925
|
const items = [];
|
|
97926
|
+
const switchedOff = new Set(state.flatMap((row) => row.kind === "device-disabled" && row.deviceId !== void 0 ? [row.deviceId] : []));
|
|
97752
97927
|
if (section === "device-state" || section === "nodes") {
|
|
97753
97928
|
const liveness = ports.liveness();
|
|
97754
97929
|
if (liveness === null) return {
|
|
@@ -97758,10 +97933,14 @@ function readRaw(section, ports, nowMs) {
|
|
|
97758
97933
|
for (const row of liveness) {
|
|
97759
97934
|
if (row.state !== "offline" || nowMs - row.updatedAt < ports.livenessHoldoffMs) continue;
|
|
97760
97935
|
const item = livenessItem(row, ports.lookup);
|
|
97761
|
-
if (item
|
|
97936
|
+
if (item === null || item.section !== section) continue;
|
|
97937
|
+
const id = item.subject.deviceId;
|
|
97938
|
+
if (id !== void 0 && switchedOff.has(id)) continue;
|
|
97939
|
+
items.push(item);
|
|
97762
97940
|
}
|
|
97763
97941
|
}
|
|
97764
97942
|
for (const row of state) {
|
|
97943
|
+
if (row.kind === "stream-offline" && row.deviceId !== void 0 && switchedOff.has(row.deviceId)) continue;
|
|
97765
97944
|
const item = stateItem(row, ports.lookup, ports.nodes);
|
|
97766
97945
|
if (item.section === section) items.push(item);
|
|
97767
97946
|
}
|
|
@@ -101894,6 +102073,7 @@ function onSystemEvent(host, event) {
|
|
|
101894
102073
|
const system = incoming.subject.systemEvent;
|
|
101895
102074
|
if (system !== void 0) host.stateSummary.observeSystem(system, host.now());
|
|
101896
102075
|
if (system !== void 0) host.updateLandings.observe(system, host.now());
|
|
102076
|
+
if (system !== void 0) host.plannedUpdates.observe(system, host.now());
|
|
101897
102077
|
const observation = system !== void 0 ? ledgeredLiveness(system) : null;
|
|
101898
102078
|
if (observation !== null) {
|
|
101899
102079
|
const previous = host.liveness.stateOf(observation.subject);
|
|
@@ -101920,17 +102100,86 @@ function onSystemEvent(host, event) {
|
|
|
101920
102100
|
});
|
|
101921
102101
|
return;
|
|
101922
102102
|
}
|
|
101923
|
-
if (
|
|
102103
|
+
if (isNodeLivenessKind(observation.kind) && system !== void 0) {
|
|
102104
|
+
armNodeLiveness(host, holdoff, observation.subject, incoming, system);
|
|
102105
|
+
return;
|
|
102106
|
+
}
|
|
102107
|
+
if (isDeviceLivenessKind(observation.kind)) {
|
|
102108
|
+
if (dropSwitchedOff(host, system)) return;
|
|
101924
102109
|
holdoff.arm(observation.subject, incoming);
|
|
101925
102110
|
return;
|
|
101926
102111
|
}
|
|
101927
102112
|
} else if (system !== void 0 && (system.kind.startsWith("device-") || system.kind.startsWith("stream-"))) {
|
|
101928
102113
|
if (host.lastSystemLiveness.get(system.subject) === system.kind) return;
|
|
101929
102114
|
host.lastSystemLiveness.set(system.subject, system.kind);
|
|
102115
|
+
if (dropSwitchedOff(host, system)) return;
|
|
101930
102116
|
}
|
|
101931
102117
|
host.consumeEvent(incoming);
|
|
101932
102118
|
}
|
|
101933
102119
|
/**
|
|
102120
|
+
* D62: a device the operator switched off is reported off, never offline. Its
|
|
102121
|
+
* `device-offline` / `stream-offline` is dropped (and said) while an open
|
|
102122
|
+
* `device-disabled` row exists — the broker of a disabled device stopping is
|
|
102123
|
+
* the switch working, not an outage. The memory of the flip is already kept.
|
|
102124
|
+
*/
|
|
102125
|
+
function dropSwitchedOff(host, system) {
|
|
102126
|
+
if (system === void 0 || system.deviceId === void 0) return false;
|
|
102127
|
+
if (system.kind !== "device-offline" && system.kind !== "stream-offline") return false;
|
|
102128
|
+
if (!host.stateSummary.ledger.isDeviceDisabled(system.deviceId)) return false;
|
|
102129
|
+
host.logger.debug("offline not notified — the device is switched off (D62)", {
|
|
102130
|
+
tags: { deviceId: system.deviceId },
|
|
102131
|
+
meta: {
|
|
102132
|
+
kind: system.kind,
|
|
102133
|
+
subject: system.subject
|
|
102134
|
+
}
|
|
102135
|
+
});
|
|
102136
|
+
return true;
|
|
102137
|
+
}
|
|
102138
|
+
/**
|
|
102139
|
+
* Arm a node liveness flip. An OFFLINE of a node that announced an update is
|
|
102140
|
+
* held for the whole planned-update window and worded as such if it is still
|
|
102141
|
+
* sent; the node's return inside the window is logged and sends nothing (the
|
|
102142
|
+
* hold-off sees the state bounce back to the one last notified).
|
|
102143
|
+
*/
|
|
102144
|
+
function armNodeLiveness(host, holdoff, subject, incoming, system) {
|
|
102145
|
+
const nodeId = system.nodeId;
|
|
102146
|
+
const now = host.now();
|
|
102147
|
+
if (nodeId === void 0) {
|
|
102148
|
+
holdoff.arm(subject, incoming);
|
|
102149
|
+
return;
|
|
102150
|
+
}
|
|
102151
|
+
const window = host.plannedUpdates;
|
|
102152
|
+
if (system.kind === "node-offline" && window.isPlanned(nodeId, now)) {
|
|
102153
|
+
window.hold(nodeId, now);
|
|
102154
|
+
holdoff.arm(subject, withPlannedUpdateWording(incoming, system, window.graceMinutes), window.windowMs);
|
|
102155
|
+
return;
|
|
102156
|
+
}
|
|
102157
|
+
if (system.kind === "node-online") {
|
|
102158
|
+
const backAfterSec = window.release(nodeId, now);
|
|
102159
|
+
if (backAfterSec !== null) host.logger.info(`node ${nodeId}: offline suppressed: planned update, back after ${backAfterSec}s`, { meta: {
|
|
102160
|
+
nodeId,
|
|
102161
|
+
backAfterSec
|
|
102162
|
+
} });
|
|
102163
|
+
}
|
|
102164
|
+
holdoff.arm(subject, incoming);
|
|
102165
|
+
}
|
|
102166
|
+
function withPlannedUpdateWording(incoming, system, graceMin) {
|
|
102167
|
+
return {
|
|
102168
|
+
...incoming,
|
|
102169
|
+
subject: {
|
|
102170
|
+
...incoming.subject,
|
|
102171
|
+
systemEvent: {
|
|
102172
|
+
...system,
|
|
102173
|
+
bodyKey: "system.node-offline.body.agent.updating",
|
|
102174
|
+
textParams: {
|
|
102175
|
+
...system.textParams,
|
|
102176
|
+
graceMin: String(graceMin)
|
|
102177
|
+
}
|
|
102178
|
+
}
|
|
102179
|
+
}
|
|
102180
|
+
};
|
|
102181
|
+
}
|
|
102182
|
+
/**
|
|
101934
102183
|
* One edge of an alert episode, from the bus or from the reconcile. The
|
|
101935
102184
|
* ledger decides whether it is news; only news reaches the rules.
|
|
101936
102185
|
*/
|
|
@@ -105749,6 +105998,7 @@ var NotificationCenter = class {
|
|
|
105749
105998
|
stateSummary;
|
|
105750
105999
|
/** Every `server-updated` heard, so a stale `node-updating` is not sent after it (D723). */
|
|
105751
106000
|
updateLandings = new NcUpdateLandings();
|
|
106001
|
+
plannedUpdates = new NcPlannedUpdateWindow();
|
|
105752
106002
|
/** States the `deviceState` rule gate reads. Refreshed on the reload tick;
|
|
105753
106003
|
* read with no I/O on the persist hook. */
|
|
105754
106004
|
deviceStates;
|
|
@@ -107141,6 +107391,9 @@ var NotificationCenter = class {
|
|
|
107141
107391
|
get timelapseRules() {
|
|
107142
107392
|
return self.timelapseRules;
|
|
107143
107393
|
},
|
|
107394
|
+
get plannedUpdates() {
|
|
107395
|
+
return self.plannedUpdates;
|
|
107396
|
+
},
|
|
107144
107397
|
get updateLandings() {
|
|
107145
107398
|
return self.updateLandings;
|
|
107146
107399
|
},
|
|
@@ -113073,7 +113326,10 @@ var PackageDropDetector = class {
|
|
|
113073
113326
|
}
|
|
113074
113327
|
if (outcome.kind === "yes") {
|
|
113075
113328
|
this.reportLlmSilence(this.llmSilence.noteAnswered(entry.deviceId), tags);
|
|
113076
|
-
return {
|
|
113329
|
+
return {
|
|
113330
|
+
packageLlmVerdict: outcome.verdict,
|
|
113331
|
+
confirmElapsedMs: latencyMs
|
|
113332
|
+
};
|
|
113077
113333
|
}
|
|
113078
113334
|
this.dropUncertain(entry, tags, outcome.reason, latencyMs);
|
|
113079
113335
|
return null;
|
|
@@ -113265,10 +113521,12 @@ var PackageDropDetector = class {
|
|
|
113265
113521
|
}
|
|
113266
113522
|
const llm = await this.llmFields(entry, rules, hitZones, tags);
|
|
113267
113523
|
if (llm === null) return;
|
|
113524
|
+
const { confirmElapsedMs, ...llmRowFields } = llm;
|
|
113525
|
+
const rowTimestamp = timestamp + (confirmElapsedMs ?? 0);
|
|
113268
113526
|
const draft = {
|
|
113269
113527
|
kind: "object",
|
|
113270
113528
|
deviceId: entry.deviceId,
|
|
113271
|
-
timestamp,
|
|
113529
|
+
timestamp: rowTimestamp,
|
|
113272
113530
|
source: "pipeline",
|
|
113273
113531
|
idempotencyKey,
|
|
113274
113532
|
trackId: entry.sourceTrackId ?? entry.id,
|
|
@@ -113287,7 +113545,7 @@ var PackageDropDetector = class {
|
|
|
113287
113545
|
frameHeight: entry.frameHeight,
|
|
113288
113546
|
...entry.keyFrameMediaId !== void 0 ? { mediaId: entry.keyFrameMediaId } : {},
|
|
113289
113547
|
importance: PACKAGE_IMPORTANCE,
|
|
113290
|
-
...
|
|
113548
|
+
...llmRowFields
|
|
113291
113549
|
};
|
|
113292
113550
|
const rowId = await this.deps.events.insertObject(draft);
|
|
113293
113551
|
if (rowId === null) {
|
|
@@ -113318,7 +113576,7 @@ var PackageDropDetector = class {
|
|
|
113318
113576
|
w: entry.bbox.w,
|
|
113319
113577
|
h: entry.bbox.h
|
|
113320
113578
|
},
|
|
113321
|
-
timestamp
|
|
113579
|
+
timestamp: rowTimestamp
|
|
113322
113580
|
});
|
|
113323
113581
|
this.deps.logger.info("package delivered — all 5 gates passed", {
|
|
113324
113582
|
tags: { deviceId: entry.deviceId },
|
|
@@ -113329,6 +113587,7 @@ var PackageDropDetector = class {
|
|
|
113329
113587
|
zoneIds: hitZones,
|
|
113330
113588
|
dwellMs,
|
|
113331
113589
|
areaFrac: Number(minAreaFrac.toFixed(5)),
|
|
113590
|
+
...confirmElapsedMs !== void 0 ? { footageAnchorShiftMs: confirmElapsedMs } : {},
|
|
113332
113591
|
...entry.confidence !== void 0 ? { confidence: entry.confidence } : {}
|
|
113333
113592
|
}
|
|
113334
113593
|
});
|
|
@@ -123860,6 +124119,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
123860
124119
|
this.frameState.lastNonPackageActivityAt.delete(data.deviceId);
|
|
123861
124120
|
this.frameState.packageCollectors.forgetDevice(data.deviceId);
|
|
123862
124121
|
this.frameState.packageOversizeLogAt.delete(data.deviceId);
|
|
124122
|
+
this.frameState.packageLookFrames.delete(data.deviceId);
|
|
123863
124123
|
this.frameState.packageLookDropReasons.delete(data.deviceId);
|
|
123864
124124
|
this.overlayState.clearDevice(data.deviceId);
|
|
123865
124125
|
this.frameState.overlaySynthesisWarnAt.delete(data.deviceId);
|
|
@@ -123883,6 +124143,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
123883
124143
|
this.frameState.lastNonPackageActivityAt.delete(deviceId);
|
|
123884
124144
|
this.frameState.packageCollectors.forgetDevice(deviceId);
|
|
123885
124145
|
this.frameState.packageOversizeLogAt.delete(deviceId);
|
|
124146
|
+
this.frameState.packageLookFrames.delete(deviceId);
|
|
123886
124147
|
this.frameState.packageLookDropReasons.delete(deviceId);
|
|
123887
124148
|
this.overlayState.clearDevice(deviceId);
|
|
123888
124149
|
this.frameState.overlaySynthesisWarnAt.delete(deviceId);
|
|
@@ -126865,6 +127126,10 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
126865
127126
|
runPackageStillness(input) {
|
|
126866
127127
|
if (this.packageDropDetector === null) return;
|
|
126867
127128
|
const tags = { deviceId: input.deviceId };
|
|
127129
|
+
if (input.frameHandle !== null) this.frameState.packageLookFrames.set(input.deviceId, {
|
|
127130
|
+
handle: input.frameHandle,
|
|
127131
|
+
at: input.timestamp
|
|
127132
|
+
});
|
|
126868
127133
|
for (const t of input.tracked) {
|
|
126869
127134
|
if (input.packageClasses.has(t.className)) continue;
|
|
126870
127135
|
if (!isDelivererInPackageZone(t.zones, input.packageZoneIds)) continue;
|
|
@@ -127098,10 +127363,23 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
127098
127363
|
...entry.confidence !== void 0 ? { confidence: entry.confidence } : {}
|
|
127099
127364
|
}
|
|
127100
127365
|
});
|
|
127101
|
-
this.
|
|
127102
|
-
|
|
127366
|
+
const lookFrame = this.frameState.packageLookFrames.get(input.deviceId);
|
|
127367
|
+
promoteWithStill({
|
|
127103
127368
|
entry,
|
|
127104
|
-
timestamp:
|
|
127369
|
+
handle: lookFrame !== void 0 && input.timestamp - lookFrame.at <= PACKAGE_LOOK_FRAME_MAX_AGE_MS ? lookFrame.handle : null,
|
|
127370
|
+
timestamp: lookFrame?.at ?? input.timestamp,
|
|
127371
|
+
query: (request) => this.queryPackageSceneCrop(request),
|
|
127372
|
+
writer: this.mediaStore,
|
|
127373
|
+
logger: this.ctx.logger,
|
|
127374
|
+
detector: this.packageDropDetector
|
|
127375
|
+
}).catch((err) => {
|
|
127376
|
+
this.ctx.logger.warn("package promotion failed", {
|
|
127377
|
+
tags,
|
|
127378
|
+
meta: {
|
|
127379
|
+
entryId: entry.id,
|
|
127380
|
+
error: err instanceof Error ? err.message : String(err)
|
|
127381
|
+
}
|
|
127382
|
+
});
|
|
127105
127383
|
});
|
|
127106
127384
|
}
|
|
127107
127385
|
for (const entry of outcome.departed) {
|