@camstack/addon-post-analysis 1.2.666 → 1.2.667

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 (16) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/{clip-model-registry-BIhYJRFt.js → clip-model-registry-D7cqhFK3.js} +731 -485
  3. package/dist/{clip-model-registry-Uc_C1x81.mjs → clip-model-registry-DpzRS8q3.mjs} +731 -485
  4. package/dist/embedding-encoder/index.js +1 -1
  5. package/dist/embedding-encoder/index.mjs +1 -1
  6. package/dist/pipeline-analytics/_stub.js +2 -2
  7. package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-FkeZoNXj.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-DmTIEp0m.mjs} +2 -2
  8. package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DAAkZRnK.mjs +26 -0
  9. package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-znrgUrN1.mjs +26 -0
  10. package/dist/pipeline-analytics/{hostInit-BBhgVoNl.mjs → hostInit-ODebWXu_.mjs} +2 -2
  11. package/dist/pipeline-analytics/index.js +449 -114
  12. package/dist/pipeline-analytics/index.mjs +449 -114
  13. package/dist/pipeline-analytics/remoteEntry.js +1 -1
  14. package/package.json +2 -2
  15. package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CnYZAdvw.mjs +0 -26
  16. package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-Br6eWzp_.mjs +0 -26
@@ -1,4 +1,4 @@
1
- import { $ as MAX_TRACK_RELATIONS, $i as zoneAnalyticsCapability, $n as buildViewerLink, $r as ncMediaPolicyError, $t as NcTemplatePreviewSchema, A as DETECTION_MACRO_CLASSES, Aa as record, Ai as ruleKindOf, An as TrackPlacementSchema, Ar as isAlarmControllableCap, At as NcAlarmConfigSchema, B as EXPORT_DENSE_MAX_RANGES, Bi as summarizeReview, Bn as alertEpisodeId, Br as isKnownTemplateVar, Bt as NcRuleSchema, C as COCO_TO_MACRO, Ca as boolean, Cn as SetTrackPurityResultSchema, Cr as ensureAlarmProfiles, Ct as NC_GROUPING_MIN_SEC, D as DEFAULT_DETAIL_CROP_CONVENTION, Da as number, Di as ruleBelongsToAlarm$1, Dn as TimelapseRuleInputSchema, Dr as failureContributionCapability, Dt as NC_SYSTEM_EVENT_KIND_GROUP_SPECS, E as CoverStateSchema, Ea as looseObject, Ei as ruleAutoTriggersAlarm, En as TRACK_RELATIONS_DEFAULT_LIMIT, Er as faceGalleryCapability, Et as NC_STATE_SUMMARY_SECTION_IDS, F as EMBEDDING_REQUIREMENTS_FAILED, Fa as union, Fi as startMoverUnderClearance, Fn as TrackSourceSchema, Fr as isDefaultAlarmProfileId, Ft as NcConditionDescriptorSchema, G as LabelAttributionSchema, Gi as systemEventFilterApplies, Gn as applyNonBlockingEdit, Gr as isScheduleActive, Gt as NcSnoozeInputSchema, H as FULL_IMAGE_BBOX, Hi as syncActiveAlarmProfileSettings, Hn as alertEpisodePayload, Hr as isMediaOwnerType, Ht as NcRuleUpdateInputSchema, I as EMBEDDING_REQUIREMENTS_UNAVAILABLE, Ia as unknown, Ii as storageOccupancyCapability, In as activateAlarmProfile, Ir as isDetectionMacroClass, It as NcConditionsSchema, J as LockStateSchema, Ji as templateCarriesSummary, Jn as assertTimelapseCadences, Jr as isVectorIndexDimConflict, Jt as NcStateSummarySectionIdSchema, K as ListTrackRelationsInputSchema, Ki as systemEventSummaryScheduleOf, Kn as applySecureOnArmEdit, Kr as isSystemDelivery, Kt as NcSnoozeSchema, L as EVENT_DENSITY_BATCH_MAX, La as DeviceType, Li as subKindsOf, Ln as addonWidgetsSourceCapability, Lr as isDrawableSubjectPath, Lt as NcRuleActionSchema, M as DeclaredDevices, Ma as string, Mi as secureActuationFor, Mn as TrackRelationKindSchema, Mr as isAlertEpisodeSeverity, Mt as NcAlarmSensorsInputSchema, N as DetectionSourceSchema, Na as templateLiteral, Ni as sensorRaisedOf, Nn as TrackRelationSchema, Nr as isAppLinkBase, Nt as NcAlarmSensorsSchema, O as DEFAULT_EVENT_COLOR, Oa as object, Oi as ruleDeviceCompatCapQueries, On as TimelapseRulePatchSchema, Or as gifDeriveSpeed, Ot as NC_TAXONOMY, P as EMBEDDING_MODEL_FAILED, Pa as tuple, Pi as servedTemplateVars, Pn as TrackSideSchema, Pr as isAudioClassName, Pt as NcAlarmSettingsPatchSchema, Q as MAX_TRACK_PURITIES, Qi as withSystemEventClasses, Qn as buildSubjectPath, Qr as memoizePinnedFfmpeg, Qt as NcTemplatePreviewInputSchema, R as EVENT_KIND_BY_CAP, Ra as errMsg, Ri as subjectPathSampleFromBox, Rn as alarmDeviceSecureOnArm, Rr as isEventKindLabelKey, Rt as NcRuleInputSchema, S as BucketAccumulator, Sa as array, Si as resolveNcMediaImage, Sn as SetTrackPurityInputSchema, Sr as encodeVectorBase64, St as NC_GROUPING_MAX_SEC, T as ClearTrackRelationResultSchema, Ta as literal, Ti as rootSupplyServes, Tn as TIMELAPSE_DENSE_FLOOR_SEC, Tr as evictionPolicyOfLocation, Tt as NC_SNOOZE_MAX_MINUTES, U as FailureCounters, Ui as systemEventDeliveryProblems, Un as applyBlockingEdit, Ur as isRetiredClearKey, Ut as NcScheduleSchema, V as FIRST_LEVEL_MACRO_CLASSES, Vi as sunTimes, Vn as alertEpisodeKind, Vr as isLabelSupplyStepId, Vt as NcRuleTargetSchema, W as LABEL_SUPPLY_MACRO, Wi as systemEventFamilyProblems, Wn as applyModeDelaysEdits, Wr as isRootSuppliableStepId, Wt as NcSharedSequenceSchema, X as MAX_BIRTH_DECISION_RECORDS, Xi as vectorDimFromBase64, Xn as audioModeOf, Xr as linkedStepOf, Xt as NcTaxonomySchema, Y as MAX_ARCHIVED_DEBUG_NOTES, Yi as templateVarsFor, Yn as audioMetricsCapability, Yr as kebabToCamel, Yt as NcSystemEventKindSchema, Z as MAX_BIRTH_LATENCY_PROXY_MS, Zi as viewerLinkBaseOf, Zn as buildEventKindDescriptor, Zr as mayWriteToLocation, Zt as NcTemplateDefaultSchema, _ as AlarmArmModeSchema, _a as nodePin, _i as resolveClipSearchMinScore, _n as SCENE_DEFAULT_QUIET_SECONDS, _t as NC_CONFIRM_DEFAULT_TIMEOUT_MS, a as CLIP_EMBEDDING_STEP_ID, aa as CAP_ADVANCE_FIELDS, ai as paintHex, an as RECORDING_EXPORT_MAX_READ_BYTES, ar as consumableLowPercentOf, at as NC_ALARM_DELAY_FIELDS, b as BaseDevice, ba as ZodObject, bi as resolveModeDelays, bn as SCENE_RESET_RECAPTURES, bt as NC_DEFAULT_SNOOZE_MINUTES, c as readClusterModelPinStrict, ca as RECORD_MAX_DATA_BYTES, cn as RetrainDismissedSchema, cr as createAlarmProfile, ct as NC_ALARM_SYSTEM_EVENT_KINDS, d as APPEARANCE_BIN_COUNT, da as customAction, di as plateGalleryCapability, dn as RetrainVerdictSubjectSchema, dr as derivePostTriggeredAction, dt as NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT, ea as DEFAULT_FIRST_SIGHTING_FRESHNESS_MS, ei as normalizeNcAction, en as NcTemplateVarDescriptorSchema, er as bundledCamstack, et as MOTION_CLOSE_AFTER_MS, f as APPEARANCE_BLOCKS, fa as defineAddonMigrations, fi as projectSubjectPath, fn as SCENE_CONFIRM_DEFAULT_MAX_IMAGE_PX, fr as deriveRecordingMode, ft as NC_CLIP_POST_ROLL_DEFAULT_SEC, g as ActionTargetResolver, ga as isDeviceScopedCap, gi as renameAlarmProfile, gn as SCENE_DEFAULT_OBSERVATION_SPACING_SEC, gr as deviceRemovalHookCapability, gt as NC_CONFIRM_DEFAULT_MAX_IMAGE_PX, h as AUDIO_MACRO_LABELS, ha as hydrateSchema, hi as readTimelapseGeneratedAt, hn as SCENE_DEFAULT_CHECK_INTERVAL_SEC, hr as deviceAttentionKind, ht as NC_CONDITION_CATALOG, ia as BaseAddon, ii as occupancyScope, ir as consumableFormOf, it as NC_ALARM_DEFAULT_TRIGGERED_DURATION_SEC, j as DETECTION_PIPELINE_CAP_NAME, ja as strictObject, ji as sceneMonitorCapability, jn as TrackPuritySchema, jr as isAlertEpisodeOpen, jt as NcAlarmPostTriggeredActionSchema, k as DEFAULT_TIMELAPSE_PREVIEW_TEXT, ka as partialRecord, ki as ruleGroupingApplies, kn as TimelapseRuleSchema, kr as gifFromMp4Args, kt as NC_TEMPLATE_VARS, l as resolveClusterModelPin, la as RECORD_QUERY_MAX, li as pickFaceRescoreIntervalMinutes, ln as RetrainOriginSchema, lr as deleteAlarmProfile, lt as NC_ALARM_TRIGGERED_MAX_SEC, m as ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT, ma as defineRecordKinds, mi as readMotionTriggeredBy, mn as SCENE_DEFAULT_ANCHOR_THRESHOLD, mr as describeSystemEventFamilyProblem, mt as NC_CLIP_RETENTION_MAX_SEC, na as evaluateSensorEdge, ni as normalizeNcMediaPolicy, nn as OpsLogEntrySchema, nr as classifyRetrainReview, nt as MotionTriggeredBySchema, o as CLUSTER_MODEL_OWNER_ADDON_ID, oa as CamProfileSchema, oi as paletteResultSchema, on as RECORDING_SOURCE_CAMSTACK_ADDON, or as coreBlockIdFromAddonId, ot as NC_ALARM_DELAY_MAX_SEC, p as APPEARANCE_RESOLVES_AMBIGUITY_DEFAULT, pa as defineCustomActions, pi as readDeviceStateFrom, pn as SCENE_CONFIRM_DEFAULT_TIMEOUT_MS, pr as describeSystemEventDeliveryProblem, pt as NC_CLIP_PRE_ROLL_DEFAULT_SEC, q as ListTrackRelationsResultSchema, qi as systemEventSummarySplitOf, qn as armRemovalReconcile, qr as isSystemEventSummaryRule, qt as NcSnoozeSuppressedSchema, ra as isSourceCap, ri as notificationRulesCapability, rn as PackageLlmVerdictSchema, rr as cloneAlarmSettings, rt as NC_ALARM_DEFAULT_PROFILE_ID, s as FACE_EMBEDDING_STEP_ID, sa as InvalidRecordError, si as parseAlertEpisodePayload, sn as RebuildObjectEmbeddingsRefusalSchema, sr as cosineSimilarity$1, st as NC_ALARM_NOTIFY_FIELDS, t as BUILTIN_CLIP_MODELS, ta as canonicalHash, ti as normalizeNcCapTarget, tn as OPS_LOG_DEFAULT_LIMIT, tr as calendarEventLocalSpan, tt as MediaFileKindEnum, u as ACTION_TARGET_INVALIDATION_EVENTS, ua as createEvent, ui as pipelineAnalyticsCapability, un as RetrainStatusSchema, ur as deriveDetailCropRect, ut as NC_AUDIO_CONFIRM_HITS_DEFAULT, v as ArchivedDebugNoteSchema, vi as resolveDeliveryParams, vn as SCENE_DEFAULT_UNCOVERED_POLICY, vt as NC_CONSUMABLE_LOW_PERCENT_DEFAULT, w as ClearTrackRelationInputSchema, wa as discriminatedUnion, wi as retrainRevisionConflictMessage, wn as SetTrackRelationInputSchema, wr as eventKindLabel, wt as NC_SENSOR_TRANSITION_KINDS, x as BirthDecisionRecordSchema, xa as _enum, xi as resolveModeNotifyPolicy, xn as SceneMonitorSchema, xt as NC_GROUPING_DEFAULT_SEC, y as BIRTH_DECISION_DEFAULT_LIMIT, ya as sleep$1, yi as resolveLocationMode, yn as SCENE_DIVERGED, yr as embeddingRefusalOf, yt as NC_CONSUMABLE_SYSTEM_EVENT_KINDS, z as EVENT_OWNER_TYPES, za as EventCategory, zi as subjectPathSvgPoints, zn as alarmPanelCapability, zr as isEventOwnerType, zt as NcRulePatchSchema } from "../clip-model-registry-Uc_C1x81.mjs";
1
+ import { $ as MAX_TRACK_RELATIONS, $i as zoneAnalyticsCapability, $n as buildViewerLink, $r as ncMediaPolicyError, $t as NcTemplatePreviewSchema, A as DETECTION_MACRO_CLASSES, Aa as record, Ai as ruleKindOf, An as TrackPlacementSchema, Ar as isAlarmControllableCap, At as NcAlarmConfigSchema, B as EXPORT_DENSE_MAX_RANGES, Bi as summarizeReview, Bn as alertEpisodeId, Br as isKnownTemplateVar, Bt as NcRuleSchema, C as COCO_TO_MACRO, Ca as boolean, Cn as SetTrackPurityResultSchema, Cr as ensureAlarmProfiles, Ct as NC_GROUPING_MIN_SEC, D as DEFAULT_DETAIL_CROP_CONVENTION, Da as number, Di as ruleBelongsToAlarm$1, Dn as TimelapseRuleInputSchema, Dr as failureContributionCapability, Dt as NC_SYSTEM_EVENT_KIND_GROUP_SPECS, E as CoverStateSchema, Ea as looseObject, Ei as ruleAutoTriggersAlarm, En as TRACK_RELATIONS_DEFAULT_LIMIT, Er as faceGalleryCapability, Et as NC_STATE_SUMMARY_SECTION_IDS, F as EMBEDDING_REQUIREMENTS_FAILED, Fa as union, Fi as startMoverUnderClearance, Fn as TrackSourceSchema, Fr as isDefaultAlarmProfileId, Ft as NcConditionDescriptorSchema, G as LabelAttributionSchema, Gi as systemEventFilterApplies, Gn as applyNonBlockingEdit, Gr as isScheduleActive, Gt as NcSnoozeInputSchema, H as FULL_IMAGE_BBOX, Hi as syncActiveAlarmProfileSettings, Hn as alertEpisodePayload, Hr as isMediaOwnerType, Ht as NcRuleUpdateInputSchema, I as EMBEDDING_REQUIREMENTS_UNAVAILABLE, Ia as unknown, Ii as storageOccupancyCapability, In as activateAlarmProfile, Ir as isDetectionMacroClass, It as NcConditionsSchema, J as LockStateSchema, Ji as templateCarriesSummary, Jn as assertTimelapseCadences, Jr as isVectorIndexDimConflict, Jt as NcStateSummarySectionIdSchema, K as ListTrackRelationsInputSchema, Ki as systemEventSummaryScheduleOf, Kn as applySecureOnArmEdit, Kr as isSystemDelivery, Kt as NcSnoozeSchema, L as EVENT_DENSITY_BATCH_MAX, La as DeviceType, Li as subKindsOf, Ln as addonWidgetsSourceCapability, Lr as isDrawableSubjectPath, Lt as NcRuleActionSchema, M as DeclaredDevices, Ma as string, Mi as secureActuationFor, Mn as TrackRelationKindSchema, Mr as isAlertEpisodeSeverity, Mt as NcAlarmSensorsInputSchema, N as DetectionSourceSchema, Na as templateLiteral, Ni as sensorRaisedOf, Nn as TrackRelationSchema, Nr as isAppLinkBase, Nt as NcAlarmSensorsSchema, O as DEFAULT_EVENT_COLOR, Oa as object, Oi as ruleDeviceCompatCapQueries, On as TimelapseRulePatchSchema, Or as gifDeriveSpeed, Ot as NC_TAXONOMY, P as EMBEDDING_MODEL_FAILED, Pa as tuple, Pi as servedTemplateVars, Pn as TrackSideSchema, Pr as isAudioClassName, Pt as NcAlarmSettingsPatchSchema, Q as MAX_TRACK_PURITIES, Qi as withSystemEventClasses, Qn as buildSubjectPath, Qr as memoizePinnedFfmpeg, Qt as NcTemplatePreviewInputSchema, R as EVENT_KIND_BY_CAP, Ra as errMsg, Ri as subjectPathSampleFromBox, Rn as alarmDeviceSecureOnArm, Rr as isEventKindLabelKey, Rt as NcRuleInputSchema, S as BucketAccumulator, Sa as array, Si as resolveNcMediaImage, Sn as SetTrackPurityInputSchema, Sr as encodeVectorBase64, St as NC_GROUPING_MAX_SEC, T as ClearTrackRelationResultSchema, Ta as literal, Ti as rootSupplyServes, Tn as TIMELAPSE_DENSE_FLOOR_SEC, Tr as evictionPolicyOfLocation, Tt as NC_SNOOZE_MAX_MINUTES, U as FailureCounters, Ui as systemEventDeliveryProblems, Un as applyBlockingEdit, Ur as isRetiredClearKey, Ut as NcScheduleSchema, V as FIRST_LEVEL_MACRO_CLASSES, Vi as sunTimes, Vn as alertEpisodeKind, Vr as isLabelSupplyStepId, Vt as NcRuleTargetSchema, W as LABEL_SUPPLY_MACRO, Wi as systemEventFamilyProblems, Wn as applyModeDelaysEdits, Wr as isRootSuppliableStepId, Wt as NcSharedSequenceSchema, X as MAX_BIRTH_DECISION_RECORDS, Xi as vectorDimFromBase64, Xn as audioModeOf, Xr as linkedStepOf, Xt as NcTaxonomySchema, Y as MAX_ARCHIVED_DEBUG_NOTES, Yi as templateVarsFor, Yn as audioMetricsCapability, Yr as kebabToCamel, Yt as NcSystemEventKindSchema, Z as MAX_BIRTH_LATENCY_PROXY_MS, Zi as viewerLinkBaseOf, Zn as buildEventKindDescriptor, Zr as mayWriteToLocation, Zt as NcTemplateDefaultSchema, _ as AlarmArmModeSchema, _a as nodePin, _i as resolveClipSearchMinScore, _n as SCENE_DEFAULT_QUIET_SECONDS, _t as NC_CONFIRM_DEFAULT_TIMEOUT_MS, a as CLIP_EMBEDDING_STEP_ID, aa as CAP_ADVANCE_FIELDS, ai as paintHex, an as RECORDING_EXPORT_MAX_READ_BYTES, ar as consumableLowPercentOf, at as NC_ALARM_DELAY_FIELDS, b as BaseDevice, ba as ZodObject, bi as resolveModeDelays, bn as SCENE_RESET_RECAPTURES, bt as NC_DEFAULT_SNOOZE_MINUTES, c as readClusterModelPinStrict, ca as RECORD_MAX_DATA_BYTES, cn as RetrainDismissedSchema, cr as createAlarmProfile, ct as NC_ALARM_SYSTEM_EVENT_KINDS, d as APPEARANCE_BIN_COUNT, da as customAction, di as plateGalleryCapability, dn as RetrainVerdictSubjectSchema, dr as derivePostTriggeredAction, dt as NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT, ea as DEFAULT_FIRST_SIGHTING_FRESHNESS_MS, ei as normalizeNcAction, en as NcTemplateVarDescriptorSchema, er as bundledCamstack, et as MOTION_CLOSE_AFTER_MS, f as APPEARANCE_BLOCKS, fa as defineAddonMigrations, fi as projectSubjectPath, fn as SCENE_CONFIRM_DEFAULT_MAX_IMAGE_PX, fr as deriveRecordingMode, ft as NC_CLIP_POST_ROLL_DEFAULT_SEC, g as ActionTargetResolver, ga as isDeviceScopedCap, gi as renameAlarmProfile, gn as SCENE_DEFAULT_OBSERVATION_SPACING_SEC, gr as deviceRemovalHookCapability, gt as NC_CONFIRM_DEFAULT_MAX_IMAGE_PX, h as AUDIO_MACRO_LABELS, ha as hydrateSchema, hi as readTimelapseGeneratedAt, hn as SCENE_DEFAULT_CHECK_INTERVAL_SEC, hr as deviceAttentionKind, ht as NC_CONDITION_CATALOG, ia as BaseAddon, ii as occupancyScope, ir as consumableFormOf, it as NC_ALARM_DEFAULT_TRIGGERED_DURATION_SEC, j as DETECTION_PIPELINE_CAP_NAME, ja as strictObject, ji as sceneMonitorCapability, jn as TrackPuritySchema, jr as isAlertEpisodeOpen, jt as NcAlarmPostTriggeredActionSchema, k as DEFAULT_TIMELAPSE_PREVIEW_TEXT, ka as partialRecord, ki as ruleGroupingApplies, kn as TimelapseRuleSchema, kr as gifFromMp4Args, kt as NC_TEMPLATE_VARS, l as resolveClusterModelPin, la as RECORD_QUERY_MAX, li as pickFaceRescoreIntervalMinutes, ln as RetrainOriginSchema, lr as deleteAlarmProfile, lt as NC_ALARM_TRIGGERED_MAX_SEC, m as ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT, ma as defineRecordKinds, mi as readMotionTriggeredBy, mn as SCENE_DEFAULT_ANCHOR_THRESHOLD, mr as describeSystemEventFamilyProblem, mt as NC_CLIP_RETENTION_MAX_SEC, na as evaluateSensorEdge, ni as normalizeNcMediaPolicy, nn as OpsLogEntrySchema, nr as classifyRetrainReview, nt as MotionTriggeredBySchema, o as CLUSTER_MODEL_OWNER_ADDON_ID, oa as CamProfileSchema, oi as paletteResultSchema, on as RECORDING_SOURCE_CAMSTACK_ADDON, or as coreBlockIdFromAddonId, ot as NC_ALARM_DELAY_MAX_SEC, p as APPEARANCE_RESOLVES_AMBIGUITY_DEFAULT, pa as defineCustomActions, pi as readDeviceStateFrom, pn as SCENE_CONFIRM_DEFAULT_TIMEOUT_MS, pr as describeSystemEventDeliveryProblem, pt as NC_CLIP_PRE_ROLL_DEFAULT_SEC, q as ListTrackRelationsResultSchema, qi as systemEventSummarySplitOf, qn as armRemovalReconcile, qr as isSystemEventSummaryRule, qt as NcSnoozeSuppressedSchema, ra as isSourceCap, ri as notificationRulesCapability, rn as PackageLlmVerdictSchema, rr as cloneAlarmSettings, rt as NC_ALARM_DEFAULT_PROFILE_ID, s as FACE_EMBEDDING_STEP_ID, sa as InvalidRecordError, si as parseAlertEpisodePayload, sn as RebuildObjectEmbeddingsRefusalSchema, sr as cosineSimilarity$1, st as NC_ALARM_NOTIFY_FIELDS, t as BUILTIN_CLIP_MODELS, ta as canonicalHash, ti as normalizeNcCapTarget, tn as OPS_LOG_DEFAULT_LIMIT, tr as calendarEventLocalSpan, tt as MediaFileKindEnum, u as ACTION_TARGET_INVALIDATION_EVENTS, ua as createEvent, ui as pipelineAnalyticsCapability, un as RetrainStatusSchema, ur as deriveDetailCropRect, ut as NC_AUDIO_CONFIRM_HITS_DEFAULT, v as ArchivedDebugNoteSchema, vi as resolveDeliveryParams, vn as SCENE_DEFAULT_UNCOVERED_POLICY, vt as NC_CONSUMABLE_LOW_PERCENT_DEFAULT, w as ClearTrackRelationInputSchema, wa as discriminatedUnion, wi as retrainRevisionConflictMessage, wn as SetTrackRelationInputSchema, wr as eventKindLabel, wt as NC_SENSOR_TRANSITION_KINDS, x as BirthDecisionRecordSchema, xa as _enum, xi as resolveModeNotifyPolicy, xn as SceneMonitorSchema, xt as NC_GROUPING_DEFAULT_SEC, y as BIRTH_DECISION_DEFAULT_LIMIT, ya as sleep$1, yi as resolveLocationMode, yn as SCENE_DIVERGED, yr as embeddingRefusalOf, yt as NC_CONSUMABLE_SYSTEM_EVENT_KINDS, z as EVENT_OWNER_TYPES, za as EventCategory, zi as subjectPathSvgPoints, zn as alarmPanelCapability, zr as isEventOwnerType, zt as NcRulePatchSchema } from "../clip-model-registry-DpzRS8q3.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";
@@ -59659,6 +59659,140 @@ async function promoteWithStill(input) {
59659
59659
  });
