@camstack/addon-post-analysis 1.2.601 → 1.2.602

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.
Files changed (15) hide show
  1. package/dist/{clip-model-registry-DAZ9ie-f.js → clip-model-registry-D0-VNIW5.js} +381 -8
  2. package/dist/{clip-model-registry-BuM8eXlN.mjs → clip-model-registry-lQ7QWjLf.mjs} +376 -9
  3. package/dist/embedding-encoder/index.js +1 -1
  4. package/dist/embedding-encoder/index.mjs +1 -1
  5. package/dist/pipeline-analytics/_stub.js +2 -2
  6. package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-DAs_96VP.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-BPA0T5-F.mjs} +2 -2
  7. package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-1AlitJg2.mjs +26 -0
  8. package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-Cfj8Mv5X.mjs +26 -0
  9. package/dist/pipeline-analytics/{hostInit-C3wjY7W8.mjs → hostInit-DIjMiIYW.mjs} +2 -2
  10. package/dist/pipeline-analytics/index.js +281 -503
  11. package/dist/pipeline-analytics/index.mjs +281 -503
  12. package/dist/pipeline-analytics/remoteEntry.js +1 -1
  13. package/package.json +1 -1
  14. package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CElkWYPg.mjs +0 -26
  15. package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-SRvLcL_J.mjs +0 -26
