@camstack/addon-post-analysis 1.2.638 → 1.2.640
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-B-Dv5y3Z.mjs → clip-model-registry-B1HxbGuP.mjs} +120 -8
- package/dist/{clip-model-registry-DEcrrqRz.js → clip-model-registry-C8xdbChV.js} +120 -8
- 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-LOOCKNGE.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-CO5qrMxU.mjs} +2 -2
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CENVyAAQ.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-DIbQ2FJ4.mjs +26 -0
- package/dist/pipeline-analytics/{hostInit-C2kfB4nI.mjs → hostInit-BN2pgAbz.mjs} +2 -2
- package/dist/pipeline-analytics/index.js +216 -85
- package/dist/pipeline-analytics/index.mjs +216 -85
- 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-D4TYbuPV.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-DXlqUmY1.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-C8xdbChV.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");
|
|
@@ -8995,6 +8995,7 @@ var en_default = {
|
|
|
8995
8995
|
"system.device-battery-low.title": "Battery low — {{deviceName}}",
|
|
8996
8996
|
"system.device-battery-low.body": "{{deviceName}} is down to {{percentage}}% battery",
|
|
8997
8997
|
"system.device-battery-low.body.binary": "{{deviceName}} reports a low battery",
|
|
8998
|
+
"system.device-battery-low.body.unmeasured": "{{deviceName}} has a low battery",
|
|
8998
8999
|
"system.device-battery-normal.title": "Battery back to normal — {{deviceName}}",
|
|
8999
9000
|
"system.device-battery-normal.body": "{{deviceName}} is back to {{percentage}}% battery",
|
|
9000
9001
|
"system.device-battery-normal.body.binary": "{{deviceName}} no longer reports a low battery",
|
|
@@ -9395,6 +9396,7 @@ var it_default = {
|
|
|
9395
9396
|
"system.device-battery-low.title": "Batteria scarica — {{deviceName}}",
|
|
9396
9397
|
"system.device-battery-low.body": "{{deviceName}} è al {{percentage}}% di batteria",
|
|
9397
9398
|
"system.device-battery-low.body.binary": "{{deviceName}} segnala la batteria scarica",
|
|
9399
|
+
"system.device-battery-low.body.unmeasured": "{{deviceName}} ha la batteria scarica",
|
|
9398
9400
|
"system.device-battery-normal.title": "Batteria rientrata — {{deviceName}}",
|
|
9399
9401
|
"system.device-battery-normal.body": "{{deviceName}} è risalito al {{percentage}}% di batteria",
|
|
9400
9402
|
"system.device-battery-normal.body.binary": "{{deviceName}} non segnala più la batteria scarica",
|
|
@@ -78853,6 +78855,97 @@ function alertSubjectDeviceId(subject) {
|
|
|
78853
78855
|
return Number.isInteger(parsed) ? parsed : void 0;
|
|
78854
78856
|
}
|
|
78855
78857
|
//#endregion
|
|
78858
|
+
//#region src/notification-center/alerts/consumable-subject.ts
|
|
78859
|
+
/**
|
|
78860
|
+
* A consumable EPISODE's name, and the thresholds the rule set asks for (D642).
|
|
78861
|
+
*
|
|
78862
|
+
* Before D642 one cluster-wide threshold judged every item, so an item had one
|
|
78863
|
+
* episode: `consumable:<deviceId>:<key>`. The threshold is now the RULE's, and
|
|
78864
|
+
* the ledger keeps one episode per threshold a rule asks for — each with its
|
|
78865
|
+
* own hysteresis, pending raise and reminder — named
|
|
78866
|
+
* `consumable@<threshold>:<deviceId>:<key>`.
|
|
78867
|
+
*
|
|
78868
|
+
* The threshold rides the FAMILY segment on purpose: the device id stays the
|
|
78869
|
+
* second segment (`alertSubjectDeviceId`, D636 — the log tag and the indexed
|
|
78870
|
+
* column read it), and the item key stays last and whole, whatever it holds.
|
|
78871
|
+
*
|
|
78872
|
+
* Pure. No clock, no I/O.
|
|
78873
|
+
*/
|
|
78874
|
+
var FAMILY = "consumable";
|
|
78875
|
+
/** The episode of `key` on `deviceId`, judged at `thresholdPercent`. */
|
|
78876
|
+
function consumableSubject(thresholdPercent, deviceId, key) {
|
|
78877
|
+
return `${FAMILY}@${String(thresholdPercent)}:${String(deviceId)}:${key}`;
|
|
78878
|
+
}
|
|
78879
|
+
/** The pre-D642 subject of the same item — read only to carry it over. */
|
|
78880
|
+
function legacyConsumableSubject(deviceId, key) {
|
|
78881
|
+
return `${FAMILY}:${String(deviceId)}:${key}`;
|
|
78882
|
+
}
|
|
78883
|
+
/** `null` for a subject that is not a consumable's. */
|
|
78884
|
+
function parseConsumableSubject(subject) {
|
|
78885
|
+
const first = subject.indexOf(":");
|
|
78886
|
+
const second = first < 0 ? -1 : subject.indexOf(":", first + 1);
|
|
78887
|
+
if (first < 0 || second < 0) return null;
|
|
78888
|
+
const family = subject.slice(0, first);
|
|
78889
|
+
const deviceId = Number(subject.slice(first + 1, second));
|
|
78890
|
+
const key = subject.slice(second + 1);
|
|
78891
|
+
if (!Number.isInteger(deviceId) || key.length === 0) return null;
|
|
78892
|
+
if (family === FAMILY) return {
|
|
78893
|
+
thresholdPercent: require_clip_model_registry.NC_CONSUMABLE_LOW_PERCENT_DEFAULT,
|
|
78894
|
+
deviceId,
|
|
78895
|
+
key,
|
|
78896
|
+
legacy: true
|
|
78897
|
+
};
|
|
78898
|
+
if (!family.startsWith(`${FAMILY}@`)) return null;
|
|
78899
|
+
const thresholdPercent = Number(family.slice(11));
|
|
78900
|
+
if (!Number.isInteger(thresholdPercent)) return null;
|
|
78901
|
+
return {
|
|
78902
|
+
thresholdPercent,
|
|
78903
|
+
deviceId,
|
|
78904
|
+
key,
|
|
78905
|
+
legacy: false
|
|
78906
|
+
};
|
|
78907
|
+
}
|
|
78908
|
+
/**
|
|
78909
|
+
* Every consumable threshold the rule set asks for, ascending.
|
|
78910
|
+
*
|
|
78911
|
+
* A rule asks when it is a system-event rule whose kinds include a consumable
|
|
78912
|
+
* kind — enabled or not: a disabled rule's episode stays PENDING (no rule
|
|
78913
|
+
* matched it) and is re-offered the moment the rule is switched back on
|
|
78914
|
+
* (D636), which is what that rule would have said had it been on. With no such
|
|
78915
|
+
* rule at all the default is still judged, so an episode exists for the first
|
|
78916
|
+
* rule an operator writes to hear (D636's "offered once per rule change").
|
|
78917
|
+
*/
|
|
78918
|
+
function consumableThresholdCensus(rules) {
|
|
78919
|
+
const thresholds = /* @__PURE__ */ new Set();
|
|
78920
|
+
for (const rule of rules) {
|
|
78921
|
+
const condition = rule.conditions.systemEvent;
|
|
78922
|
+
if (rule.delivery !== "system-event" || condition === void 0) continue;
|
|
78923
|
+
if (!condition.kinds.some((kind) => require_clip_model_registry.NC_CONSUMABLE_SYSTEM_EVENT_KINDS.includes(kind))) continue;
|
|
78924
|
+
thresholds.add(require_clip_model_registry.consumableLowPercentOf(condition));
|
|
78925
|
+
}
|
|
78926
|
+
if (thresholds.size === 0) thresholds.add(require_clip_model_registry.NC_CONSUMABLE_LOW_PERCENT_DEFAULT);
|
|
78927
|
+
return [...thresholds].toSorted((a, b) => a - b);
|
|
78928
|
+
}
|
|
78929
|
+
//#endregion
|
|
78930
|
+
//#region src/notification-center/alerts/tank-subject.ts
|
|
78931
|
+
function tankSubject(deviceId, key) {
|
|
78932
|
+
return `tank:${String(deviceId)}:${key}`;
|
|
78933
|
+
}
|
|
78934
|
+
/** `null` for a subject that is not a leftover tank episode. */
|
|
78935
|
+
function parseTankSubject(subject) {
|
|
78936
|
+
const first = subject.indexOf(":");
|
|
78937
|
+
const second = first < 0 ? -1 : subject.indexOf(":", first + 1);
|
|
78938
|
+
if (first < 0 || second < 0) return null;
|
|
78939
|
+
if (subject.slice(0, first) !== "tank") return null;
|
|
78940
|
+
const deviceId = Number(subject.slice(first + 1, second));
|
|
78941
|
+
const key = subject.slice(second + 1);
|
|
78942
|
+
if (!Number.isInteger(deviceId) || key.length === 0) return null;
|
|
78943
|
+
return {
|
|
78944
|
+
deviceId,
|
|
78945
|
+
key
|
|
78946
|
+
};
|
|
78947
|
+
}
|
|
78948
|
+
//#endregion
|
|
78856
78949
|
//#region src/notification-center/alerts/alert-store.ts
|
|
78857
78950
|
/**
|
|
78858
78951
|
* @durable class=ledger owner=notification-center
|
|
@@ -78973,6 +79066,7 @@ function mergeBootWindowAlertRow(stored, provisional) {
|
|
|
78973
79066
|
}
|
|
78974
79067
|
var NcAlertStore = class {
|
|
78975
79068
|
ledger;
|
|
79069
|
+
logger;
|
|
78976
79070
|
/**
|
|
78977
79071
|
* THE BOOT WINDOW (D698). Battery slices arrive from the moment the centre
|
|
78978
79072
|
* starts, and the ledger is read only in the back-fill. A row written in that
|
|
@@ -78984,6 +79078,7 @@ var NcAlertStore = class {
|
|
|
78984
79078
|
*/
|
|
78985
79079
|
bootWindow;
|
|
78986
79080
|
constructor(deps) {
|
|
79081
|
+
this.logger = deps.logger;
|
|
78987
79082
|
this.ledger = new DurableLedger({
|
|
78988
79083
|
spec: NC_ALERTS_SPEC,
|
|
78989
79084
|
kind: deps.records.kind(ncDurableRecordKinds["device-alerts"]),
|
|
@@ -79003,6 +79098,50 @@ var NcAlertStore = class {
|
|
|
79003
79098
|
this.bootWindow.settle();
|
|
79004
79099
|
return loaded;
|
|
79005
79100
|
}
|
|
79101
|
+
/**
|
|
79102
|
+
* Close open `tank:<id>:<key>` leftovers once (D934). Idempotent.
|
|
79103
|
+
*
|
|
79104
|
+
* A row closes when the same key is already a consumable episode in this
|
|
79105
|
+
* ledger, or when an answered directory has no device for it. A live device
|
|
79106
|
+
* whose key has not been seen yet is kept — the next consumable observation
|
|
79107
|
+
* closes it. `battery:` rows are not tank subjects and are never touched.
|
|
79108
|
+
* Deletes go through this ledger (D679).
|
|
79109
|
+
*/
|
|
79110
|
+
async sweepOpenTankLeftovers(input) {
|
|
79111
|
+
const known = consumableKeysOf(this.ledger.snapshot());
|
|
79112
|
+
const closing = [];
|
|
79113
|
+
let kept = 0;
|
|
79114
|
+
for (const row of this.ledger.snapshot()) {
|
|
79115
|
+
if (!row.alerting) continue;
|
|
79116
|
+
const tank = parseTankSubject(row.subject);
|
|
79117
|
+
if (tank === null) continue;
|
|
79118
|
+
const reason = tankCloseReason(tank, known, input.liveOwner(tank.deviceId));
|
|
79119
|
+
if (reason === "keep") kept += 1;
|
|
79120
|
+
else closing.push({
|
|
79121
|
+
row,
|
|
79122
|
+
reason
|
|
79123
|
+
});
|
|
79124
|
+
}
|
|
79125
|
+
for (const item of closing) {
|
|
79126
|
+
const deviceId = alertSubjectDeviceId(item.row.subject);
|
|
79127
|
+
await this.ledger.forget(item.row.subject);
|
|
79128
|
+
this.logger.info("leftover tank alert closed", {
|
|
79129
|
+
...deviceId !== void 0 ? { tags: { deviceId } } : {},
|
|
79130
|
+
meta: {
|
|
79131
|
+
subject: item.row.subject,
|
|
79132
|
+
reason: item.reason
|
|
79133
|
+
}
|
|
79134
|
+
});
|
|
79135
|
+
}
|
|
79136
|
+
this.logger.info("leftover tank alert sweep", { meta: {
|
|
79137
|
+
closed: closing.length,
|
|
79138
|
+
kept
|
|
79139
|
+
} });
|
|
79140
|
+
return {
|
|
79141
|
+
closed: closing.length,
|
|
79142
|
+
kept
|
|
79143
|
+
};
|
|
79144
|
+
}
|
|
79006
79145
|
/** Drop a deleted device's mirrored rows (the durable ones go by `deleteWhere`, D871). */
|
|
79007
79146
|
evictDevice(deviceId) {
|
|
79008
79147
|
return this.ledger.evictDevice(deviceId);
|
|
@@ -79030,77 +79169,21 @@ var NcAlertStore = class {
|
|
|
79030
79169
|
};
|
|
79031
79170
|
}
|
|
79032
79171
|
};
|
|
79033
|
-
|
|
79034
|
-
|
|
79035
|
-
/**
|
|
79036
|
-
* A consumable EPISODE's name, and the thresholds the rule set asks for (D642).
|
|
79037
|
-
*
|
|
79038
|
-
* Before D642 one cluster-wide threshold judged every item, so an item had one
|
|
79039
|
-
* episode: `consumable:<deviceId>:<key>`. The threshold is now the RULE's, and
|
|
79040
|
-
* the ledger keeps one episode per threshold a rule asks for — each with its
|
|
79041
|
-
* own hysteresis, pending raise and reminder — named
|
|
79042
|
-
* `consumable@<threshold>:<deviceId>:<key>`.
|
|
79043
|
-
*
|
|
79044
|
-
* The threshold rides the FAMILY segment on purpose: the device id stays the
|
|
79045
|
-
* second segment (`alertSubjectDeviceId`, D636 — the log tag and the indexed
|
|
79046
|
-
* column read it), and the item key stays last and whole, whatever it holds.
|
|
79047
|
-
*
|
|
79048
|
-
* Pure. No clock, no I/O.
|
|
79049
|
-
*/
|
|
79050
|
-
var FAMILY = "consumable";
|
|
79051
|
-
/** The episode of `key` on `deviceId`, judged at `thresholdPercent`. */
|
|
79052
|
-
function consumableSubject(thresholdPercent, deviceId, key) {
|
|
79053
|
-
return `${FAMILY}@${String(thresholdPercent)}:${String(deviceId)}:${key}`;
|
|
79054
|
-
}
|
|
79055
|
-
/** The pre-D642 subject of the same item — read only to carry it over. */
|
|
79056
|
-
function legacyConsumableSubject(deviceId, key) {
|
|
79057
|
-
return `${FAMILY}:${String(deviceId)}:${key}`;
|
|
79058
|
-
}
|
|
79059
|
-
/** `null` for a subject that is not a consumable's. */
|
|
79060
|
-
function parseConsumableSubject(subject) {
|
|
79061
|
-
const first = subject.indexOf(":");
|
|
79062
|
-
const second = first < 0 ? -1 : subject.indexOf(":", first + 1);
|
|
79063
|
-
if (first < 0 || second < 0) return null;
|
|
79064
|
-
const family = subject.slice(0, first);
|
|
79065
|
-
const deviceId = Number(subject.slice(first + 1, second));
|
|
79066
|
-
const key = subject.slice(second + 1);
|
|
79067
|
-
if (!Number.isInteger(deviceId) || key.length === 0) return null;
|
|
79068
|
-
if (family === FAMILY) return {
|
|
79069
|
-
thresholdPercent: require_clip_model_registry.NC_CONSUMABLE_LOW_PERCENT_DEFAULT,
|
|
79070
|
-
deviceId,
|
|
79071
|
-
key,
|
|
79072
|
-
legacy: true
|
|
79073
|
-
};
|
|
79074
|
-
if (!family.startsWith(`${FAMILY}@`)) return null;
|
|
79075
|
-
const thresholdPercent = Number(family.slice(11));
|
|
79076
|
-
if (!Number.isInteger(thresholdPercent)) return null;
|
|
79077
|
-
return {
|
|
79078
|
-
thresholdPercent,
|
|
79079
|
-
deviceId,
|
|
79080
|
-
key,
|
|
79081
|
-
legacy: false
|
|
79082
|
-
};
|
|
79172
|
+
function consumableKey(deviceId, key) {
|
|
79173
|
+
return `${String(deviceId)}:${key}`;
|
|
79083
79174
|
}
|
|
79084
|
-
|
|
79085
|
-
|
|
79086
|
-
|
|
79087
|
-
|
|
79088
|
-
|
|
79089
|
-
* matched it) and is re-offered the moment the rule is switched back on
|
|
79090
|
-
* (D636), which is what that rule would have said had it been on. With no such
|
|
79091
|
-
* rule at all the default is still judged, so an episode exists for the first
|
|
79092
|
-
* rule an operator writes to hear (D636's "offered once per rule change").
|
|
79093
|
-
*/
|
|
79094
|
-
function consumableThresholdCensus(rules) {
|
|
79095
|
-
const thresholds = /* @__PURE__ */ new Set();
|
|
79096
|
-
for (const rule of rules) {
|
|
79097
|
-
const condition = rule.conditions.systemEvent;
|
|
79098
|
-
if (rule.delivery !== "system-event" || condition === void 0) continue;
|
|
79099
|
-
if (!condition.kinds.some((kind) => require_clip_model_registry.NC_CONSUMABLE_SYSTEM_EVENT_KINDS.includes(kind))) continue;
|
|
79100
|
-
thresholds.add(require_clip_model_registry.consumableLowPercentOf(condition));
|
|
79175
|
+
function consumableKeysOf(rows) {
|
|
79176
|
+
const keys = /* @__PURE__ */ new Set();
|
|
79177
|
+
for (const row of rows) {
|
|
79178
|
+
const parts = parseConsumableSubject(row.subject);
|
|
79179
|
+
if (parts !== null) keys.add(consumableKey(parts.deviceId, parts.key));
|
|
79101
79180
|
}
|
|
79102
|
-
|
|
79103
|
-
|
|
79181
|
+
return keys;
|
|
79182
|
+
}
|
|
79183
|
+
function tankCloseReason(tank, known, owner) {
|
|
79184
|
+
if (known.has(consumableKey(tank.deviceId, tank.key))) return "consumable key already known";
|
|
79185
|
+
if (owner === false) return "no live owner";
|
|
79186
|
+
return "keep";
|
|
79104
79187
|
}
|
|
79105
79188
|
//#endregion
|
|
79106
79189
|
//#region src/notification-center/alerts/consumable-band.ts
|
|
@@ -79853,6 +79936,24 @@ function incomingFromBatteryBand(input) {
|
|
|
79853
79936
|
});
|
|
79854
79937
|
}
|
|
79855
79938
|
/**
|
|
79939
|
+
* The summary sentence for a battery episode whose slice has not been read
|
|
79940
|
+
* since boot. It names the device and nothing else: a missing level is not
|
|
79941
|
+
* 0%, and it is not the binary indicator's sentence.
|
|
79942
|
+
*/
|
|
79943
|
+
function incomingFromUnmeasuredBattery(input) {
|
|
79944
|
+
const kind = "device-battery-low";
|
|
79945
|
+
return systemSubject({
|
|
79946
|
+
facts: input.facts,
|
|
79947
|
+
kind,
|
|
79948
|
+
subject: `battery:${input.deviceId}`,
|
|
79949
|
+
titleKey: `system.${kind}.title`,
|
|
79950
|
+
bodyKey: `system.${kind}.body.unmeasured`,
|
|
79951
|
+
textParams: deviceTextParams(input.deviceId, input.identity),
|
|
79952
|
+
deviceId: input.deviceId,
|
|
79953
|
+
...input.identity !== void 0 ? { deviceType: input.identity.type } : {}
|
|
79954
|
+
});
|
|
79955
|
+
}
|
|
79956
|
+
/**
|
|
79856
79957
|
* A consumable BAND, as a system-event subject.
|
|
79857
79958
|
*
|
|
79858
79959
|
* Built exactly like {@link incomingFromBatteryBand} — the operator asked for
|
|
@@ -80828,22 +80929,24 @@ function deliveryForKind(kind) {
|
|
|
80828
80929
|
}
|
|
80829
80930
|
//#endregion
|
|
80830
80931
|
//#region src/notification-center/alerts/open-alert.ts
|
|
80932
|
+
/** `battery:<deviceId>` — nothing else. A `tank:` subject is not one of these. */
|
|
80933
|
+
function isBatterySubject(subject) {
|
|
80934
|
+
const deviceId = alertSubjectDeviceId(subject);
|
|
80935
|
+
return deviceId !== void 0 && subject === `battery:${String(deviceId)}`;
|
|
80936
|
+
}
|
|
80831
80937
|
function unmeasuredEpisode(input) {
|
|
80832
80938
|
const deviceId = alertSubjectDeviceId(input.subject);
|
|
80833
80939
|
if (deviceId === void 0) return null;
|
|
80834
80940
|
const identity = input.lookup(deviceId);
|
|
80835
80941
|
const facts = input.facts;
|
|
80836
|
-
if (input.family === "battery")
|
|
80837
|
-
|
|
80838
|
-
|
|
80839
|
-
|
|
80840
|
-
|
|
80841
|
-
|
|
80842
|
-
|
|
80843
|
-
|
|
80844
|
-
},
|
|
80845
|
-
identity
|
|
80846
|
-
});
|
|
80942
|
+
if (input.family === "battery") {
|
|
80943
|
+
if (!isBatterySubject(input.subject)) return null;
|
|
80944
|
+
return incomingFromUnmeasuredBattery({
|
|
80945
|
+
facts,
|
|
80946
|
+
deviceId,
|
|
80947
|
+
identity
|
|
80948
|
+
});
|
|
80949
|
+
}
|
|
80847
80950
|
const parts = parseConsumableSubject(input.subject);
|
|
80848
80951
|
if (parts !== null && parts.legacy) {
|
|
80849
80952
|
const parsed = parseProviderVerdictDetail(input.detail);
|
|
@@ -80917,6 +81020,15 @@ function isProviderVerdictDetail(detail) {
|
|
|
80917
81020
|
}
|
|
80918
81021
|
function openAlertOf(row, input) {
|
|
80919
81022
|
const parts = parseConsumableSubject(row.subject);
|
|
81023
|
+
const battery = isBatterySubject(row.subject);
|
|
81024
|
+
if (parts === null && !battery) {
|
|
81025
|
+
const deviceId = alertSubjectDeviceId(row.subject);
|
|
81026
|
+
input.logger?.warn("open alert skipped — subject is neither a battery nor a consumable", {
|
|
81027
|
+
...deviceId !== void 0 ? { tags: { deviceId } } : {},
|
|
81028
|
+
meta: { subject: row.subject }
|
|
81029
|
+
});
|
|
81030
|
+
return null;
|
|
81031
|
+
}
|
|
80920
81032
|
const family = parts !== null ? "consumable" : "battery";
|
|
80921
81033
|
const subject = (input.restated ?? unmeasuredEpisode({
|
|
80922
81034
|
subject: row.subject,
|
|
@@ -81137,6 +81249,7 @@ var NcDeviceAlerts = class {
|
|
|
81137
81249
|
*/
|
|
81138
81250
|
/** One item from the consumables slice — every form (D934). */
|
|
81139
81251
|
observeConsumableItem(deviceId, sliceItem) {
|
|
81252
|
+
this.closeTankLeftover(deviceId, sliceItem.key);
|
|
81140
81253
|
if (sliceItem.wear !== null) {
|
|
81141
81254
|
this.observeConsumable(deviceId, sliceItem.wear);
|
|
81142
81255
|
return;
|
|
@@ -81317,13 +81430,15 @@ var NcDeviceAlerts = class {
|
|
|
81317
81430
|
for (const row of this.deps.rows.all()) {
|
|
81318
81431
|
if (!row.alerting) continue;
|
|
81319
81432
|
const restated = this.restatementOf(row.subject);
|
|
81433
|
+
const logger = this.logger();
|
|
81320
81434
|
const open = openAlertOf(row, {
|
|
81321
81435
|
facts,
|
|
81322
81436
|
restated: restated === null ? null : restated(facts),
|
|
81323
|
-
lookup: this.deps.lookup
|
|
81437
|
+
lookup: this.deps.lookup,
|
|
81438
|
+
...logger !== void 0 ? { logger } : {}
|
|
81324
81439
|
});
|
|
81325
81440
|
if (open !== null) out.push(open);
|
|
81326
|
-
else this.logger()?.debug("open alert left out of the state summary — it cannot be worded", {
|
|
81441
|
+
else if (parseConsumableSubject(row.subject) !== null || isBatterySubject(row.subject)) this.logger()?.debug("open alert left out of the state summary — it cannot be worded", {
|
|
81327
81442
|
...tagsOf(row.subject),
|
|
81328
81443
|
meta: { subject: row.subject }
|
|
81329
81444
|
});
|
|
@@ -81388,6 +81503,16 @@ var NcDeviceAlerts = class {
|
|
|
81388
81503
|
}
|
|
81389
81504
|
this.absentThresholds = absent;
|
|
81390
81505
|
}
|
|
81506
|
+
/**
|
|
81507
|
+
* A leftover `tank:<id>:<key>` ends when that key is seen on the consumables
|
|
81508
|
+
* slice (D934). Silent: no recovery. A real `battery:` row is a different
|
|
81509
|
+
* subject and is not touched.
|
|
81510
|
+
*/
|
|
81511
|
+
closeTankLeftover(deviceId, key) {
|
|
81512
|
+
const subject = tankSubject(deviceId, key);
|
|
81513
|
+
if (this.deps.rows.get(subject) === void 0) return;
|
|
81514
|
+
this.dropRow(subject, "closed — the same key is a consumable (D934)");
|
|
81515
|
+
}
|
|
81391
81516
|
/** Remove one row, mirror and durable, with a line that names why. */
|
|
81392
81517
|
dropRow(subject, reason) {
|
|
81393
81518
|
this.offeredAt.delete(subject);
|
|
@@ -101584,7 +101709,13 @@ async function runBootBackfill(host) {
|
|
|
101584
101709
|
if (!await phase("alertEpisodes", () => host.hydrateAlertEpisodes())) return;
|
|
101585
101710
|
if (!await phase("deviceAlerts", async () => {
|
|
101586
101711
|
const rows = await host.alertStore.load();
|
|
101587
|
-
host.
|
|
101712
|
+
const directoryAnswered = host.deviceDirectory.answeredGeneration() > 0;
|
|
101713
|
+
const tankLeftovers = await host.alertStore.sweepOpenTankLeftovers({ liveOwner: (deviceId) => directoryAnswered ? host.deviceDirectory.get(deviceId) !== void 0 : void 0 });
|
|
101714
|
+
host.logger.info("device alert ledger reseeded", { meta: {
|
|
101715
|
+
rows,
|
|
101716
|
+
tankLeftoversClosed: tankLeftovers.closed,
|
|
101717
|
+
tankLeftoversKept: tankLeftovers.kept
|
|
101718
|
+
} });
|
|
101588
101719
|
})) return;
|
|
101589
101720
|
if (!await phase("stateSummary", async () => {
|
|
101590
101721
|
const loaded = await host.stateSummary.load();
|
|
@@ -112207,7 +112338,7 @@ var MotionEpisodeTracker = class {
|
|
|
112207
112338
|
*
|
|
112208
112339
|
* A single timeout is the call's bound doing its job. Three uncertain confirms
|
|
112209
112340
|
* in a row, with no yes and no no between them, is the provider not answering
|
|
112210
|
-
* — the shape camera
|
|
112341
|
+
* — the shape camera 102 showed on 2026-10-26 (nine timeouts, zero answers).
|
|
112211
112342
|
* A time window would also count a timeout that a later answer already closed.
|
|
112212
112343
|
* The streak resets on any answer. A further uncertain while the edge is
|
|
112213
112344
|
* open does not raise again.
|