59660
59660
  }
59661
59661
  //#endregion
59662
+ //#region src/pipeline-analytics/pipeline/key-frame-persist.ts
59663
+ /**
59664
+ * A box is written only when it can be USED — a degenerate rectangle, or one
59665
+ * measured on a degenerate frame, says nothing and would read back as a box at
59666
+ * the origin. Absent is the honest answer; the reader then pairs a snapshot,
59667
+ * exactly as it did before D510.
59668
+ *
59669
+ * Its result is spread into BOTH writes: the small companion is derived from
59670
+ * the very bytes of the native one, so it is the same scene at the same
59671
+ * instant and the box maps into it by ratio like any other scale of the frame.
59672
+ * A box on one row and not the other would make the summary's answer depend on
59673
+ * which row a reader happened to pick.
59674
+ */
59675
+ function isStatableSubject(subject) {
59676
+ if (subject === void 0) return false;
59677
+ return subject.w > 0 && subject.h > 0 && subject.frameWidth > 0 && subject.frameHeight > 0;
59678
+ }
59679
+ /**
59680
+ * Read, derive and store one track's key frame + its web companion.
59681
+ *
59682
+ * PARCEL-OR-NOTHING: no parcel writes nothing and the caller's bounded retry
59683
+ * parks a later frame. The `keyFrame` write lands FIRST and its media id (D482)
59684
+ * is what the outcome carries — a `keyFrameSmall` failure afterwards must not
59685
+ * re-arm a retry that would re-shoot a key frame the rebuild can already read.
59686
+ */
59687
+ async function persistTrackKeyFrame(deps, input) {
59688
+ const { deviceId, trackId, retry } = input;
59689
+ const drop = {
59690
+ tags: { deviceId },
59691
+ meta: {
59692
+ trackId,
59693
+ retry
59694
+ }
59695
+ };
59696
+ try {
59697
+ const parcel = await deps.fetchParkedKeyFrame(deviceId, trackId);
59698
+ if (parcel === null || parcel.jpeg.byteLength === 0) {
59699
+ deps.logger.error("key-frame parcel missing — nothing to write, retry parks a later frame", { ...drop });
59700
+ return { kind: "parcel-missing" };
59701
+ }
59702
+ const subjectBox = isStatableSubject(parcel.subject) ? { subjectBox: parcel.subject } : {};
59703
+ const keyFrameMediaId = await deps.media.putReplacing({
59704
+ deviceId,
59705
+ ownerKind: "track",
59706
+ ownerId: trackId,
59707
+ kind: "keyFrame",
59708
+ timestamp: parcel.timestamp,
59709
+ data: parcel.jpeg,
59710
+ ...subjectBox
59711
+ });
59712
+ try {
59713
+ const keyFrameSmall = await deps.deriveSmall(parcel.jpeg);
59714
+ await deps.media.putReplacing({
59715
+ deviceId,
59716
+ ownerKind: "track",
59717
+ ownerId: trackId,
59718
+ kind: "keyFrameSmall",
59719
+ timestamp: parcel.timestamp,
59720
+ data: keyFrameSmall,
59721
+ ...subjectBox
59722
+ });
59723
+ } catch (err) {
59724
+ deps.logger.warn("keyFrameSmall write failed — the native keyFrame is stored", {
59725
+ ...drop,
59726
+ meta: {
59727
+ ...drop.meta,
59728
+ nodeId: parcel.nodeId,
59729
+ error: errMsg(err)
59730
+ }
59731
+ });
59732
+ }
59733
+ deps.logger.debug("key frame written from the parked parcel", {
59734
+ ...drop,
59735
+ meta: {
59736
+ ...drop.meta,
59737
+ nodeId: parcel.nodeId,
59738
+ width: parcel.width,
59739
+ height: parcel.height,
59740
+ bytes: parcel.jpeg.byteLength,
59741
+ parkedTimestamp: parcel.timestamp
59742
+ }
59743
+ });
59744
+ return {
59745
+ kind: "landed",
59746
+ keyFrameMediaId
59747
+ };
59748
+ } catch (err) {
59749
+ const error = errMsg(err);
59750
+ deps.logger.warn("key-frame write failed", {
59751
+ ...drop,
59752
+ meta: {
59753
+ ...drop.meta,
59754
+ error
59755
+ }
59756
+ });
59757
+ return {
59758
+ kind: "error",
59759
+ error
59760
+ };
59761
+ }
59762
+ }
59763
+ /**
59764
+ * Write one parked frame under an OBJECT event (`object:<id>`), once.
59765
+ *
59766
+ * A package delivery has no track row owning a key frame, and the notification
59767
+ * ladder reads only `track:` and `object:` owners — so without this the
59768
+ * delivery ships text-only. `null` = no parcel to write (said at the caller).
59769
+ * `putReplacing` makes a repeat the same row, never a second one.
59770
+ */
59771
+ async function persistObjectFrame(deps, input) {
59772
+ const { deviceId, trackId, objectId, timestamp } = input;
59773
+ const parcel = await deps.fetchParkedKeyFrame(deviceId, trackId);
59774
+ if (parcel === null || parcel.jpeg.byteLength === 0) {
59775
+ deps.logger.warn("object frame parcel missing — nothing to write", {
59776
+ tags: { deviceId },
59777
+ meta: {
59778
+ trackId,
59779
+ objectId
59780
+ }
59781
+ });
59782
+ return null;
59783
+ }
59784
+ const subjectBox = isStatableSubject(parcel.subject) ? { subjectBox: parcel.subject } : {};
59785
+ return deps.media.putReplacing({
59786
+ deviceId,
59787
+ ownerKind: "object",
59788
+ ownerId: objectId,
59789
+ kind: "keyFrame",
59790
+ timestamp,
59791
+ data: parcel.jpeg,
59792
+ ...subjectBox
59793
+ });
59794
+ }
59795
+ //#endregion
59662
59796
  //#region src/pipeline-analytics/pipeline/person-over-vehicle.ts