@@ -1,4 +1,4 @@
1
- import { $ as MotionTriggeredBySchema, $i as strictObject, $n as deriveDetailCropRect, $r as retrainRevisionConflictMessage, $t as OPS_LOG_DEFAULT_LIMIT, A as DetectionSourceSchema, Ai as BaseAddon, An as TrackSourceSchema, Ar as isScheduleActive, At as NcAlarmSensorsSchema, B as FailureCounters, Bn as assertTimelapseCadences, Bt as NcRuleTargetSchema, C as CoverStateSchema, Ci as zoneAnalyticsCapability, Cn as TimelapseRuleInputSchema, Cr as isEventKindLabelKey, Ct as NC_SYSTEM_EVENT_KIND_GROUP_SPECS, D as DETECTION_MACRO_CLASSES, Di as isSourceCap, Dn as TrackRelationKindSchema, Dr as isMediaOwnerType, Dt as NcAlarmConfigSchema, E as DEFAULT_TIMELAPSE_PREVIEW_TEXT, Ei as evaluateSensorEdge, En as TrackPuritySchema, Er as isLabelSupplyStepId, Et as NC_TEMPLATE_VARS, F as EVENT_KIND_BY_CAP, Fi as defineCustomActions, Fn as applyBlockingEdit, Fr as linkedStepOf, Ft as NcRuleActionSchema, G as LockStateSchema, Gi as boolean, Gn as calendarEventLocalSpan, Gr as readMotionTriggeredBy, Gt as NcSnoozeSchema, H as LabelAttributionSchema, Hi as ZodObject, Hn as audioModeOf, Hr as pipelineAnalyticsCapability, Ht as NcScheduleSchema, I as EVENT_OWNER_TYPES, Ii as defineRecordKinds, In as applyModeDelaysEdits, Ir as mayWriteToLocation, It as NcRuleActionsSchema, J as MAX_BIRTH_LATENCY_PROXY_MS, Ji as looseObject, Jn as consumableLowPercentOf, Jr as resolveClipSearchMinScore, Jt as NcSystemEventKindSchema, K as MAX_ARCHIVED_DEBUG_NOTES, Ki as discriminatedUnion, Kn as classifyRetrainReview, Kr as readTimelapseGeneratedAt, Kt as NcSnoozeSuppressedSchema, L as EXPORT_DENSE_MAX_RANGES, Li as hydrateSchema, Ln as applyNonBlockingEdit, Lr as memoizePinnedFfmpeg, Lt as NcRuleInputSchema, M as EMBEDDING_REQUIREMENTS_FAILED, Mi as RECORD_MAX_DATA_BYTES, Mn as addonWidgetsSourceCapability, Mr as isSystemEventSummaryRule, Mt as NcConditionDescriptorSchema, N as EMBEDDING_REQUIREMENTS_UNAVAILABLE, Ni as createEvent, Nn as alarmDeviceSecureOnArm, Nr as isVectorIndexDimConflict, Nt as NcConditionsSchema, O as DETECTION_PIPELINE_CAP_NAME, Oi as DeviceType, On as TrackRelationSchema, Or as isRetiredClearKey, Ot as NcAlarmPostTriggeredActionSchema, P as EVENT_DENSITY_BATCH_MAX, Pi as customAction, Pn as alarmPanelCapability, Pr as kebabToCamel, Pt as NcLegacyRuleActionSequenceSchema, Q as MediaFileKindEnum, Qi as record, Qn as deleteAlarmProfile, Qt as NcTemplateVarDescriptorSchema, R as FIRST_LEVEL_MACRO_CLASSES, Ri as isDeviceScopedCap, Rn as applySecureOnArmEdit, Rr as notificationRulesCapability, Rt as NcRulePatchSchema, S as ClearTrackRelationResultSchema, Si as viewerLinkBaseOf, Sn as TRACK_RELATIONS_DEFAULT_LIMIT, Sr as isDetectionMacroClass, St as NC_SNOOZE_MAX_MINUTES, T as DEFAULT_EVENT_COLOR, Ti as canonicalHash, Tn as TimelapseRuleSchema, Tr as isKnownTemplateVar, Tt as NC_TAXONOMY, U as ListTrackRelationsInputSchema, Ui as _enum, Un as buildEventKindDescriptor, Ur as plateGalleryCapability, Ut as NcSharedSequenceSchema, V as LABEL_SUPPLY_MACRO, Vi as sleep$1, Vn as audioMetricsCapability, Vr as pickFaceRescoreIntervalMinutes, Vt as NcRuleUpdateInputSchema, W as ListTrackRelationsResultSchema, Wi as array, Wn as buildViewerLink, Wr as readDeviceStateFrom, Wt as NcSnoozeInputSchema, X as MAX_TRACK_RELATIONS, Xi as object, Xn as cosineSimilarity$1, Xr as resolveModeDelays, Xt as NcTemplatePreviewInputSchema, Y as MAX_TRACK_PURITIES, Yi as number, Yn as coreBlockIdFromAddonId, Yr as resolveLocationMode, Yt as NcTaxonomySchema, Z as MOTION_CLOSE_AFTER_MS, Zi as partialRecord, Zn as createAlarmProfile, Zr as resolveModeNotifyPolicy, Zt as NcTemplatePreviewSchema, _ as BIRTH_DECISION_DEFAULT_LIMIT, _i as systemEventSummaryScheduleOf, _n as SceneMonitorSchema, _r as gifFromMp4Args, _t as NC_DEFAULT_SNOOZE_MINUTES, a as CLIP_EMBEDDING_STEP_ID, aa as EventCategory, ai as ruleKindOf, an as RetrainDismissedSchema, at as NC_ALARM_SYSTEM_EVENT_KINDS, b as COCO_TO_MACRO, bi as templateVarsFor, bn as SetTrackRelationInputSchema, br as isAudioClassName, bt as NC_GROUPING_MIN_SEC, c as readClusterModelPinStrict, ci as sensorRaisedOf, cn as SCENE_CONFIRM_DEFAULT_MAX_IMAGE_PX, ct as NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT, d as APPEARANCE_BLOCKS, di as subKindsOf, dn as SCENE_DEFAULT_CHECK_INTERVAL_SEC, dr as ensureAlarmProfiles, dt as NC_CLIP_RETENTION_MAX_SEC, ea as string, ei as rootSupplyServes, en as OpsLogEntrySchema, er as derivePostTriggeredAction, et as NC_ALARM_DEFAULT_PROFILE_ID, f as APPEARANCE_RESOLVES_AMBIGUITY_DEFAULT, fi as summarizeReview, fn as SCENE_DEFAULT_OBSERVATION_SPACING_SEC, fr as eventKindLabel, ft as NC_CONDITION_CATALOG, g as ArchivedDebugNoteSchema, gi as systemEventFilterApplies, gn as SCENE_RESET_RECAPTURES, gr as gifDeriveSpeed, gt as NC_CONSUMABLE_SYSTEM_EVENT_KINDS, h as AlarmArmModeSchema, hi as systemEventFamilyProblems, hn as SCENE_DIVERGED, hr as failureContributionCapability, ht as NC_CONSUMABLE_LOW_PERCENT_DEFAULT, ia as unknown, ii as ruleGroupingApplies, in as RebuildObjectEmbeddingsRefusalSchema, ir as deviceRemovalHookCapability, it as NC_ALARM_NOTIFY_FIELDS, j as EMBEDDING_MODEL_FAILED, ji as CamProfileSchema, jn as activateAlarmProfile, jr as isSystemDelivery, jt as NcAlarmSettingsPatchSchema, k as DeclaredDevices, ki as errMsg, kn as TrackSideSchema, kr as isRootSuppliableStepId, kt as NcAlarmSensorsInputSchema, l as resolveClusterModelPin, li as servedTemplateVars, ln as SCENE_CONFIRM_DEFAULT_TIMEOUT_MS, lt as NC_CLIP_POST_ROLL_DEFAULT_SEC, m as AUDIO_MACRO_LABELS, mi as systemEventDeliveryProblems, mn as SCENE_DEFAULT_UNCOVERED_POLICY, mr as faceGalleryCapability, mt as NC_CONFIRM_DEFAULT_TIMEOUT_MS, na as tuple, ni as ruleBelongsToAlarm$1, nn as RECORDING_EXPORT_MAX_READ_BYTES, nr as describeSystemEventDeliveryProblem, nt as NC_ALARM_DELAY_FIELDS, o as CLUSTER_MODEL_OWNER_ADDON_ID, oi as sceneMonitorCapability, on as RetrainOriginSchema, ot as NC_ALARM_TRIGGERED_MAX_SEC, p as ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT, pi as syncActiveAlarmProfileSettings, pn as SCENE_DEFAULT_QUIET_SECONDS, pr as evictionPolicyOfLocation, pt as NC_CONFIRM_DEFAULT_MAX_IMAGE_PX, q as MAX_BIRTH_DECISION_RECORDS, qi as literal, qn as cloneAlarmSettings, qr as renameAlarmProfile, qt as NcStateSummarySectionIdSchema, ra as union, ri as ruleDeviceCompatCapQueries, rn as RECORDING_SOURCE_CAMSTACK_ADDON, rr as describeSystemEventFamilyProblem, rt as NC_ALARM_DELAY_MAX_SEC, s as FACE_EMBEDDING_STEP_ID, si as secureActuationFor, sn as RetrainStatusSchema, sr as embeddingRefusalOf, st as NC_AUDIO_CONFIRM_HITS_DEFAULT, t as BUILTIN_CLIP_MODELS, ta as templateLiteral, ti as ruleAutoTriggersAlarm, tr as deriveRecordingMode, tt as NC_ALARM_DEFAULT_TRIGGERED_DURATION_SEC, u as APPEARANCE_BIN_COUNT, ui as storageOccupancyCapability, un as SCENE_DEFAULT_ANCHOR_THRESHOLD, ur as encodeVectorBase64, ut as NC_CLIP_PRE_ROLL_DEFAULT_SEC, v as BaseDevice, vi as systemEventSummarySplitOf, vn as SetTrackPurityInputSchema, vr as isAlarmControllableCap, vt as NC_GROUPING_DEFAULT_SEC, w as DEFAULT_DETAIL_CROP_CONVENTION, wi as DEFAULT_FIRST_SIGHTING_FRESHNESS_MS, wn as TimelapseRulePatchSchema, wr as isEventOwnerType, wt as NC_TANK_SYSTEM_EVENT_KINDS, x as ClearTrackRelationInputSchema, xi as vectorDimFromBase64, xn as TIMELAPSE_DENSE_FLOOR_SEC, xr as isDefaultAlarmProfileId, xt as NC_SENSOR_TRANSITION_KINDS, y as BirthDecisionRecordSchema, yi as templateCarriesSummary, yn as SetTrackPurityResultSchema, yr as isAppLinkBase, yt as NC_GROUPING_MAX_SEC, z as FULL_IMAGE_BBOX, zi as nodePin, zn as armRemovalReconcile, zr as occupancyScope, zt as NcRuleSchema } from "../clip-model-registry-BuM8eXlN.mjs";
1
+ import { $ as MediaFileKindEnum, $i as record, $n as deleteAlarmProfile, $t as NcTemplateVarDescriptorSchema, A as DeclaredDevices, Ai as errMsg, An as TrackSideSchema, Ar as isRootSuppliableStepId, At as NcAlarmSensorsInputSchema, B as FULL_IMAGE_BBOX, Bi as nodePin, Bn as armRemovalReconcile, Br as occupancyScope, Bt as NcRuleSchema, C as ClearTrackRelationResultSchema, Ci as viewerLinkBaseOf, Cn as TRACK_RELATIONS_DEFAULT_LIMIT, Cr as isDetectionMacroClass, Ct as NC_SNOOZE_MAX_MINUTES, D as DEFAULT_TIMELAPSE_PREVIEW_TEXT, Di as evaluateSensorEdge, Dn as TrackPuritySchema, Dr as isLabelSupplyStepId, Dt as NC_TEMPLATE_VARS, E as DEFAULT_EVENT_COLOR, Ei as canonicalHash, En as TimelapseRuleSchema, Er as isKnownTemplateVar, Et as NC_TAXONOMY, F as EVENT_DENSITY_BATCH_MAX, Fi as customAction, Fn as alarmPanelCapability, Fr as kebabToCamel, Ft as NcLegacyRuleActionSequenceSchema, G as ListTrackRelationsResultSchema, Gi as array, Gn as buildViewerLink, Gr as readDeviceStateFrom, Gt as NcSnoozeInputSchema, H as LABEL_SUPPLY_MACRO, Hi as sleep$1, Hn as audioMetricsCapability, Hr as pickFaceRescoreIntervalMinutes, Ht as NcRuleUpdateInputSchema, I as EVENT_KIND_BY_CAP, Ii as defineCustomActions, In as applyBlockingEdit, Ir as linkedStepOf, It as NcRuleActionSchema, J as MAX_BIRTH_DECISION_RECORDS, Ji as literal, Jn as cloneAlarmSettings, Jr as renameAlarmProfile, Jt as NcStateSummarySectionIdSchema, K as LockStateSchema, Ki as boolean, Kn as calendarEventLocalSpan, Kr as readMotionTriggeredBy, Kt as NcSnoozeSchema, L as EVENT_OWNER_TYPES, Li as defineRecordKinds, Ln as applyModeDelaysEdits, Lr as mayWriteToLocation, Lt as NcRuleActionsSchema, M as EMBEDDING_MODEL_FAILED, Mi as CamProfileSchema, Mn as activateAlarmProfile, Mr as isSystemDelivery, Mt as NcAlarmSettingsPatchSchema, N as EMBEDDING_REQUIREMENTS_FAILED, Ni as RECORD_MAX_DATA_BYTES, Nn as addonWidgetsSourceCapability, Nr as isSystemEventSummaryRule, Nt as NcConditionDescriptorSchema, O as DETECTION_MACRO_CLASSES, Oi as isSourceCap, On as TrackRelationKindSchema, Or as isMediaOwnerType, Ot as NcAlarmConfigSchema, P as EMBEDDING_REQUIREMENTS_UNAVAILABLE, Pi as createEvent, Pn as alarmDeviceSecureOnArm, Pr as isVectorIndexDimConflict, Pt as NcConditionsSchema, Q as MOTION_CLOSE_AFTER_MS, Qi as partialRecord, Qn as createAlarmProfile, Qr as resolveModeNotifyPolicy, Qt as NcTemplatePreviewSchema, R as EXPORT_DENSE_MAX_RANGES, Ri as hydrateSchema, Rn as applyNonBlockingEdit, Rr as memoizePinnedFfmpeg, Rt as NcRuleInputSchema, S as ClearTrackRelationInputSchema, Si as vectorDimFromBase64, Sn as TIMELAPSE_DENSE_FLOOR_SEC, Sr as isDefaultAlarmProfileId, St as NC_SENSOR_TRANSITION_KINDS, T as DEFAULT_DETAIL_CROP_CONVENTION, Ti as DEFAULT_FIRST_SIGHTING_FRESHNESS_MS, Tn as TimelapseRulePatchSchema, Tr as isEventOwnerType, Tt as NC_TANK_SYSTEM_EVENT_KINDS, U as LabelAttributionSchema, Ui as ZodObject, Un as audioModeOf, Ur as pipelineAnalyticsCapability, Ut as NcScheduleSchema, V as FailureCounters, Vn as assertTimelapseCadences, Vt as NcRuleTargetSchema, W as ListTrackRelationsInputSchema, Wi as _enum, Wn as buildEventKindDescriptor, Wr as plateGalleryCapability, Wt as NcSharedSequenceSchema, X as MAX_TRACK_PURITIES, Xi as number, Xn as coreBlockIdFromAddonId, Xr as resolveLocationMode, Xt as NcTaxonomySchema, Y as MAX_BIRTH_LATENCY_PROXY_MS, Yi as looseObject, Yn as consumableLowPercentOf, Yr as resolveClipSearchMinScore, Yt as NcSystemEventKindSchema, Z as MAX_TRACK_RELATIONS, Zi as object, Zn as cosineSimilarity$1, Zr as resolveModeDelays, Zt as NcTemplatePreviewInputSchema, _ as BIRTH_DECISION_DEFAULT_LIMIT, _i as systemEventFilterApplies, _n as SCENE_RESET_RECAPTURES, _r as gifDeriveSpeed, _t as NC_CONSUMABLE_SYSTEM_EVENT_KINDS, a as CLIP_EMBEDDING_STEP_ID, aa as unknown, ai as ruleGroupingApplies, an as RebuildObjectEmbeddingsRefusalSchema, ar as deviceRemovalHookCapability, at as NC_ALARM_NOTIFY_FIELDS, b as BucketAccumulator, bi as templateCarriesSummary, bn as SetTrackPurityResultSchema, br as isAppLinkBase, bt as NC_GROUPING_MAX_SEC, c as readClusterModelPinStrict, ci as secureActuationFor, cn as RetrainStatusSchema, cr as embeddingRefusalOf, ct as NC_AUDIO_CONFIRM_HITS_DEFAULT, d as APPEARANCE_BLOCKS, di as storageOccupancyCapability, dn as SCENE_DEFAULT_ANCHOR_THRESHOLD, dr as encodeVectorBase64, dt as NC_CLIP_PRE_ROLL_DEFAULT_SEC, ea as strictObject, ei as retrainRevisionConflictMessage, en as OPS_LOG_DEFAULT_LIMIT, er as deriveDetailCropRect, et as MotionTriggeredBySchema, f as APPEARANCE_RESOLVES_AMBIGUITY_DEFAULT, fi as subKindsOf, fn as SCENE_DEFAULT_CHECK_INTERVAL_SEC, fr as ensureAlarmProfiles, ft as NC_CLIP_RETENTION_MAX_SEC, g as ArchivedDebugNoteSchema, gi as systemEventFamilyProblems, gn as SCENE_DIVERGED, gr as failureContributionCapability, gt as NC_CONSUMABLE_LOW_PERCENT_DEFAULT, h as AlarmArmModeSchema, hi as systemEventDeliveryProblems, hn as SCENE_DEFAULT_UNCOVERED_POLICY, hr as faceGalleryCapability, ht as NC_CONFIRM_DEFAULT_TIMEOUT_MS, ia as union, ii as ruleDeviceCompatCapQueries, in as RECORDING_SOURCE_CAMSTACK_ADDON, ir as describeSystemEventFamilyProblem, it as NC_ALARM_DELAY_MAX_SEC, j as DetectionSourceSchema, ji as BaseAddon, jn as TrackSourceSchema, jr as isScheduleActive, jt as NcAlarmSensorsSchema, k as DETECTION_PIPELINE_CAP_NAME, ki as DeviceType, kn as TrackRelationSchema, kr as isRetiredClearKey, kt as NcAlarmPostTriggeredActionSchema, l as resolveClusterModelPin, li as sensorRaisedOf, ln as SCENE_CONFIRM_DEFAULT_MAX_IMAGE_PX, lt as NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT, m as AUDIO_MACRO_LABELS, mi as syncActiveAlarmProfileSettings, mn as SCENE_DEFAULT_QUIET_SECONDS, mr as evictionPolicyOfLocation, mt as NC_CONFIRM_DEFAULT_MAX_IMAGE_PX, na as templateLiteral, ni as ruleAutoTriggersAlarm, nr as deriveRecordingMode, nt as NC_ALARM_DEFAULT_TRIGGERED_DURATION_SEC, o as CLUSTER_MODEL_OWNER_ADDON_ID, oa as EventCategory, oi as ruleKindOf, on as RetrainDismissedSchema, ot as NC_ALARM_SYSTEM_EVENT_KINDS, p as ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT, pi as summarizeReview, pn as SCENE_DEFAULT_OBSERVATION_SPACING_SEC, pr as eventKindLabel, pt as NC_CONDITION_CATALOG, q as MAX_ARCHIVED_DEBUG_NOTES, qi as discriminatedUnion, qn as classifyRetrainReview, qr as readTimelapseGeneratedAt, qt as NcSnoozeSuppressedSchema, ra as tuple, ri as ruleBelongsToAlarm$1, rn as RECORDING_EXPORT_MAX_READ_BYTES, rr as describeSystemEventDeliveryProblem, rt as NC_ALARM_DELAY_FIELDS, s as FACE_EMBEDDING_STEP_ID, si as sceneMonitorCapability, sn as RetrainOriginSchema, st as NC_ALARM_TRIGGERED_MAX_SEC, t as BUILTIN_CLIP_MODELS, ta as string, ti as rootSupplyServes, tn as OpsLogEntrySchema, tr as derivePostTriggeredAction, tt as NC_ALARM_DEFAULT_PROFILE_ID, u as APPEARANCE_BIN_COUNT, ui as servedTemplateVars, un as SCENE_CONFIRM_DEFAULT_TIMEOUT_MS, ut as NC_CLIP_POST_ROLL_DEFAULT_SEC, v as BaseDevice, vi as systemEventSummaryScheduleOf, vn as SceneMonitorSchema, vr as gifFromMp4Args, vt as NC_DEFAULT_SNOOZE_MINUTES, w as CoverStateSchema, wi as zoneAnalyticsCapability, wn as TimelapseRuleInputSchema, wr as isEventKindLabelKey, wt as NC_SYSTEM_EVENT_KIND_GROUP_SPECS, x as COCO_TO_MACRO, xi as templateVarsFor, xn as SetTrackRelationInputSchema, xr as isAudioClassName, xt as NC_GROUPING_MIN_SEC, y as BirthDecisionRecordSchema, yi as systemEventSummarySplitOf, yn as SetTrackPurityInputSchema, yr as isAlarmControllableCap, yt as NC_GROUPING_DEFAULT_SEC, z as FIRST_LEVEL_MACRO_CLASSES, zi as isDeviceScopedCap, zn as applySecureOnArmEdit, zr as notificationRulesCapability, zt as NcRulePatchSchema } from "../clip-model-registry-lQ7QWjLf.mjs";
2
2
  import { t as __exportAll } from "../embedding-encoder/index.mjs";