59663
59797
  /**
59664
59798
  * How much of the PERSON box must sit inside a vehicle box to be counted.
@@ -71066,6 +71200,12 @@ Object.freeze({
71066
71200
  "idleStopMinutes": 30
71067
71201
  } } }
71068
71202
  },
71203
+ "media-player": {
71204
+ "channelDown": { "steps": 1 },
71205
+ "channelUp": { "steps": 1 },
71206
+ "volumeDown": { "steps": 1 },
71207
+ "volumeUp": { "steps": 1 }
71208
+ },
71069
71209
  "mqtt-broker": { "startEmbeddedBroker": {
71070
71210
  "port": 1883,
71071
71211
  "allowAnonymous": false
@@ -71560,6 +71700,15 @@ var WORD_LEVEL_FIELD = {
71560
71700
  */
71561
71701
  var BOOLEAN_LEVEL_FIELD = { "running-state": "running" };
71562
71702
  /**
71703
+ * The device-history series key of a level cap's boolean — `cap:<cap>.<field>`,
71704
+ * the shape of `capSeriesKey` (system builtin, not importable from an addon;
71705
+ * the wiring spec pins the literal). `null` for a cap with no boolean level.
71706
+ */
71707
+ function levelSeriesKey(capName) {
71708
+ const field = BOOLEAN_LEVEL_FIELD[capName];
71709
+ return field === void 0 ? null : `cap:${capName}.${field}`;
71710
+ }
71711
+ /**
71563
71712
  * Caps whose level is a WORD with NO change stamp: cap → field. `enum-sensor`
71564
71713
  * carries `{ value, lastFetchedAt }`, and `lastFetchedAt` moves on every
71565
71714
  * provider refresh, so it says nothing about when the word changed. Gated by
@@ -71586,6 +71735,7 @@ var WORD_LEVEL_INACTIVE = {
71586
71735
  * post-analysis runner, D28).
71587
71736
  */
71588
71737
  var ADVANCE_FIELD = CAP_ADVANCE_FIELDS;
71738
+ var DEFAULT_SEED_WAIT_MS = 2e3;
71589
71739
  /** Default drop-summary window: one line per device per ten minutes, at most. */
71590
71740
  var DEFAULT_DROP_SUMMARY_WINDOW_MS = 6e5;
71591
71741
  var SensorTransitionGate = class {
@@ -71597,6 +71747,14 @@ var SensorTransitionGate = class {
71597
71747
  lastStamps = /* @__PURE__ */ new Map();
71598
71748
  /** Drops since the window opened, keyed by `${deviceId}:${capName}:${reason}`. */
71599
71749
  drops = /* @__PURE__ */ new Map();
71750
+ /** Seed reads started, by key; a settled one stays so a seed is read once. */
71751
+ seeds = /* @__PURE__ */ new Map();
71752
+ seedsSettled = /* @__PURE__ */ new Set();
71753
+ /** Seeds whose wait ran out: decided as unseeded from then on. */
71754
+ seedsAbandoned = /* @__PURE__ */ new Set();
71755
+ readSeed;
71756
+ onSeedFailed;
71757
+ seedWaitMs;
71600
71758
  windowStartedAt;
71601
71759
  startedAtMs;
71602
71760
  now;
@@ -71608,6 +71766,55 @@ var SensorTransitionGate = class {
71608
71766
  this.freshnessMs = options.firstSightingFreshnessMs ?? DEFAULT_FIRST_SIGHTING_FRESHNESS_MS;
71609
71767
  this.summaryWindowMs = options.summaryWindowMs ?? DEFAULT_DROP_SUMMARY_WINDOW_MS;
71610
71768
  this.windowStartedAt = options.now();
71769
+ this.readSeed = options.readSeed;
71770
+ this.onSeedFailed = options.onSeedFailed;
71771
+ this.seedWaitMs = options.seedWaitMs ?? DEFAULT_SEED_WAIT_MS;
71772
+ }
71773
+ /**
71774
+ * {@link observe}, plus: a level cap's first boolean `false` whose persisted
71775
+ * prior is still being read waits for that read, bounded by `seedWaitMs`, and
71776
+ * is decided again. This is the only wait on the path, and it is on a read
71777
+ * that was started at the FIRST sighting of the device (a null at boot, long
71778
+ * before the boolean) — never one begun by the event itself unless the
71779
+ * boolean really is the first thing seen. A read that fails or times out
71780
+ * decides as unseeded, i.e. exactly as before the seed existed (D49).
71781
+ */
71782
+ async observeSettled(deviceId, capName, slice) {
71783
+ const first = this.observe(deviceId, capName, slice);
71784
+ if (first.changed || first.reason !== "seed-pending") return first;
71785
+ const key = `${deviceId}:${capName}`;
71786
+ const pending = this.seeds.get(key);
71787
+ if (pending !== void 0) {
71788
+ let timer;
71789
+ const timeout = new Promise((resolve) => {
71790
+ timer = setTimeout(resolve, this.seedWaitMs);
71791
+ });
71792
+ await Promise.race([pending, timeout]);
71793
+ if (timer !== void 0) clearTimeout(timer);
71794
+ if (!this.seedsSettled.has(key)) this.seedsAbandoned.add(key);
71795
+ }
71796
+ return this.observe(deviceId, capName, slice);
71797
+ }
71798
+ /** Start the one seed read of a level cap's key; never awaited here. */
71799
+ ensureSeed(deviceId, capName) {
71800
+ const read = this.readSeed;
71801
+ if (read === void 0) return;
71802
+ const key = `${deviceId}:${capName}`;
71803
+ if (this.seeds.has(key)) return;
71804
+ const settle = () => {
71805
+ this.seedsSettled.add(key);
71806
+ };
71807
+ const started = read(deviceId, capName).then((seed) => {
71808
+ if (seed !== null && !this.lastValues.has(key)) this.lastValues.set(key, seed.value);
71809
+ settle();
71810
+ }, (error) => {
71811
+ this.onSeedFailed?.(deviceId, capName, error);
71812
+ settle();
71813
+ });
71814
+ this.seeds.set(key, started);
71815
+ }
71816
+ seedPending(key) {
71817
+ return this.seeds.has(key) && !this.seedsSettled.has(key) && !this.seedsAbandoned.has(key);
71611
71818
  }
71612
71819
  /**
71613
71820
  * Feed one `DeviceStateChanged` slice for a cap `EVENT_KIND_BY_CAP` maps.
@@ -71619,6 +71826,7 @@ var SensorTransitionGate = class {
71619
71826
  * a boolean in either direction, or a word-level cap's word changing.
71620
71827
  */
71621
71828
  observe(deviceId, capName, slice) {
71829
+ if (BOOLEAN_LEVEL_FIELD[capName] !== void 0) this.ensureSeed(deviceId, capName);
71622
71830
  if (slice["lastChangedAt"] === 0) return this.drop(deviceId, capName, "cold-slice");
71623
71831
  const unstampedField = UNSTAMPED_WORD_FIELD[capName];
71624
71832
  if (unstampedField !== void 0) return this.observeUnstampedWord(deviceId, capName, slice, unstampedField);
@@ -71674,6 +71882,10 @@ var SensorTransitionGate = class {
71674
71882
  if (typeof raw !== "boolean") return this.drop(deviceId, capName, "non-boolean-value");
71675
71883
  const key = `${deviceId}:${capName}`;
71676
71884
  const prior = this.lastValues.get(key);
71885
+ if (prior === void 0 && !raw && this.seedPending(key)) return {
71886
+ changed: false,
71887
+ reason: "seed-pending"
71888
+ };
71677
71889
  this.lastValues.set(key, raw);
71678
71890
  if (prior === void 0) {
71679
71891
  if (!raw) return this.drop(deviceId, capName, "baseline-seeded-inactive");
@@ -85512,6 +85724,15 @@ function isLinkedStillId(id) {
85512
85724
  var NC_LINKED_WAKE_CAPTURE_TIMEOUT_MS = 15e3;
85513
85725
  var NC_LINKED_WAKE_POLL_MS = 1e3;
85514
85726
  var NC_LINKED_WAKE_MIN_GAP_MS = 6e4;
85727
+ /**
85728
+ * D60 — a tile the freshness read calls stale is RE-POLLED, unforced, until the
85729
+ * wrapper hands back a frame from the event or this bound is spent. The wrapper
85730
+ * settles a soft miss with its old cached hit; one more ask, a moment later,
85731
+ * usually finds the refreshed one. The bound sits inside the dispatcher's still
85732
+ * deadline (`NC_STILL_WAIT_MS`, 3 s): the row waits for it through `pendingUntil`.
85733
+ */
85734
+ var NC_LINKED_STALE_POLL_MS = 500;
85735
+ var NC_LINKED_STALE_MAX_POLLS = 5;
85515
85736
  /** Per camera — the marker's own bound (`SENSOR_MARKER_SNAPSHOT_TIMEOUT_MS`). */
85516
85737
  var SENSOR_LINKED_CAPTURE_TIMEOUT_MS = 2500;
85517
85738
  /** The capture-free wrapper-state read, per camera. It runs IN PARALLEL with
@@ -85521,6 +85742,8 @@ var SENSOR_LINKED_CAPTURE_TIMEOUT_MS = 2500;
85521
85742
  * photograph). A read that misses the bound or fails is UNKNOWN and keeps the
85522
85743
  * tile (D49). */
85523
85744
  var SENSOR_LINKED_STATE_READ_TIMEOUT_MS = SENSOR_LINKED_CAPTURE_TIMEOUT_MS;
85745
+ /** The battery-slice read behind the unknown-state wake: cheap, and bounded. */
85746
+ var SENSOR_LINKED_BATTERY_READ_TIMEOUT_MS = 1e3;
85524
85747
  /** The one cache-only freshness read for the set — one hop, after the
85525
85748
  * captures. A read that misses it keeps every tile and says `freshness
85526
85749
  * unverified` (D49). */
@@ -85626,13 +85849,13 @@ var NcLinkedStillShelf = class {
85626
85849
  startedAt,
85627
85850
  options
85628
85851
  };
85629
- let results;
85852
+ let judged;
85630
85853
  try {
85631
- results = await Promise.all(stills.cameraIds.map((id) => this.captureOne(id, ctx)));
85854
+ const results = await Promise.all(stills.cameraIds.map((id) => this.captureOne(id, ctx)));
85855
+ judged = await this.repollStale(ctx, atMs, await this.judgeFreshness(stills.sensorId, results, atMs));
85632
85856
  } finally {
85633
85857
  this.pendingWakes.delete(setId);
85634
85858
  }
85635
- const judged = await this.judgeFreshness(stills.sensorId, results, atMs);
85636
85859
  for (const r of judged) this.logTile(stills.sensorId, r);
85637
85860
  const landed = judged.filter(isLandedTile);
85638
85861
  const composed = await this.compose(stills.sensorId, landed, atMs);
@@ -85679,6 +85902,16 @@ var NcLinkedStillShelf = class {
85679
85902
  if (verdict.reason === "waking" && ctx.options.wakeSleeping) return this.awaitWaking(cameraId, ctx);
85680
85903
  if (verdict.reason === "unreachable" && ctx.options.wakeSleeping) return excluded("wake-skipped:unreachable");
85681
85904
  if (verdict.reason !== null) return excluded(verdict.reason);
85905
+ if (verdict.unknown !== null && capture.outcome === "empty" && ctx.options.wakeSleeping && await this.isBatteryCamera(cameraId)) {
85906
+ this.deps.logger.info("linked camera state unknown and capture empty — waking as a battery camera", {
85907
+ tags: { deviceId: cameraId },
85908
+ meta: {
85909
+ sensorId: ctx.sensorId,
85910
+ stateUnknown: verdict.unknown
85911
+ }
85912
+ });
85913
+ return this.wakeOne(cameraId, ctx);
85914
+ }
85682
85915
  return {
85683
85916
  cameraId,
85684
85917
  ...capture,
@@ -85686,6 +85919,20 @@ var NcLinkedStillShelf = class {
85686
85919
  tookMs: took()
85687
85920
  };
85688
85921
  }
85922
+ /** Only a camera KNOWN to be a battery camera is woken on an unknown state. */
85923
+ async isBatteryCamera(cameraId) {
85924
+ const read = this.deps.isBatteryCamera;
85925
+ if (read === void 0) return false;
85926
+ try {
85927
+ return await withTimeout$2(read(cameraId), SENSOR_LINKED_BATTERY_READ_TIMEOUT_MS, "battery read") === true;
85928
+ } catch (err) {
85929
+ this.deps.logger.warn("linked camera battery read failed — not woken on an unknown state", {
85930
+ tags: { deviceId: cameraId },
85931
+ meta: { error: String(err) }
85932
+ });
85933
+ return false;
85934
+ }
85935
+ }
85689
85936
  /** D998: one forced capture, by the rule's leave, at most once per gap per camera. */
85690
85937
  async wakeOne(cameraId, ctx) {
85691
85938
  const took = () => this.deps.now() - ctx.startedAt;
@@ -85747,8 +85994,46 @@ var NcLinkedStillShelf = class {
85747
85994
  };
85748
85995
  }
85749
85996
  markPending(ctx) {
85750
- const until = ctx.startedAt + NC_LINKED_WAKE_CAPTURE_TIMEOUT_MS + NC_LINKED_WAKE_POLL_MS;
85751
- this.pendingWakes.set(ctx.setId, Math.max(this.pendingWakes.get(ctx.setId) ?? 0, until));
85997
+ this.markPendingUntil(ctx.setId, ctx.startedAt + NC_LINKED_WAKE_CAPTURE_TIMEOUT_MS + NC_LINKED_WAKE_POLL_MS);
85998
+ }
85999
+ markPendingUntil(setId, until) {
86000
+ this.pendingWakes.set(setId, Math.max(this.pendingWakes.get(setId) ?? 0, until));
86001
+ }
86002
+ /**
86003
+ * D60: a `stale` tile asks again (unforced — a poll never wakes) until its
86004
+ * frame is from the event or the bound is spent; the row's still-wait is held
86005
+ * open meanwhile. A camera that never freshens stays `stale`, said on its line.
86006
+ */
86007
+ async repollStale(ctx, atMs, judged) {
86008
+ let current = judged;
86009
+ if (!current.some((r) => r.outcome === "stale")) return current;
86010
+ this.markPendingUntil(ctx.setId, this.deps.now() + NC_LINKED_STALE_POLL_MS * 6);
86011
+ for (let i = 0; i < NC_LINKED_STALE_MAX_POLLS; i++) {
86012
+ const waiting = current.filter((r) => r.outcome === "stale").map((r) => r.cameraId);
86013
+ if (waiting.length === 0) break;
86014
+ await new Promise((resolve) => setTimeout(resolve, NC_LINKED_STALE_POLL_MS));
86015
+ const landedAgain = (await Promise.all(waiting.map(async (cameraId) => {
86016
+ const capture = await this.captureStill(cameraId, false, SENSOR_LINKED_CAPTURE_TIMEOUT_MS);
86017
+ return capture.outcome === "landed" && capture.jpeg !== void 0 ? {
86018
+ cameraId,
86019
+ outcome: "landed",
86020
+ jpeg: capture.jpeg,
86021
+ tookMs: this.deps.now() - ctx.startedAt
86022
+ } : null;
86023
+ }))).filter((r) => r !== null);
86024
+ if (landedAgain.length === 0) continue;
86025
+ const rejudged = await this.judgeFreshness(ctx.sensorId, landedAgain, atMs);
86026
+ const fresh = new Map(rejudged.filter((r) => r.outcome === "landed").map((r) => [r.cameraId, r]));
86027
+ current = current.map((r) => fresh.get(r.cameraId) ?? r);
86028
+ for (const cameraId of fresh.keys()) this.deps.logger.info("linked camera frame was stale — a re-poll brought one from the event", {
86029
+ tags: { deviceId: cameraId },
86030
+ meta: {
86031
+ sensorId: ctx.sensorId,
86032
+ polls: i + 1
86033
+ }
86034
+ });
86035
+ }
86036
+ return current;
85752
86037
  }
85753
86038
  /** A wake that brought nothing back names itself, not the generic `empty`. */
85754
86039
  asWakeResult(capture) {
@@ -85817,9 +86102,17 @@ var NcLinkedStillShelf = class {
85817
86102
  unknown: null
85818
86103
  };
85819
86104
  } catch (err) {
86105
+ const timedOut = err instanceof LinkedReadTimeout;
86106
+ this.deps.logger.warn("linked camera snapshot state read failed — state unknown", {
86107
+ tags: { deviceId: cameraId },
86108
+ meta: {
86109
+ error: String(err),
86110
+ timedOut
86111
+ }
86112
+ });
85820
86113
  return {
85821
86114
  reason: null,
85822
- unknown: err instanceof LinkedReadTimeout ? "timeout" : "error"
86115
+ unknown: timedOut ? "timeout" : "error"
85823
86116
  };
85824
86117
  }
85825
86118
  }
@@ -107461,6 +107754,7 @@ var NotificationCenter = class {
107461
107754
  this.linkedStills = getSnapshot !== void 0 ? new NcLinkedStillShelf({
107462
107755
  getSnapshot,
107463
107756
  ...deps.getSnapshotState !== void 0 ? { getSnapshotState: deps.getSnapshotState } : {},
107757
+ ...deps.isBatteryCamera !== void 0 ? { isBatteryCamera: deps.isBatteryCamera } : {},
107464
107758
  ...deps.getFrameCapturedAt !== void 0 ? { getFrameCapturedAt: deps.getFrameCapturedAt } : {},
107465
107759
  isOnline: (id) => this.deviceDirectory.get(id)?.online,
107466
107760
  logger: this.logger.child("linked-stills"),
@@ -110232,6 +110526,7 @@ var BuildNotificationCenter = class extends BuildNotificationCenterBase {
110232
110526
  now: () => Date.now()
110233
110527
  }),
110234
110528
  ...buildLinkedSnapshotReads(api.snapshot),
110529
+ isBatteryCamera: async (deviceId) => await api.battery.getStatus.query({ deviceId }) !== null,
110235
110530
  identityIdsByName: async () => {
110236
110531
  const byName = /* @__PURE__ */ new Map();
110237
110532
  const identities = await stores.identityStore.listIdentities();
@@ -114429,6 +114724,12 @@ function deliveredIdempotencyKey(entryId) {
114429
114724
  function pickedUpIdempotencyKey(entryId) {
114430
114725
  return `pa-pkg-${entryId}-pickedup`;
114431
114726
  }
114727
+ /**
114728
+ * How long a delivery waits for its still to be written before it ships
114729
+ * without one. Under the notification still poll (`NC_STILL_WAIT_MS`, 3 s) so
114730
+ * a slow store never holds the alert longer than the dispatcher would.
114731
+ */
114732
+ var PACKAGE_FRAME_PERSIST_BOUND_MS = 2e3;
114432
114733
  var PackageDropDetector = class {
114433
114734
  deps;
114434
114735
  /** Per-device mirror of the last LOGGED value of the `packageDropEnabled`
@@ -114442,6 +114743,62 @@ var PackageDropDetector = class {
114442
114743
  * LLM gate (D931). `null` means the delivery is dropped (no, or no yes).
114443
114744
  * An empty object means the rule did not ask. A verdict is spread onto the row.
114444
114745
  */
114746
+ /**
114747
+ * The delivery's still, written once under `object:<rowId>` when the entry
114748
+ * had no key frame. Never throws and never waits past
114749
+ * {@link PACKAGE_FRAME_PERSIST_BOUND_MS}: a delivery without a picture still
114750
+ * ships, and says why (D391).
114751
+ */
114752
+ async persistDeliveryStill(entry, rowId, timestamp) {
114753
+ const persist = this.deps.persistDeliveryFrame;
114754
+ if (persist === void 0) return void 0;
114755
+ const tags = { deviceId: entry.deviceId };
114756
+ const meta = {
114757
+ entryId: entry.id,
114758
+ rowId
114759
+ };
114760
+ let timer;
114761
+ try {
114762
+ const bound = new Promise((resolve) => {
114763
+ timer = setTimeout(() => resolve("timeout"), PACKAGE_FRAME_PERSIST_BOUND_MS);
114764
+ });
114765
+ const written = await Promise.race([persist({
114766
+ deviceId: entry.deviceId,
114767
+ trackId: entry.sourceTrackId ?? entry.id,
114768
+ rowId,
114769
+ timestamp
114770
+ }), bound]);
114771
+ if (written === "timeout") {
114772
+ this.deps.logger.warn("package delivery still not written in time — shipping without it", {
114773
+ tags,
114774
+ meta: {
114775
+ ...meta,
114776
+ boundMs: PACKAGE_FRAME_PERSIST_BOUND_MS
114777
+ }
114778
+ });
114779
+ return;
114780
+ }
114781
+ if (written === null) {
114782
+ this.deps.logger.warn("package delivery has no frame to write — shipping without a still", {
114783
+ tags,
114784
+ meta
114785
+ });
114786
+ return;
114787
+ }
114788
+ return written;
114789
+ } catch (err) {
114790
+ this.deps.logger.warn("package delivery still write failed — shipping without it", {
114791
+ tags,
114792
+ meta: {
114793
+ ...meta,
114794
+ error: errMsg(err)
114795
+ }
114796
+ });
114797
+ return;
114798
+ } finally {
114799
+ if (timer !== void 0) clearTimeout(timer);
114800
+ }
114801
+ }
114445
114802
  async llmFields(entry, rules, hitZones, tags) {
114446
114803
  if (!rules.some((rule) => rule.confirmWithLlm === true && rule.zoneIds.some((id) => hitZones.includes(id)))) return {};
114447
114804
  const confirm = this.deps.confirmPackage;
@@ -114703,6 +115060,7 @@ var PackageDropDetector = class {
114703
115060
  });
114704
115061
  return;
114705
115062
  }
115063
+ const keyFrameMediaId = entry.keyFrameMediaId ?? await this.persistDeliveryStill(entry, rowId, rowTimestamp);
114706
115064
  const ev = {
114707
115065
  ...draft,
114708
115066
  id: rowId
@@ -114714,7 +115072,7 @@ var PackageDropDetector = class {
114714
115072
  eventId: String(rowId),
114715
115073
  className: entry.className,
114716
115074
  zoneIds: hitZones,
114717
- ...entry.keyFrameMediaId !== void 0 ? { keyFrameMediaId: entry.keyFrameMediaId } : {},
115075
+ ...keyFrameMediaId !== void 0 ? { keyFrameMediaId } : {},
114718
115076
  bbox: {
114719
115077
  x: entry.bbox.x,
114720
115078
  y: entry.bbox.y,
@@ -118277,6 +118635,7 @@ var BuildStores = class extends BuildStoresBase {
118277
118635
  resolveSettings: (deviceId) => this.resolveDevicePackageDropSettings(deviceId),
118278
118636
  resolveZoneMembershipMinOverlap: async (deviceId) => (await this.resolveDeviceTrackingSettings(deviceId)).zoneMembershipMinOverlap,
118279
118637
  confirmPackage: (input) => this.deps.confirmPackage(input),
118638
+ persistDeliveryFrame: (request) => this.deps.persistPackageDeliveryFrame(request),
118280
118639
  onLlmSilence: (edge) => {
118281
118640
  const deviceId = edge.phase === "silent" ? edge.note.deviceId : edge.deviceId;
118282
118641
  this.ctx.eventBus.emit({
@@ -120398,108 +120757,6 @@ async function ensureTrackHierarchyMedia(deps, input) {
120398
120757
  await Promise.all(tasks);
120399
120758
  }
120400
120759
  //#endregion
120401
- //#region src/pipeline-analytics/pipeline/key-frame-persist.ts
120402
- /**
120403
- * A box is written only when it can be USED — a degenerate rectangle, or one
120404
- * measured on a degenerate frame, says nothing and would read back as a box at
120405
- * the origin. Absent is the honest answer; the reader then pairs a snapshot,
120406
- * exactly as it did before D510.
120407
- *
120408
- * Its result is spread into BOTH writes: the small companion is derived from
120409
- * the very bytes of the native one, so it is the same scene at the same
120410
- * instant and the box maps into it by ratio like any other scale of the frame.
120411
- * A box on one row and not the other would make the summary's answer depend on
120412
- * which row a reader happened to pick.
120413
- */
120414
- function isStatableSubject(subject) {
120415
- if (subject === void 0) return false;
120416
- return subject.w > 0 && subject.h > 0 && subject.frameWidth > 0 && subject.frameHeight > 0;
120417
- }
120418
- /**
120419
- * Read, derive and store one track's key frame + its web companion.
120420
- *
120421
- * PARCEL-OR-NOTHING: no parcel writes nothing and the caller's bounded retry
120422
- * parks a later frame. The `keyFrame` write lands FIRST and its media id (D482)
120423
- * is what the outcome carries — a `keyFrameSmall` failure afterwards must not
120424
- * re-arm a retry that would re-shoot a key frame the rebuild can already read.
120425
- */
120426
- async function persistTrackKeyFrame(deps, input) {
120427
- const { deviceId, trackId, retry } = input;
120428
- const drop = {
120429
- tags: { deviceId },
120430
- meta: {
120431
- trackId,
120432
- retry
120433
- }
120434
- };
120435
- try {
120436
- const parcel = await deps.fetchParkedKeyFrame(deviceId, trackId);
120437
- if (parcel === null || parcel.jpeg.byteLength === 0) {
120438
- deps.logger.error("key-frame parcel missing — nothing to write, retry parks a later frame", { ...drop });
120439
- return { kind: "parcel-missing" };
120440
- }
120441
- const subjectBox = isStatableSubject(parcel.subject) ? { subjectBox: parcel.subject } : {};
120442
- const keyFrameMediaId = await deps.media.putReplacing({
120443
- deviceId,
120444
- ownerKind: "track",
120445
- ownerId: trackId,
120446
- kind: "keyFrame",
120447
- timestamp: parcel.timestamp,
120448
- data: parcel.jpeg,
120449
- ...subjectBox
120450
- });
120451
- try {
120452
- const keyFrameSmall = await deps.deriveSmall(parcel.jpeg);
120453
- await deps.media.putReplacing({
120454
- deviceId,
120455
- ownerKind: "track",
120456
- ownerId: trackId,
120457
- kind: "keyFrameSmall",
120458
- timestamp: parcel.timestamp,
120459
- data: keyFrameSmall,
120460
- ...subjectBox
120461
- });
120462
- } catch (err) {
120463
- deps.logger.warn("keyFrameSmall write failed — the native keyFrame is stored", {
120464
- ...drop,
120465
- meta: {
120466
- ...drop.meta,
120467
- nodeId: parcel.nodeId,
120468
- error: errMsg(err)
120469
- }
120470
- });
120471
- }
120472
- deps.logger.debug("key frame written from the parked parcel", {
120473
- ...drop,
120474
- meta: {
120475
- ...drop.meta,
120476
- nodeId: parcel.nodeId,
120477
- width: parcel.width,
120478
- height: parcel.height,
120479
- bytes: parcel.jpeg.byteLength,
120480
- parkedTimestamp: parcel.timestamp
120481
- }
120482
- });
120483
- return {
120484
- kind: "landed",
120485
- keyFrameMediaId
120486
- };
120487
- } catch (err) {
120488
- const error = errMsg(err);
120489
- deps.logger.warn("key-frame write failed", {
120490
- ...drop,
120491
- meta: {
120492
- ...drop.meta,
120493
- error
120494
- }
120495
- });
120496
- return {
120497
- kind: "error",
120498
- error
120499
- };
120500
- }
120501
- }
120502
- //#endregion
120503
120760
  //#region src/pipeline-analytics/pipeline/key-frame-retry.ts
120504
120761
  /** Retry-path attempts allowed per track. The operator's number. */
120505
120762
  var KEY_FRAME_MAX_RETRIES = 3;
@@ -122083,6 +122340,8 @@ var DEFAULT_ASSIST_MIN_SCORE = .3;
122083
122340
  * cannot page the whole table into memory to build a manifest.
122084
122341
  */
122085
122342
  var RETRAIN_EXPORT_MAX = 2e4;
122343
+ /** How far back a restart looks for a level cap's last persisted boolean. */
122344
+ var LEVEL_SEED_WINDOW_MS = 48 * 36e5;
122086
122345
  /**
122087
122346
  * Pipeline Analytics addon — subscribes to `PipelineInferenceResult` +
122088
122347
  * `PipelineAudioInferenceResult` on the bus, refines raw detections
@@ -122358,7 +122617,15 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
122358
122617
  */
122359
122618
  sensorTransitions = new SensorTransitionGate({
122360
122619
  startedAtMs: Date.now(),
122361
- now: () => Date.now()
122620
+ now: () => Date.now(),
122621
+ readSeed: (deviceId, capName) => this.readPersistedLevel(deviceId, capName),
122622
+ onSeedFailed: (deviceId, capName, error) => this.ctx.logger.warn("level seed read failed — gate starts unseeded", {
122623
+ tags: { deviceId },
122624
+ meta: {
122625
+ capName,
122626
+ error: errMsg(error)
122627
+ }
122628
+ })
122362
122629
  });
122363
122630
  /** `camera-index-unknown` drops, summarised per window — see the file. */
122364
122631
  cameraIndexUnknownDrops = new CameraIndexUnknownDrops({ nowMs: Date.now() });
@@ -124170,6 +124437,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
124170
124437
  this.packageDropDetector = value;
124171
124438
  },
124172
124439
  confirmPackage: (input) => this.confirmPackageDelivery(input),
124440
+ persistPackageDeliveryFrame: (request) => this.persistPackageDeliveryFrame(request),
124173
124441
  stationaryEvidence: () => this.stationaryEvidence,
124174
124442
  setStationaryEvidence: (value) => {
124175
124443
  this.stationaryEvidence = value;
@@ -128325,6 +128593,44 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
128325
128593
  via: "frame"
128326
128594
  });
128327
128595
  }
128596
+ /**
128597
+ * #383: a delivery whose entry had no key frame writes the source track's
128598
+ * parked frame under the object row it just created — the one owner the
128599
+ * notification ladder reads for a package event.
128600
+ */
128601
+ async persistPackageDeliveryFrame(request) {
128602
+ const mediaStore = this.mediaStore;
128603
+ if (mediaStore === null) return null;
128604
+ return persistObjectFrame({
128605
+ fetchParkedKeyFrame: async (deviceId, trackId) => {
128606
+ const parcel = await this.mediaCapture.fetchParkedParcel(trackId, "keyFrame");
128607
+ if (parcel === null || parcel.info.deviceId !== deviceId) return null;
128608
+ const subject = parcel.info.subject;
128609
+ return {
128610
+ jpeg: parcel.jpeg,
128611
+ width: parcel.width,
128612
+ height: parcel.height,
128613
+ timestamp: parcel.timestamp,
128614
+ nodeId: parcel.info.nodeId,
128615
+ subject: {
128616
+ x: subject.bbox.x,
128617
+ y: subject.bbox.y,
128618
+ w: subject.bbox.w,
128619
+ h: subject.bbox.h,
128620
+ frameWidth: subject.frameWidth,
128621
+ frameHeight: subject.frameHeight
128622
+ }
128623
+ };
128624
+ },
128625
+ media: mediaStore,
128626
+ logger: this.ctx.logger
128627
+ }, {
128628
+ deviceId: request.deviceId,
128629
+ trackId: request.trackId,
128630
+ objectId: String(request.rowId),
128631
+ timestamp: request.timestamp
128632
+ });
128633
+ }
128328
128634
  async confirmPackageDelivery(input) {
128329
128635
  const crops = this.packageScene?.cropsFor(input.deviceId);
128330
128636
  return confirmPackageWithLlm({
@@ -129326,7 +129632,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
129326
129632
  const store = this.sensorEventStore;
129327
129633
  const cache = this.linkedCamerasCache;
129328
129634
  if (store === null || cache === null) return;
129329
- if (!this.sensorSliceCarriedATransition(data)) return;
129635
+ if (!await this.sensorSliceCarriedATransition(data)) return;
129330
129636
  const cameras = await resolveSensorNotificationCameras(cache, data).catch((err) => {
129331
129637
  this.ctx.logger.debug("linked-camera resolution failed — evaluated per row", {
129332
129638
  tags: { deviceId: data.deviceId },
@@ -129494,7 +129800,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
129494
129800
  * The drops are SUMMARISED, never logged one by one: this path carries every
129495
129801
  * camera's native `motion` slice at motion rate.
129496
129802
  */
129497
- sensorSliceCarriedATransition(data) {
129803
+ async sensorSliceCarriedATransition(data) {
129498
129804
  const slice = data.slice;
129499
129805
  if (typeof slice !== "object" || slice === null || Array.isArray(slice)) {
129500
129806
  this.ctx.logger.debug("sensor state change carried no slice — dropped", {
@@ -129503,7 +129809,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
129503
129809
  });
129504
129810
  return false;
129505
129811
  }
129506
- const verdict = this.sensorTransitions.observe(data.deviceId, data.capName, { ...slice });
129812
+ const verdict = await this.sensorTransitions.observeSettled(data.deviceId, data.capName, { ...slice });
129507
129813
  this.flushSensorTransitionDrops();
129508
129814
  if (verdict.changed) {
129509
129815
  const entries = Object.entries(slice);
@@ -129521,6 +129827,35 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
129521
129827
  return verdict.changed;
129522
129828
  }
129523
129829
  /**
129830
+ * The last persisted boolean of a level cap, from device-history — the
129831
+ * gate's seed after a restart. Off the event path (the gate starts it at the
129832
+ * first sighting). A cap that declares no history field, or a series with no
129833
+ * point, answers `null`.
129834
+ */
129835
+ async readPersistedLevel(deviceId, capName) {
129836
+ const key = levelSeriesKey(capName);
129837
+ if (key === null) return null;
129838
+ const to = Date.now();
129839
+ const result = await this.ctx.api.deviceHistory.query.query({
129840
+ deviceId,
129841
+ key,
129842
+ from: to - LEVEL_SEED_WINDOW_MS,
129843
+ to,
129844
+ resolution: "raw",
129845
+ maxPoints: 200
129846
+ });
129847
+ const latest = result.series.flatMap((s) => s.points).reduce((best, p) => best === null || p.t > best.t ? p : best, null);
129848
+ if (latest !== null && latest.last !== null) return {
129849
+ value: latest.last >= .5,
129850
+ since: latest.t
129851
+ };
129852
+ const held = result.series.flatMap((s) => s.before === null ? [] : [s.before]).reduce((best, b) => best === null || b.t > best.t ? b : best, null);
129853
+ return held !== null && held.value !== null ? {
129854
+ value: held.value >= .5,
129855
+ since: held.t
129856
+ } : null;
129857
+ }
129858
+ /**
129524
129859
  * One `info` line per (device, cap, reason) per window, or none.
129525
129860
  *
129526
129861
  * A branch that drops work says so — but this one drops ~0.6 events/s