3
3
  import * as fs$1 from "node:fs";
4
4
  import { createWriteStream, promises } from "node:fs";
@@ -6930,17 +6930,6 @@ function ncAudioSampleFromFrame(frame, timestampMs, floor) {
6930
6930
  ...frame.classifyOutcome !== void 0 ? { classifyOutcome: frame.classifyOutcome } : {}
6931
6931
  };
6932
6932
  }
6933
- /** The level-path audio row for one frame — the one row kind with no label to explain it. */
6934
- function levelAudioEventDraft(deviceId, timestamp, frame) {
6935
- return {
6936
- deviceId,
6937
- timestamp,
6938
- kind: "audio",
6939
- rms: frame.level?.rms ?? 0,
6940
- dbfs: frame.level?.dbfs ?? 0,
6941
- ...frame.classifyOutcome !== void 0 ? { classifyOutcome: frame.classifyOutcome } : {}
6942
- };
6943
- }
6944
6933
  //#endregion
6945
6934
  //#region src/pipeline-analytics/scene/condition-resolver.ts
6946
6935
  var DAY = "day";
@@ -10922,7 +10911,7 @@ var NC_LIVENESS_SPEC = {
10922
10911
  writeMode: "write-behind",
10923
10912
  keyOf: (row) => row.subject,
10924
10913
  toValue: rowToValue$1,
10925
- fromRecord: recordToRow$2,
10914
+ fromRecord: recordToRow$1,
10926
10915
  equalFact: (held, incoming) => held.state === incoming.state,
10927
10916
  deviceIdOf: (row) => row.deviceId
10928
10917
  };
@@ -11109,7 +11098,7 @@ function rowToValue$1(row) {
11109
11098
  * (silent) rather than hydrating a state nothing can ever equal, which would
11110
11099
  * make every future event a phantom flip.
11111
11100
  */
11112
- function recordToRow$2(subject, data) {
11101
+ function recordToRow$1(subject, data) {
11113
11102
  if (subject.length === 0) return null;
11114
11103
  const state = data["state"];
11115
11104
  if (state !== "online" && state !== "offline") return null;
@@ -12590,7 +12579,7 @@ var NC_OCCUPANCY_SPEC = {
12590
12579
  writeMode: "write-through",
12591
12580
  keyOf: (row) => row.key,
12592
12581
  toValue: rowToValue,
12593
- fromRecord: recordToRow$1,
12582
+ fromRecord: recordToRow,
12594
12583
  deviceIdOf: (row) => row.deviceId
12595
12584
  };
12596
12585
  var OccupancyStore = class {
@@ -12667,7 +12656,7 @@ function rowToValue(row) {
12667
12656
  * {@link parseOccupancyKey} rejects — so the caller skips it (cold re-observe)
12668
12657
  * rather than hydrating a mis-parsed scope.
12669
12658
  */
12670
- function recordToRow$1(key, data) {
12659
+ function recordToRow(key, data) {
12671
12660
  const scope = parseOccupancyKey(key);
12672
12661
  if (scope === null) return null;
12673
12662
  const deviceId = Number(data["deviceId"]);
@@ -50520,7 +50509,7 @@ function previewBlurSigma(frameWidth) {
50520
50509
  }
50521
50510
  /** Break a word too long for one line into line-width pieces. Without this a
50522
50511
  * single 200-character token wraps to nothing and overflows both edges. */
50523
- function chunk$2(word, size) {
50512
+ function chunk$1(word, size) {
50524
50513
  const pieces = [];
50525
50514
  for (let i = 0; i < word.length; i += size) pieces.push(word.slice(i, i + size));
50526
50515
  return pieces;
@@ -50528,7 +50517,7 @@ function chunk$2(word, size) {
50528
50517
  /** Greedy word wrap at a character budget — the only measurement available,
50529
50518
  * since librsvg lays the text out long after this string is written. */
50530
50519
  function wrapLines(text, maxChars) {
50531
- return text.split(" ").filter((w) => w.length > 0).reduce((lines, word) => (word.length > maxChars ? chunk$2(word, maxChars) : [word]).reduce((acc, piece) => {
50520
+ return text.split(" ").filter((w) => w.length > 0).reduce((lines, word) => (word.length > maxChars ? chunk$1(word, maxChars) : [word]).reduce((acc, piece) => {
50532
50521
  const last = acc.at(-1);
50533
50522
  if (last === void 0) return [piece];
50534
50523
  const merged = `${last} ${piece}`;
@@ -60438,7 +60427,7 @@ async function readRescoreFingerprint(ports) {
60438
60427
  clusterModelId
60439
60428
  };
60440
60429
  }
60441
- function chunk$1(items, size) {
60430
+ function chunk(items, size) {
60442
60431
  const out = [];
60443
60432
  for (let i = 0; i < items.length; i += size) out.push(items.slice(i, i + size));
60444
60433
  return out;
@@ -60560,7 +60549,7 @@ var FaceRescoreJob = class {
60560
60549
  fingerprint: fingerprint.combined
60561
60550
  });
60562
60551
  const paramsByDevice = /* @__PURE__ */ new Map();
60563
- for (const batchIds of chunk$1(ids, RESCORE_BATCH_SIZE)) {
60552
+ for (const batchIds of chunk(ids, RESCORE_BATCH_SIZE)) {
60564
60553
  if (this.stopped) throw new Error("stopped before completion");
60565
60554
  const storeStart = this.ports.now();
60566
60555
  const batch = await this.ports.loadRescoreBatch(batchIds);
@@ -98265,431 +98254,6 @@ var SweepCursorStore = class SweepCursorStore {
98265
98254
  }
98266
98255
  };
98267
98256
  //#endregion
98268
- //#region src/durable/lts-aggregator.ts
98269
- /** Wall-clock bucket width. Five minutes, matching HA's statistics tier. */
98270
- var LTS_BUCKET_MS = 5 * 6e4;
98271
- /**
98272
- * Row cap per (subject, series, scope) — one year of five-minute buckets, the
98273
- * same number HA's own docs use. At ~60 bytes a row that is ~6 MB per series
98274
- * per camera-year, against a `media` table already measured in hundreds of MB.
98275
- */
98276
- var LTS_MAX_ROWS_PER_SERIES = 105120;
98277
- /** Buckets written per transaction — bounds one statement, not the flush. */
98278
- var FLUSH_BATCH = 200;
98279
- /** How often the row cap is enforced. Rarely: it is a bound, not a deadline. */
98280
- var CAP_SWEEP_INTERVAL_MS = 6 * 36e5;
98281
- /**
98282
- * The row's identity IS its four key columns (D871): a composite
98283
- * `primaryKey` + `WITHOUT ROWID`, so the table is its own index and there is no
98284
- * TEXT `id` repeating what the row already says. The old layout kept
98285
- * `<subject>|<series>|<scope>|<bucketStart>` as a TEXT primary key beside the
98286
- * four columns — 85 MB of rows plus a 44 MB autoindex for 1.07 M rows. A
98287
- * composite-key collection is written with `upsertMany` (a bucket flushed twice
98288
- * replaces itself) and read with `query` / `count` / `deleteWhere`; the calls
98289
- * that address one row by id are refused by the engine.
98290
- */
98291
- var LTS_KEY_COLUMNS = [
98292
- "subject",
98293
- "series",
98294
- "scope",
98295
- "bucketStart"
98296
- ];
98297
- var LTS_COLUMNS = [
98298
- (
98299
- /** The camera id, or the node id. One column, because every query is
98300
- * "this thing over time" and the thing is one or the other. */
98301
- {
98302
- name: "subject",
98303
- type: "TEXT"
98304
- }),
98305
- (
98306
- /** Numeric mirror of `subject` for camera rows, so a per-camera question is
98307
- * answered by an integer index — every log line and every query about a
98308
- * device in this repo is keyed by the numeric id. `NULL` for node rows. */
98309
- {
98310
- name: "deviceId",
98311
- type: "INTEGER"
98312
- }),
98313
- {
98314
- name: "series",
98315
- type: "TEXT"
98316
- },
98317
- (
98318
- /** Sub-scope within a series: a zoneId for occupancy, `''` otherwise. */
98319
- {
98320
- name: "scope",
98321
- type: "TEXT"
98322
- }),
98323
- (
98324
- /** Bucket start, wall-clock aligned to {@link LTS_BUCKET_MS}. */
98325
- {
98326
- name: "bucketStart",
98327
- type: "INTEGER"
98328
- }),
98329
- {
98330
- name: "samples",
98331
- type: "INTEGER",
98332
- notNull: true
98333
- },
98334
- {
98335
- name: "sum",
98336
- type: "REAL",
98337
- notNull: true
98338
- },
98339
- {
98340
- name: "min",
98341
- type: "REAL",
98342
- notNull: true
98343
- },
98344
- {
98345
- name: "max",
98346
- type: "REAL",
98347
- notNull: true
98348
- }
98349
- ];
98350
- /**
98351
- * The primary key serves every per-subject read (`subject, series, scope` then a
98352
- * `bucketStart` range, already in bucket order); this index serves the read that
98353
- * names a series without a subject. The old `deviceId` index went with the TEXT
98354
- * id: nothing queries a series by the numeric mirror.
98355
- */
98356
- var LTS_INDEXES = [{
98357
- name: "idx_lts_series_bucket",
98358
- columns: ["series", "bucketStart"]
98359
- }];
98360
- function ltsBucketStart(at, bucketMs = LTS_BUCKET_MS) {
98361
- return Math.floor(at / bucketMs) * bucketMs;
98362
- }
98363
- var LtsAggregator = class {
98364
- open = /* @__PURE__ */ new Map();
98365
- /** Every (subject, series, scope) that has produced a row in this process —
98366
- * the groups the cap sweep has any reason to look at. */
98367
- groups = /* @__PURE__ */ new Set();
98368
- lastCapSweepAt = 0;
98369
- collection;
98370
- store;
98371
- logger;
98372
- nowFn;
98373
- bucketMs;
98374
- maxRows;
98375
- constructor(deps) {
98376
- this.collection = deps.collection;
98377
- this.store = deps.store;
98378
- this.logger = deps.logger;
98379
- this.nowFn = deps.now ?? (() => Date.now());
98380
- this.bucketMs = deps.bucketMs ?? LTS_BUCKET_MS;
98381
- this.maxRows = deps.maxRowsPerSeries ?? LTS_MAX_ROWS_PER_SERIES;
98382
- }
98383
- static declare(store, collection) {
98384
- return store.declareCollection.mutate({
98385
- collection,
98386
- columns: [...LTS_COLUMNS],
98387
- primaryKey: [...LTS_KEY_COLUMNS],
98388
- withoutRowid: true,
98389
- indexes: [...LTS_INDEXES]
98390
- });
98391
- }
98392
- /**
98393
- * Record one observation. Synchronous, allocation-free after the first
98394
- * sample of a bucket, and it cannot throw — it sits on paths that are
98395
- * already producing the value for another reason and must not learn a new
98396
- * failure mode.
98397
- *
98398
- * A non-finite value is DROPPED rather than folded in: one `NaN` would make
98399
- * `sum`, `min` and `max` all `NaN` for the whole bucket, turning a skewed
98400
- * row into a meaningless one.
98401
- */
98402
- note(input) {
98403
- if (!Number.isFinite(input.value)) return;
98404
- const at = input.at ?? this.nowFn();
98405
- const scope = input.scope ?? "";
98406
- const bucketStart = ltsBucketStart(at, this.bucketMs);
98407
- const key = rowId(input.subject, input.series, scope, bucketStart);
98408
- const held = this.open.get(key);
98409
- if (held === void 0) {
98410
- this.open.set(key, {
98411
- subject: input.subject,
98412
- ...input.deviceId !== void 0 ? { deviceId: input.deviceId } : {},
98413
- series: input.series,
98414
- scope,
98415
- bucketStart,
98416
- samples: 1,
98417
- sum: input.value,
98418
- min: input.value,
98419
- max: input.value
98420
- });
98421
- return;
98422
- }
98423
- held.samples += 1;
98424
- held.sum += input.value;
98425
- if (input.value < held.min) held.min = input.value;
98426
- if (input.value > held.max) held.max = input.value;
98427
- }
98428
- /** Buckets currently accumulating — diagnostics, and what a flush would write. */
98429
- openBuckets() {
98430
- return [...this.open.values()].map(toRow);
98431
- }
98432
- /**
98433
- * Write every bucket that has CLOSED (its window ended at or before `now`)
98434
- * and drop it from RAM. Returns the number of rows written.
98435
- *
98436
- * The current bucket is deliberately left alone: writing it early would mean
98437
- * rewriting it on the next tick, which turns one row into up to sixty and
98438
- * offers every one of them to the checkpoint lottery (D96).
98439
- */
98440
- async flushDue(now = this.nowFn()) {
98441
- const currentBucket = ltsBucketStart(now, this.bucketMs);
98442
- const due = [...this.open.values()].filter((b) => b.bucketStart < currentBucket);
98443
- if (due.length === 0) {
98444
- await this.maybeSweepCap(now);
98445
- return 0;
98446
- }
98447
- let written = 0;
98448
- for (const batch of chunk(due, FLUSH_BATCH)) {
98449
- written += await this.writeBatch(batch);
98450
- for (const bucket of batch) this.open.delete(rowId(bucket.subject, bucket.series, bucket.scope, bucket.bucketStart));
98451
- }
98452
- await this.maybeSweepCap(now);
98453
- return written;
98454
- }
98455
- /**
98456
- * Upsert one batch in a single transaction. If the batch is refused as a
98457
- * whole (all-or-nothing), each bucket is retried alone so one bad row costs
98458
- * one interval, not forty. Returns the number of rows written.
98459
- */
98460
- async writeBatch(batch) {
98461
- try {
98462
- await this.upsert(batch);
98463
- for (const bucket of batch) this.groups.add(groupKey(bucket.subject, bucket.series, bucket.scope));
98464
- return batch.length;
98465
- } catch (err) {
98466
- if (batch.length > 1) {
98467
- let written = 0;
98468
- for (const bucket of batch) written += await this.writeBatch([bucket]);
98469
- return written;
98470
- }
98471
- const bucket = batch[0];
98472
- this.logger.warn("lts bucket write failed — this interval will be missing", {
98473
- ...bucket?.deviceId !== void 0 ? { tags: { deviceId: bucket.deviceId } } : {},
98474
- meta: {
98475
- collection: this.collection,
98476
- series: bucket?.series,
98477
- subject: bucket?.subject,
98478
- bucketStart: bucket?.bucketStart,
98479
- error: String(err)
98480
- }
98481
- });
98482
- return 0;
98483
- }
98484
- }
98485
- async upsert(batch) {
98486
- await this.store.upsertMany.mutate({
98487
- collection: this.collection,
98488
- conflict: [...LTS_KEY_COLUMNS],
98489
- records: batch.map((bucket) => ({ data: {
98490
- subject: bucket.subject,
98491
- deviceId: bucket.deviceId ?? null,
98492
- series: bucket.series,
98493
- scope: bucket.scope,
98494
- bucketStart: bucket.bucketStart,
98495
- samples: bucket.samples,
98496
- sum: bucket.sum,
98497
- min: bucket.min,
98498
- max: bucket.max
98499
- } }))
98500
- });
98501
- }
98502
- /** Read closed buckets back. The read surface every chart will use. */
98503
- async read(query = {}) {
98504
- const where = {};
98505
- if (query.series !== void 0) where["series"] = query.series;
98506
- if (query.subject !== void 0) where["subject"] = query.subject;
98507
- if (query.scope !== void 0) where["scope"] = query.scope;
98508
- const records = await this.store.query.query({
98509
- collection: this.collection,
98510
- filter: {
98511
- ...Object.keys(where).length > 0 ? { where } : {},
98512
- ...query.from !== void 0 || query.to !== void 0 ? { whereBetween: { bucketStart: [query.from ?? 0, query.to ?? Number.MAX_SAFE_INTEGER] } } : {},
98513
- orderBy: {
98514
- field: "bucketStart",
98515
- direction: "asc"
98516
- },
98517
- limit: query.limit ?? 5e3
98518
- }
98519
- });
98520
- const rows = [];
98521
- for (const record of records) {
98522
- const row = recordToRow(record.data);
98523
- if (row !== null) rows.push(row);
98524
- }
98525
- return rows;
98526
- }
98527
- /**
98528
- * Enforce the per-(subject, series, scope) row cap, at most once every six
98529
- * hours. Only groups this process has written to are examined: a group with
98530
- * no new rows cannot have crossed a cap it was under.
98531
- */
98532
- async maybeSweepCap(now) {
98533
- if (now - this.lastCapSweepAt < CAP_SWEEP_INTERVAL_MS) return;
98534
- this.lastCapSweepAt = now;
98535
- for (const group of this.groups) {
98536
- const [subject, series, scope] = group.split("\0");
98537
- if (subject === void 0 || series === void 0 || scope === void 0) continue;
98538
- const where = {
98539
- subject,
98540
- series,
98541
- scope
98542
- };
98543
- try {
98544
- const excess = await this.store.count.query({
98545
- collection: this.collection,
98546
- filter: { where }
98547
- }) - this.maxRows;
98548
- if (excess <= 0) continue;
98549
- const cutoff = (await this.store.query.query({
98550
- collection: this.collection,
98551
- filter: {
98552
- where,
98553
- orderBy: {
98554
- field: "bucketStart",
98555
- direction: "asc"
98556
- },
98557
- limit: excess
98558
- }
98559
- })).at(-1)?.data["bucketStart"];
98560
- if (typeof cutoff !== "number") continue;
98561
- const { deleted } = await this.store.deleteWhere.mutate({
98562
- collection: this.collection,
98563
- filter: {
98564
- where,
98565
- whereBetween: { bucketStart: [0, cutoff] }
98566
- }
98567
- });
98568
- this.logger.info("lts row cap enforced", { meta: {
98569
- collection: this.collection,
98570
- series,
98571
- subject,
98572
- deleted,
98573
- cap: this.maxRows
98574
- } });
98575
- } catch (err) {
98576
- this.logger.warn("lts row cap sweep failed — the series keeps growing this cycle", { meta: {
98577
- collection: this.collection,
98578
- series,
98579
- subject,
98580
- error: String(err)
98581
- } });
98582
- }
98583
- }
98584
- }
98585
- };
98586
- function chunk(items, size) {
98587
- const out = [];
98588
- for (let i = 0; i < items.length; i += size) out.push(items.slice(i, i + size));
98589
- return out;
98590
- }
98591
- function groupKey(subject, series, scope) {
98592
- return `${subject}${series}${scope}`;
98593
- }
98594
- function rowId(subject, series, scope, bucketStart) {
98595
- return `${subject}|${series}|${scope}|${bucketStart}`;
98596
- }
98597
- function toRow(bucket) {
98598
- return {
98599
- subject: bucket.subject,
98600
- ...bucket.deviceId !== void 0 ? { deviceId: bucket.deviceId } : {},
98601
- series: bucket.series,
98602
- scope: bucket.scope,
98603
- bucketStart: bucket.bucketStart,
98604
- samples: bucket.samples,
98605
- sum: bucket.sum,
98606
- min: bucket.min,
98607
- max: bucket.max
98608
- };
98609
- }
98610
- /** Structural validation on read. A malformed row is skipped, never charted. */
98611
- function recordToRow(data) {
98612
- const subject = data["subject"];
98613
- const series = data["series"];
98614
- const scope = data["scope"];
98615
- if (typeof subject !== "string" || typeof series !== "string") return null;
98616
- const bucketStart = Number(data["bucketStart"]);
98617
- const samples = Number(data["samples"]);
98618
- const sum = Number(data["sum"]);
98619
- const min = Number(data["min"]);
98620
- const max = Number(data["max"]);
98621
- if (![
98622
- bucketStart,
98623
- samples,
98624
- sum,
98625
- min,
98626
- max
98627
- ].every((n) => Number.isFinite(n))) return null;
98628
- const rawDeviceId = data["deviceId"];
98629
- const deviceId = typeof rawDeviceId === "number" && Number.isFinite(rawDeviceId) ? rawDeviceId : void 0;
98630
- return {
98631
- subject,
98632
- ...deviceId !== void 0 ? { deviceId } : {},
98633
- series,
98634
- scope: typeof scope === "string" ? scope : "",
98635
- bucketStart,
98636
- samples,
98637
- sum,
98638
- min,
98639
- max
98640
- };
98641
- }
98642
- //#endregion
98643
- //#region src/pipeline-analytics/store/lts-store.ts
98644
- /**
98645
- * @durable class=ledger owner=pipeline-analytics
98646
- * write="one row per (camera, series, zone, 5-min bucket), written ONCE when the bucket closes; a camera with no sample writes nothing"
98647
- * retention="row CAP per (subject, series, scope) — 105,120 rows ≈ one year of 5-minute buckets. Deliberately not an age sweep: an LTS row has no owner to be orphaned from and no clock but its own (D61)."
98648
- */
98649
- var LTS_COLLECTION = "pipeline-analytics:stats-5m-v2";
98650
- var AnalyticsLts = class {
98651
- lts;
98652
- constructor(deps) {
98653
- this.lts = new LtsAggregator({
98654
- collection: LTS_COLLECTION,
98655
- store: deps.store,
98656
- logger: deps.logger,
98657
- ...deps.now !== void 0 ? { now: deps.now } : {}
98658
- });
98659
- }
98660
- static declare(store) {
98661
- return LtsAggregator.declare(store, LTS_COLLECTION);
98662
- }
98663
- /**
98664
- * One camera sample. Synchronous and infallible by contract — every call
98665
- * site is a path that already produced the value for another reason, and
98666
- * none of them may learn a new failure mode because a chart exists.
98667
- */
98668
- note(series, deviceId, value, at, scope) {
98669
- this.lts.note({
98670
- subject: String(deviceId),
98671
- deviceId,
98672
- series,
98673
- ...scope !== void 0 ? { scope } : {},
98674
- value,
98675
- ...at !== void 0 ? { at } : {}
98676
- });
98677
- }
98678
- /** Write every bucket that has closed. Driven by the addon's flush timer. */
98679
- flushDue(now) {
98680
- return this.lts.flushDue(now);
98681
- }
98682
- /** The read surface charts will use. */
98683
- read(query) {
98684
- return this.lts.read(query);
98685
- }
98686
- /** Buckets still accumulating — makes "is it running" answerable at once,
98687
- * instead of after five minutes of silence. */
98688
- openBuckets() {
98689
- return this.lts.openBuckets();
98690
- }
98691
- };
98692
- //#endregion
98693
98257
  //#region src/pipeline-analytics/store/identity-store.ts
98694
98258
  /**
98695
98259
  * IdentityStore — per-person identity registry for face recognition.
@@ -101733,13 +101297,6 @@ var ANALYTICS_COLLECTIONS = [
101733
101297
  why: "a phantom cell is a property of the SCENE — \"this patch of pixels keeps producing 4-second motionless tracks\" — not of any track. The tracks that produced it are dead by construction (that is the entire premise: the stationary registry cannot see them because they never live long enough to be promoted), so there is no owner it could be orphaned from. Its bound is its own 24h close window plus a 512-cell-per-device cap, both enforced by the registry on write — deliberately not an age sweep, which would be a second clock (D61)."
101734
101298
  }
101735
101299
  },
101736
- {
101737
- collection: LTS_COLLECTION,
101738
- classification: {
101739
- kind: "never-orphaned",
101740
- why: "a five-minute statistics row summarises an INTERVAL, not an entity — there is no owner it can be orphaned from. Its bound is a ROW CAP per (subject, series, scope) enforced by the aggregator itself (105,120 rows ≈ one year), deliberately not an age sweep: D61 collapsed ten disagreeing age clocks into one, and an LTS series has no clock but its own."
101741
- }
101742
- },
101743
101300
  {
101744
101301
  collection: RETRAIN_ANNOTATIONS_COLLECTION,
101745
101302
  classification: {
@@ -107043,6 +106600,78 @@ Object.freeze({
107043
106600
  "path": "online",
107044
106601
  "valueType": "boolean"
107045
106602
  }],
106603
+ "dishwasher": [
106604
+ {
106605
+ "path": "state",
106606
+ "valueType": "enum",
106607
+ "enumValues": [
106608
+ "idle",
106609
+ "running",
106610
+ "paused",
106611
+ "finished",
106612
+ "error",
106613
+ "unavailable"
106614
+ ]
106615
+ },
106616
+ {
106617
+ "path": "program",
106618
+ "valueType": "string"
106619
+ },
106620
+ {
106621
+ "path": "remainingMinutes",
106622
+ "valueType": "number"
106623
+ },
106624
+ {
106625
+ "path": "progressPercent",
106626
+ "valueType": "number"
106627
+ },
106628
+ {
106629
+ "path": "doorOpen",
106630
+ "valueType": "boolean"
106631
+ },
106632
+ {
106633
+ "path": "remoteStartAllowed",
106634
+ "valueType": "boolean"
106635
+ },
106636
+ {
106637
+ "path": "powerOn",
106638
+ "valueType": "boolean"
106639
+ },
106640
+ {
106641
+ "path": "saltLevel",
106642
+ "valueType": "enum",
106643
+ "enumValues": [
106644
+ "ok",
106645
+ "low",
106646
+ "empty"
106647
+ ]
106648
+ },
106649
+ {
106650
+ "path": "rinseAidLevel",
106651
+ "valueType": "enum",
106652
+ "enumValues": [
106653
+ "ok",
106654
+ "low",
106655
+ "empty"
106656
+ ]
106657
+ },
106658
+ {
106659
+ "path": "halfLoad",
106660
+ "valueType": "boolean"
106661
+ },
106662
+ {
106663
+ "path": "hygienePlus",
106664
+ "valueType": "boolean"
106665
+ },
106666
+ {
106667
+ "path": "errorCode",
106668
+ "valueType": "number"
106669
+ },
106670
+ {
106671
+ "path": "errorLabel",
106672
+ "valueType": "string"
106673
+ }
106674
+ ],
107046
106675
  "doorbell": [{
107047
106676
  "path": "lastPressedAt",
107048
106677
  "valueType": "number"
@@ -107133,6 +106762,10 @@ Object.freeze({
107133
106762
  "path": "detected",
107134
106763
  "valueType": "boolean"
107135
106764
  }],
106765
+ "heating-valve": [{
106766
+ "path": "position",
106767
+ "valueType": "number"
106768
+ }],
107136
106769
  "humidifier": [
107137
106770
  {
107138
106771
  "path": "on",
@@ -110561,6 +110194,189 @@ var MigrationMarkerStore = class MigrationMarkerStore {
110561
110194
  };
110562
110195
  };
110563
110196
  //#endregion
110197
+ //#region src/pipeline-analytics/store/analytics-history-keys.ts
110198
+ /** Declared addon series keys (D850). */
110199
+ var ANALYTICS_HISTORY_BUCKET_SERIES = {
110200
+ motion: "addon:pipeline-analytics/motion",
110201
+ "audio-dbfs": "addon:pipeline-analytics/audio-dbfs",
110202
+ occupancy: "addon:pipeline-analytics/occupancy"
110203
+ };
110204
+ var ANALYTICS_AUDIO_LEVEL_KEY = "addon:pipeline-analytics/audio-level";
110205
+ /** Map the public cap enum to the device-history key (read path). */
110206
+ function historyKeyForLtsSeries(series) {
110207
+ if (series === "battery") return "cap:battery.percentage";
110208
+ return ANALYTICS_HISTORY_BUCKET_SERIES[series];
110209
+ }
110210
+ //#endregion
110211
+ //#region src/pipeline-analytics/store/analytics-history-producer.ts
110212
+ var BUCKET_SERIES_META = [
110213
+ {
110214
+ name: "motion",
110215
+ displayName: "Motion events (region count)"
110216
+ },
110217
+ {
110218
+ name: "audio-dbfs",
110219
+ displayName: "Audio noise baseline (dBFS)",
110220
+ unit: "dBFS"
110221
+ },
110222
+ {
110223
+ name: "occupancy",
110224
+ displayName: "Occupancy count"
110225
+ }
110226
+ ];
110227
+ var AUDIO_LEVEL_SERIES = {
110228
+ name: "audio-level",
110229
+ displayName: "Audio level (dBFS)",
110230
+ unit: "dBFS"
110231
+ };
110232
+ var AnalyticsHistoryProducer = class {
110233
+ accum = new BucketAccumulator();
110234
+ deviceHistory;
110235
+ logger;
110236
+ nowFn;
110237
+ declared = false;
110238
+ constructor(deps) {
110239
+ this.deviceHistory = deps.deviceHistory;
110240
+ this.logger = deps.logger;
110241
+ this.nowFn = deps.now ?? (() => Date.now());
110242
+ }
110243
+ async declare() {
110244
+ if (this.declared) return;
110245
+ for (const meta of BUCKET_SERIES_META) await this.deviceHistory.declareSeries({
110246
+ name: meta.name,
110247
+ subjectKind: "device",
110248
+ kind: "gauge",
110249
+ displayName: meta.displayName,
110250
+ ingest: "buckets",
110251
+ ...meta.unit !== void 0 ? { unit: meta.unit } : {}
110252
+ });
110253
+ await this.deviceHistory.declareSeries({
110254
+ name: AUDIO_LEVEL_SERIES.name,
110255
+ subjectKind: "device",
110256
+ kind: "gauge",
110257
+ displayName: AUDIO_LEVEL_SERIES.displayName,
110258
+ unit: AUDIO_LEVEL_SERIES.unit,
110259
+ ingest: "points"
110260
+ });
110261
+ this.declared = true;
110262
+ }
110263
+ note(series, deviceId, value, at, scope) {
110264
+ const key = ANALYTICS_HISTORY_BUCKET_SERIES[series];
110265
+ this.accum.note(key, {
110266
+ kind: "device",
110267
+ deviceId
110268
+ }, scope ?? "", value, at ?? this.nowFn());
110269
+ }
110270
+ recordAudioLevel(deviceId, dbfs, at) {
110271
+ const record = this.deviceHistory.record;
110272
+ if (record === void 0) return;
110273
+ record.call(this.deviceHistory, { points: [{
110274
+ key: ANALYTICS_AUDIO_LEVEL_KEY,
110275
+ subject: {
110276
+ kind: "device",
110277
+ deviceId
110278
+ },
110279
+ scope: "",
110280
+ ts: at,
110281
+ value: dbfs
110282
+ }] }).catch((err) => {
110283
+ this.logger.warn("audio level history point not stored", {
110284
+ tags: { deviceId },
110285
+ meta: { error: err instanceof Error ? err.message : String(err) }
110286
+ });
110287
+ });
110288
+ }
110289
+ async flushDue(now) {
110290
+ const at = now ?? this.nowFn();
110291
+ const closed = this.accum.takeClosed(at);
110292
+ if (closed.length === 0) return 0;
110293
+ try {
110294
+ return (await this.deviceHistory.recordBuckets({ buckets: closed })).accepted;
110295
+ } catch (err) {
110296
+ const dropped = this.accum.requeue(closed);
110297
+ this.logger.warn("analytics history bucket flush failed — requeued", { meta: {
110298
+ buckets: closed.length,
110299
+ dropped: dropped.length,
110300
+ error: err instanceof Error ? err.message : String(err)
110301
+ } });
110302
+ return 0;
110303
+ }
110304
+ }
110305
+ pendingBucketCount() {
110306
+ return this.accum.pendingBucketCount();
110307
+ }
110308
+ async readLongTermBuckets(input) {
110309
+ const key = historyKeyForLtsSeries(input.series);
110310
+ const result = await this.deviceHistory.query({
110311
+ deviceId: input.deviceId,
110312
+ key,
110313
+ ...input.scope !== void 0 ? { scope: input.scope } : {},
110314
+ from: input.from,
110315
+ to: input.to,
110316
+ resolution: "5m",
110317
+ ...input.limit !== void 0 ? { maxPoints: input.limit } : {}
110318
+ });
110319
+ const out = [];
110320
+ for (const s of result.series) for (const p of s.points) {
110321
+ if (p.mean === null) continue;
110322
+ out.push({
110323
+ scope: s.scope,
110324
+ bucketStart: p.t,
110325
+ samples: p.samples,
110326
+ sum: p.mean * p.samples,
110327
+ min: p.min,
110328
+ max: p.max
110329
+ });
110330
+ }
110331
+ return out.toSorted((a, b) => a.bucketStart - b.bucketStart);
110332
+ }
110333
+ /** Admin debug read — maps device-history 5m buckets to legacy LTS row shape. */
110334
+ async readDebug(input) {
110335
+ const deviceId = input.subject !== void 0 ? Number(input.subject) : NaN;
110336
+ if (!Number.isFinite(deviceId) || input.series === void 0) return [];
110337
+ const key = historyKeyForLtsSeries(input.series);
110338
+ const result = await this.deviceHistory.query({
110339
+ deviceId,
110340
+ key,
110341
+ ...input.scope !== void 0 ? { scope: input.scope } : {},
110342
+ from: input.from ?? 0,
110343
+ to: input.to ?? this.nowFn(),
110344
+ resolution: "5m",
110345
+ ...input.limit !== void 0 ? { maxPoints: input.limit } : {}
110346
+ });
110347
+ const rows = [];
110348
+ for (const s of result.series) for (const p of s.points) {
110349
+ if (p.mean === null) continue;
110350
+ rows.push({
110351
+ subject: String(deviceId),
110352
+ deviceId,
110353
+ series: input.series,
110354
+ scope: s.scope,
110355
+ bucketStart: p.t,
110356
+ samples: p.samples,
110357
+ sum: p.mean * p.samples,
110358
+ min: p.min,
110359
+ max: p.max
110360
+ });
110361
+ }
110362
+ return rows;
110363
+ }
110364
+ openBucketsForDebug() {
110365
+ return [];
110366
+ }
110367
+ };
110368
+ //#endregion
110369
+ //#region src/pipeline-analytics/store/device-history-write-client.ts
110370
+ /** Adapt tRPC-shaped `ctx.api.deviceHistory` to the producer's plain async surface. */
110371
+ function deviceHistoryWriteClient(api) {
110372
+ return {
110373
+ declareSeries: (input) => api.declareSeries.mutate(input),
110374
+ record: (input) => api.record.mutate({ points: [...input.points] }),
110375
+ recordBuckets: (input) => api.recordBuckets.mutate({ buckets: [...input.buckets] }),
110376
+ query: (input) => api.query.query(input)
110377
+ };
110378
+ }
110379
+ //#endregion
110564
110380
  //#region src/pipeline-analytics/store/media-subject-shot.ts
110565
110381
  /** Preference among rows that tie on time. Lower is better. */
110566
110382
  var SUBJECT_SHOT_KIND_RANK = {
@@ -112895,7 +112711,7 @@ var NcArtifactSecretSchema = string();
112895
112711
  var EmbeddingEnabledSchema = boolean();
112896
112712
  var SILENCE_FLOOR_DBFS = -55;
112897
112713
  var RETENTION_SWEEP_INTERVAL_MS = 5 * 6e4;
112898
- /** How often closed LTS buckets are written. See `store/lts-store.ts`. */
112714
+ /** How often closed history buckets are flushed. See `analytics-history-producer.ts`. */
112899
112715
  var LTS_FLUSH_INTERVAL_MS = 6e4;
112900
112716
  /**
112901
112717
  * How long the events ops-log is kept when the cluster has said nothing. 30
@@ -114551,7 +114367,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
114551
114367
  /**
114552
114368
  * Five-minute long-term statistics — the tier this system did not have.
114553
114369
  * Global for every camera (no opt-in: a baseline nobody enables is the
114554
- * failure mode `observe` mode was already in). See `store/lts-store.ts`.
114370
+ * failure mode `observe` mode was already in). See `analytics-history-producer.ts`.
114555
114371
  */
114556
114372
  lts = null;
114557
114373
  /** The runner node that last produced a frame for a camera — see
@@ -114718,7 +114534,6 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
114718
114534
  onAudioResult: (data) => this.handleAudioResult(data),
114719
114535
  onMotionAnalysis: (deviceId, data, timestampMs) => this.handleMotionAnalysis(deviceId, data, timestampMs),
114720
114536
  onOnboardMotion: (deviceId, data, timestampMs) => this.handleOnboardMotion(deviceId, data, timestampMs),
114721
- onBatterySample: (deviceId, percentage, at) => this.lts?.note("battery", deviceId, percentage, at),
114722
114537
  onSensorStateChanged: (data, timestampMs) => this.dispatchSensorStateChanged(data, timestampMs),
114723
114538
  onBindingsChanged: (data) => this.handleBindingsChangedEvent(data),
114724
114539
  onDeviceUnregistered: (deviceId) => this.handleDeviceUnregisteredEvent(deviceId),
@@ -115047,7 +114862,6 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
115047
114862
  TrackingTapeIndexStore.declare(api.settingsStore),
115048
114863
  BirthDecisionLedgerStore.declare(api.settingsStore),
115049
114864
  TrackRelationsStore.declare(api.settingsStore),
115050
- AnalyticsLts.declare(api.settingsStore),
115051
114865
  declarePaAnalyticsBootRecordBackedLegacy(api.settingsStore, isHub),
115052
114866
  declareNotificationCenterBootCollections(api.settingsStore, isHub)
115053
114867
  ]);
@@ -115403,9 +115217,12 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
115403
115217
  }
115404
115218
  });
115405
115219
  this.refreshDeviceAlertSettings();
115406
- this.lts = new AnalyticsLts({
115407
- store: api.settingsStore,
115408
- logger: logger.child("lts")
115220
+ this.lts = new AnalyticsHistoryProducer({
115221
+ deviceHistory: deviceHistoryWriteClient(api.deviceHistory),
115222
+ logger: logger.child("device-history")
115223
+ });
115224
+ this.lts.declare().catch((err) => {
115225
+ logger.warn("pipeline-analytics history series declare failed", { meta: { error: err instanceof Error ? err.message : String(err) } });
115409
115226
  });
115410
115227
  const lts = this.lts;
115411
115228
  const eventStore = new EventStore({
@@ -116872,8 +116689,8 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
116872
116689
  open: []
116873
116690
  };
116874
116691
  return {
116875
- rows: (await lts.read(input)).map(withMean),
116876
- open: lts.openBuckets().map(withMean)
116692
+ rows: (await lts.readDebug(input)).map(withMean),
116693
+ open: lts.openBucketsForDebug().map(withMean)
116877
116694
  };
116878
116695
  },
116879
116696
  /**
@@ -120949,33 +120766,8 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
120949
120766
  });
120950
120767
  this.levelStateByDevice.set(deviceId, res.nextState);
120951
120768
  if (!res.emit) return;
120952
- const draft = levelAudioEventDraft(deviceId, timestamp, frame);
120953
- this.lastAudioInsertByDevice.set(deviceId, {
120954
- className: void 0,
120955
- atMs: timestamp
120956
- });
120957
- const insertedId = await this.eventStore.insertAudio(draft);
120958
- if (insertedId === null) return;
120959
- const ev = {
120960
- ...draft,
120961
- id: insertedId
120962
- };
120963
- this.ctx.eventBus.emit({
120964
- id: `pa-${ev.id}`,
120965
- timestamp: new Date(ev.timestamp),
120966
- source: {
120967
- type: "addon",
120968
- id: "pipeline-analytics",
120969
- addonId: "pipeline-analytics"
120970
- },
120971
- category: EventCategory.PipelineAnalyticsDetectionEvent,
120972
- data: {
120973
- deviceId,
120974
- kind: "audio",
120975
- eventId: ev.id,
120976
- timestamp: ev.timestamp
120977
- }
120978
- });
120769
+ const dbfs = level?.dbfs ?? Number.NEGATIVE_INFINITY;
120770
+ this.lts?.recordAudioLevel(deviceId, dbfs, timestamp);
120979
120771
  }
120980
120772
  /**
120981
120773
  * Persist motion-analysis bus events into the EPISODE tracker (D475): a
@@ -125090,21 +124882,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
125090
124882
  async readLongTermSeries(input) {
125091
124883
  const lts = this.lts;
125092
124884
  if (!lts) throw new Error("pipeline-analytics: the long-term store is not ready yet");
125093
- return (await lts.read({
125094
- subject: String(input.deviceId),
125095
- series: input.series,
125096
- ...input.scope !== void 0 ? { scope: input.scope } : {},
125097
- from: input.from,
125098
- to: input.to,
125099
- ...input.limit !== void 0 ? { limit: input.limit } : {}
125100
- })).map((r) => ({
125101
- scope: r.scope,
125102
- bucketStart: r.bucketStart,
125103
- samples: r.samples,
125104
- sum: r.sum,
125105
- min: r.min,
125106
- max: r.max
125107
- }));
124885
+ return lts.readLongTermBuckets(input);
125108
124886
  }
125109
124887
  async getEventStoreFootprint() {
125110
124888
  return this.queryFacade.getEventStoreFootprint();