@camstack/addon-post-analysis 1.2.641 → 1.2.643
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{clip-model-registry-Cw7Iy7Qi.mjs → clip-model-registry-DdgT3gdf.mjs} +301 -25
- package/dist/{clip-model-registry-Qr0XipkX.js → clip-model-registry-lKeBMKlT.js} +301 -25
- package/dist/embedding-encoder/index.js +1 -1
- package/dist/embedding-encoder/index.mjs +1 -1
- package/dist/pipeline-analytics/_stub.js +2 -2
- package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-Cct0TMzC.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-B6X8TAQP.mjs} +2 -2
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BIjXlrFH.mjs +26 -0
- package/dist/pipeline-analytics/{_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-CuNXxDlT.mjs → _virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js--XkysBjS.mjs} +1 -1
- package/dist/pipeline-analytics/{hostInit-B9c2FowI.mjs → hostInit-CDPfOUWf.mjs} +2 -2
- package/dist/pipeline-analytics/index.js +411 -15
- package/dist/pipeline-analytics/index.mjs +411 -15
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +1 -1
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-_TUthUZh.mjs +0 -26
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as MediaFileKindEnum, $i as CAP_ADVANCE_FIELDS, $n as cloneAlarmSettings, $r as paintHex, $t as OpsLogEntrySchema, A as DeclaredDevices, Aa as EventCategory, Ai as subKindsOf, An as TrackSideSchema, Ar as isAudioClassName, At as NcAlarmSensorsInputSchema, B as FULL_IMAGE_BBOX, Bi as templateCarriesSummary, Bn as applyModeDelaysEdits, Br as isRootSuppliableStepId, Bt as NcRuleUpdateInputSchema, C as ClearTrackRelationResultSchema, Ca as record, Ci as ruleKindOf, Cn as TimelapseRuleInputSchema, Cr as failureContributionCapability, Ct as NC_SNOOZE_MAX_MINUTES, D as DEFAULT_TIMELAPSE_PREVIEW_TEXT, Da as tuple, Di as servedTemplateVars, Dn as TrackPuritySchema, Dr as isAlertEpisodeOpen, Dt as NC_TEMPLATE_VARS, E as DEFAULT_EVENT_COLOR, Ea as templateLiteral, Ei as sensorRaisedOf, En as TrackPlacementSchema, Er as isAlarmControllableCap, Et as NC_TAXONOMY, F as EVENT_DENSITY_BATCH_MAX, Fi as systemEventDeliveryProblems, Fn as alarmPanelCapability, Fr as isEventOwnerType, Ft as NcRuleActionSchema, G as ListTrackRelationsResultSchema, Gi as zoneAnalyticsCapability, Gn as audioMetricsCapability, Gr as kebabToCamel, Gt as NcSnoozeSuppressedSchema, H as LABEL_SUPPLY_MACRO, Hi as vectorDimFromBase64, Hn as applySecureOnArmEdit, Hr as isSystemDelivery, Ht as NcSharedSequenceSchema, I as EVENT_KIND_BY_CAP, Ii as systemEventFamilyProblems, In as alertEpisodeId, Ir as isKnownTemplateVar, It as NcRuleInputSchema, J as MAX_BIRTH_DECISION_RECORDS, Ji as evaluateSensorEdge, Jn as buildSubjectPath, Jr as memoizePinnedFfmpeg, Jt as NcTaxonomySchema, K as LockStateSchema, Ki as DEFAULT_FIRST_SIGHTING_FRESHNESS_MS, Kn as audioModeOf, Kr as linkedStepOf, Kt as NcStateSummarySectionIdSchema, L as EVENT_OWNER_TYPES, Li as systemEventFilterApplies, Ln as alertEpisodeKind, Lr as isLabelSupplyStepId, Lt as NcRulePatchSchema, M as EMBEDDING_MODEL_FAILED, Mi as subjectPathSvgPoints, Mn as activateAlarmProfile, Mr as isDetectionMacroClass, Mt as NcAlarmSettingsPatchSchema, N as EMBEDDING_REQUIREMENTS_FAILED, Ni as summarizeReview, Nn as addonWidgetsSourceCapability, Nr as isDrawableSubjectPath, Nt as NcConditionDescriptorSchema, O as DETECTION_MACRO_CLASSES, Oa as union, Oi as startMoverUnderClearance, On as TrackRelationKindSchema, Or as isAlertEpisodeSeverity, Ot as NcAlarmConfigSchema, P as EMBEDDING_REQUIREMENTS_UNAVAILABLE, Pi as syncActiveAlarmProfileSettings, Pn as alarmDeviceSecureOnArm, Pr as isEventKindLabelKey, Pt as NcConditionsSchema, Q as MOTION_CLOSE_AFTER_MS, Qi as BaseAddon, Qn as classifyRetrainReview, Qr as occupancyScope, Qt as OPS_LOG_DEFAULT_LIMIT, R as EXPORT_DENSE_MAX_RANGES, Ri as systemEventSummaryScheduleOf, Rn as alertEpisodePayload, Rr as isMediaOwnerType, Rt as NcRuleSchema, S as ClearTrackRelationInputSchema, Sa as partialRecord, Si as ruleGroupingApplies, Sn as TRACK_RELATIONS_DEFAULT_LIMIT, Sr as faceGalleryCapability, St as NC_SENSOR_TRANSITION_KINDS, T as DEFAULT_DETAIL_CROP_CONVENTION, Ta as string, Ti as secureActuationFor, Tn as TimelapseRuleSchema, Tr as gifFromMp4Args, Tt as NC_SYSTEM_EVENT_KIND_GROUP_SPECS, U as LabelAttributionSchema, Ui as viewerLinkBaseOf, Un as armRemovalReconcile, Ur as isSystemEventSummaryRule, Ut as NcSnoozeInputSchema, V as FailureCounters, Vi as templateVarsFor, Vn as applyNonBlockingEdit, Vr as isScheduleActive, Vt as NcScheduleSchema, W as ListTrackRelationsInputSchema, Wi as withSystemEventClasses, Wn as assertTimelapseCadences, Wr as isVectorIndexDimConflict, Wt as NcSnoozeSchema, X as MAX_TRACK_PURITIES, Xi as DeviceType, Xn as bundledCamstack, Xr as normalizeNcMediaPolicy, Xt as NcTemplatePreviewSchema, Y as MAX_BIRTH_LATENCY_PROXY_MS, Yi as isSourceCap, Yn as buildViewerLink, Yr as ncMediaPolicyError, Yt as NcTemplatePreviewInputSchema, Z as MAX_TRACK_RELATIONS, Zi as errMsg, Zn as calendarEventLocalSpan, Zr as notificationRulesCapability, Zt as NcTemplateVarDescriptorSchema, _ as BIRTH_DECISION_DEFAULT_LIMIT, _a as discriminatedUnion, _i as retrainRevisionConflictMessage, _n as SceneMonitorSchema, _t as NC_CONSUMABLE_SYSTEM_EVENT_KINDS, a as CLIP_EMBEDDING_STEP_ID, aa as customAction, ai as plateGalleryCapability, an as RetrainDismissedSchema, ar as deleteAlarmProfile, at as NC_ALARM_NOTIFY_FIELDS, b as BucketAccumulator, ba as number, bi as ruleBelongsToAlarm$1, bn as SetTrackRelationInputSchema, br as eventKindLabel, bt as NC_GROUPING_MAX_SEC, c as readClusterModelPinStrict, ca as hydrateSchema, ci as readMotionTriggeredBy, cn as SCENE_CONFIRM_DEFAULT_MAX_IMAGE_PX, cr as deriveRecordingMode, ct as NC_AUDIO_CONFIRM_HITS_DEFAULT, d as APPEARANCE_BLOCKS, di as resolveClipSearchMinScore, dn as SCENE_DEFAULT_CHECK_INTERVAL_SEC, dr as deviceAttentionKind, dt as NC_CLIP_PRE_ROLL_DEFAULT_SEC, ea as CamProfileSchema, ei as paletteResultSchema, en as PackageLlmVerdictSchema, er as consumableFormOf, et as MotionTriggeredBySchema, f as APPEARANCE_RESOLVES_AMBIGUITY_DEFAULT, fa as sleep$1, fi as resolveLocationMode, fn as SCENE_DEFAULT_OBSERVATION_SPACING_SEC, fr as deviceRemovalHookCapability, ft as NC_CLIP_RETENTION_MAX_SEC, g as ArchivedDebugNoteSchema, ga as boolean, gn as SCENE_RESET_RECAPTURES, gt as NC_CONSUMABLE_LOW_PERCENT_DEFAULT, h as AlarmArmModeSchema, ha as array, hi as resolveNcMediaImage, hn as SCENE_DIVERGED, hr as embeddingRefusalOf, ht as NC_CONFIRM_DEFAULT_TIMEOUT_MS, ia as createEvent, ii as pipelineAnalyticsCapability, in as RebuildObjectEmbeddingsRefusalSchema, ir as createAlarmProfile, it as NC_ALARM_DELAY_MAX_SEC, j as DetectionSourceSchema, ji as subjectPathSampleFromBox, jn as TrackSourceSchema, jr as isDefaultAlarmProfileId, jt as NcAlarmSensorsSchema, k as DETECTION_PIPELINE_CAP_NAME, ka as unknown, ki as storageOccupancyCapability, kn as TrackRelationSchema, kr as isAppLinkBase, kt as NcAlarmPostTriggeredActionSchema, l as resolveClusterModelPin, la as isDeviceScopedCap, li as readTimelapseGeneratedAt, ln as SCENE_CONFIRM_DEFAULT_TIMEOUT_MS, lr as describeSystemEventDeliveryProblem, lt as NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT, m as AUDIO_MACRO_LABELS, ma as _enum, mi as resolveModeNotifyPolicy, mn as SCENE_DEFAULT_UNCOVERED_POLICY, mt as NC_CONFIRM_DEFAULT_MAX_IMAGE_PX, na as RECORD_MAX_DATA_BYTES, nn as RECORDING_EXPORT_MAX_READ_BYTES, nr as coreBlockIdFromAddonId, nt as NC_ALARM_DEFAULT_TRIGGERED_DURATION_SEC, o as CLUSTER_MODEL_OWNER_ADDON_ID, oa as defineCustomActions, oi as projectSubjectPath, on as RetrainOriginSchema, or as deriveDetailCropRect, ot as NC_ALARM_SYSTEM_EVENT_KINDS, p as ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT, pa as ZodObject, pi as resolveModeDelays, pn as SCENE_DEFAULT_QUIET_SECONDS, pt as NC_CONDITION_CATALOG, q as MAX_ARCHIVED_DEBUG_NOTES, qi as canonicalHash, qn as buildEventKindDescriptor, qr as mayWriteToLocation, qt as NcSystemEventKindSchema, ra as RECORD_QUERY_MAX, ri as pickFaceRescoreIntervalMinutes, rn as RECORDING_SOURCE_CAMSTACK_ADDON, rr as cosineSimilarity$1, rt as NC_ALARM_DELAY_FIELDS, s as FACE_EMBEDDING_STEP_ID, sa as defineRecordKinds, si as readDeviceStateFrom, sn as RetrainStatusSchema, sr as derivePostTriggeredAction, st as NC_ALARM_TRIGGERED_MAX_SEC, t as BUILTIN_CLIP_MODELS, ta as InvalidRecordError, ti as parseAlertEpisodePayload, tr as consumableLowPercentOf, tt as NC_ALARM_DEFAULT_PROFILE_ID, u as APPEARANCE_BIN_COUNT, ua as nodePin, ui as renameAlarmProfile, un as SCENE_DEFAULT_ANCHOR_THRESHOLD, ur as describeSystemEventFamilyProblem, ut as NC_CLIP_POST_ROLL_DEFAULT_SEC, v as BaseDevice, va as literal, vi as rootSupplyServes, vn as SetTrackPurityInputSchema, vr as encodeVectorBase64, vt as NC_DEFAULT_SNOOZE_MINUTES, w as CoverStateSchema, wa as strictObject, wi as sceneMonitorCapability, wn as TimelapseRulePatchSchema, wr as gifDeriveSpeed, wt as NC_STATE_SUMMARY_SECTION_IDS, x as COCO_TO_MACRO, xa as object, xi as ruleDeviceCompatCapQueries, xn as TIMELAPSE_DENSE_FLOOR_SEC, xr as evictionPolicyOfLocation, xt as NC_GROUPING_MIN_SEC, y as BirthDecisionRecordSchema, ya as looseObject, yi as ruleAutoTriggersAlarm, yn as SetTrackPurityResultSchema, yr as ensureAlarmProfiles, yt as NC_GROUPING_DEFAULT_SEC, z as FIRST_LEVEL_MACRO_CLASSES, zi as systemEventSummarySplitOf, zn as applyBlockingEdit, zr as isRetiredClearKey, zt as NcRuleTargetSchema } from "../clip-model-registry-
|
|
1
|
+
import { $ as MediaFileKindEnum, $i as CAP_ADVANCE_FIELDS, $n as cloneAlarmSettings, $r as paintHex, $t as OpsLogEntrySchema, A as DeclaredDevices, Aa as EventCategory, Ai as subKindsOf, An as TrackSideSchema, Ar as isAudioClassName, At as NcAlarmSensorsInputSchema, B as FULL_IMAGE_BBOX, Bi as templateCarriesSummary, Bn as applyModeDelaysEdits, Br as isRootSuppliableStepId, Bt as NcRuleUpdateInputSchema, C as ClearTrackRelationResultSchema, Ca as record, Ci as ruleKindOf, Cn as TimelapseRuleInputSchema, Cr as failureContributionCapability, Ct as NC_SNOOZE_MAX_MINUTES, D as DEFAULT_TIMELAPSE_PREVIEW_TEXT, Da as tuple, Di as servedTemplateVars, Dn as TrackPuritySchema, Dr as isAlertEpisodeOpen, Dt as NC_TEMPLATE_VARS, E as DEFAULT_EVENT_COLOR, Ea as templateLiteral, Ei as sensorRaisedOf, En as TrackPlacementSchema, Er as isAlarmControllableCap, Et as NC_TAXONOMY, F as EVENT_DENSITY_BATCH_MAX, Fi as systemEventDeliveryProblems, Fn as alarmPanelCapability, Fr as isEventOwnerType, Ft as NcRuleActionSchema, G as ListTrackRelationsResultSchema, Gi as zoneAnalyticsCapability, Gn as audioMetricsCapability, Gr as kebabToCamel, Gt as NcSnoozeSuppressedSchema, H as LABEL_SUPPLY_MACRO, Hi as vectorDimFromBase64, Hn as applySecureOnArmEdit, Hr as isSystemDelivery, Ht as NcSharedSequenceSchema, I as EVENT_KIND_BY_CAP, Ii as systemEventFamilyProblems, In as alertEpisodeId, Ir as isKnownTemplateVar, It as NcRuleInputSchema, J as MAX_BIRTH_DECISION_RECORDS, Ji as evaluateSensorEdge, Jn as buildSubjectPath, Jr as memoizePinnedFfmpeg, Jt as NcTaxonomySchema, K as LockStateSchema, Ki as DEFAULT_FIRST_SIGHTING_FRESHNESS_MS, Kn as audioModeOf, Kr as linkedStepOf, Kt as NcStateSummarySectionIdSchema, L as EVENT_OWNER_TYPES, Li as systemEventFilterApplies, Ln as alertEpisodeKind, Lr as isLabelSupplyStepId, Lt as NcRulePatchSchema, M as EMBEDDING_MODEL_FAILED, Mi as subjectPathSvgPoints, Mn as activateAlarmProfile, Mr as isDetectionMacroClass, Mt as NcAlarmSettingsPatchSchema, N as EMBEDDING_REQUIREMENTS_FAILED, Ni as summarizeReview, Nn as addonWidgetsSourceCapability, Nr as isDrawableSubjectPath, Nt as NcConditionDescriptorSchema, O as DETECTION_MACRO_CLASSES, Oa as union, Oi as startMoverUnderClearance, On as TrackRelationKindSchema, Or as isAlertEpisodeSeverity, Ot as NcAlarmConfigSchema, P as EMBEDDING_REQUIREMENTS_UNAVAILABLE, Pi as syncActiveAlarmProfileSettings, Pn as alarmDeviceSecureOnArm, Pr as isEventKindLabelKey, Pt as NcConditionsSchema, Q as MOTION_CLOSE_AFTER_MS, Qi as BaseAddon, Qn as classifyRetrainReview, Qr as occupancyScope, Qt as OPS_LOG_DEFAULT_LIMIT, R as EXPORT_DENSE_MAX_RANGES, Ri as systemEventSummaryScheduleOf, Rn as alertEpisodePayload, Rr as isMediaOwnerType, Rt as NcRuleSchema, S as ClearTrackRelationInputSchema, Sa as partialRecord, Si as ruleGroupingApplies, Sn as TRACK_RELATIONS_DEFAULT_LIMIT, Sr as faceGalleryCapability, St as NC_SENSOR_TRANSITION_KINDS, T as DEFAULT_DETAIL_CROP_CONVENTION, Ta as string, Ti as secureActuationFor, Tn as TimelapseRuleSchema, Tr as gifFromMp4Args, Tt as NC_SYSTEM_EVENT_KIND_GROUP_SPECS, U as LabelAttributionSchema, Ui as viewerLinkBaseOf, Un as armRemovalReconcile, Ur as isSystemEventSummaryRule, Ut as NcSnoozeInputSchema, V as FailureCounters, Vi as templateVarsFor, Vn as applyNonBlockingEdit, Vr as isScheduleActive, Vt as NcScheduleSchema, W as ListTrackRelationsInputSchema, Wi as withSystemEventClasses, Wn as assertTimelapseCadences, Wr as isVectorIndexDimConflict, Wt as NcSnoozeSchema, X as MAX_TRACK_PURITIES, Xi as DeviceType, Xn as bundledCamstack, Xr as normalizeNcMediaPolicy, Xt as NcTemplatePreviewSchema, Y as MAX_BIRTH_LATENCY_PROXY_MS, Yi as isSourceCap, Yn as buildViewerLink, Yr as ncMediaPolicyError, Yt as NcTemplatePreviewInputSchema, Z as MAX_TRACK_RELATIONS, Zi as errMsg, Zn as calendarEventLocalSpan, Zr as notificationRulesCapability, Zt as NcTemplateVarDescriptorSchema, _ as BIRTH_DECISION_DEFAULT_LIMIT, _a as discriminatedUnion, _i as retrainRevisionConflictMessage, _n as SceneMonitorSchema, _t as NC_CONSUMABLE_SYSTEM_EVENT_KINDS, a as CLIP_EMBEDDING_STEP_ID, aa as customAction, ai as plateGalleryCapability, an as RetrainDismissedSchema, ar as deleteAlarmProfile, at as NC_ALARM_NOTIFY_FIELDS, b as BucketAccumulator, ba as number, bi as ruleBelongsToAlarm$1, bn as SetTrackRelationInputSchema, br as eventKindLabel, bt as NC_GROUPING_MAX_SEC, c as readClusterModelPinStrict, ca as hydrateSchema, ci as readMotionTriggeredBy, cn as SCENE_CONFIRM_DEFAULT_MAX_IMAGE_PX, cr as deriveRecordingMode, ct as NC_AUDIO_CONFIRM_HITS_DEFAULT, d as APPEARANCE_BLOCKS, di as resolveClipSearchMinScore, dn as SCENE_DEFAULT_CHECK_INTERVAL_SEC, dr as deviceAttentionKind, dt as NC_CLIP_PRE_ROLL_DEFAULT_SEC, ea as CamProfileSchema, ei as paletteResultSchema, en as PackageLlmVerdictSchema, er as consumableFormOf, et as MotionTriggeredBySchema, f as APPEARANCE_RESOLVES_AMBIGUITY_DEFAULT, fa as sleep$1, fi as resolveLocationMode, fn as SCENE_DEFAULT_OBSERVATION_SPACING_SEC, fr as deviceRemovalHookCapability, ft as NC_CLIP_RETENTION_MAX_SEC, g as ArchivedDebugNoteSchema, ga as boolean, gn as SCENE_RESET_RECAPTURES, gt as NC_CONSUMABLE_LOW_PERCENT_DEFAULT, h as AlarmArmModeSchema, ha as array, hi as resolveNcMediaImage, hn as SCENE_DIVERGED, hr as embeddingRefusalOf, ht as NC_CONFIRM_DEFAULT_TIMEOUT_MS, ia as createEvent, ii as pipelineAnalyticsCapability, in as RebuildObjectEmbeddingsRefusalSchema, ir as createAlarmProfile, it as NC_ALARM_DELAY_MAX_SEC, j as DetectionSourceSchema, ji as subjectPathSampleFromBox, jn as TrackSourceSchema, jr as isDefaultAlarmProfileId, jt as NcAlarmSensorsSchema, k as DETECTION_PIPELINE_CAP_NAME, ka as unknown, ki as storageOccupancyCapability, kn as TrackRelationSchema, kr as isAppLinkBase, kt as NcAlarmPostTriggeredActionSchema, l as resolveClusterModelPin, la as isDeviceScopedCap, li as readTimelapseGeneratedAt, ln as SCENE_CONFIRM_DEFAULT_TIMEOUT_MS, lr as describeSystemEventDeliveryProblem, lt as NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT, m as AUDIO_MACRO_LABELS, ma as _enum, mi as resolveModeNotifyPolicy, mn as SCENE_DEFAULT_UNCOVERED_POLICY, mt as NC_CONFIRM_DEFAULT_MAX_IMAGE_PX, na as RECORD_MAX_DATA_BYTES, nn as RECORDING_EXPORT_MAX_READ_BYTES, nr as coreBlockIdFromAddonId, nt as NC_ALARM_DEFAULT_TRIGGERED_DURATION_SEC, o as CLUSTER_MODEL_OWNER_ADDON_ID, oa as defineCustomActions, oi as projectSubjectPath, on as RetrainOriginSchema, or as deriveDetailCropRect, ot as NC_ALARM_SYSTEM_EVENT_KINDS, p as ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT, pa as ZodObject, pi as resolveModeDelays, pn as SCENE_DEFAULT_QUIET_SECONDS, pt as NC_CONDITION_CATALOG, q as MAX_ARCHIVED_DEBUG_NOTES, qi as canonicalHash, qn as buildEventKindDescriptor, qr as mayWriteToLocation, qt as NcSystemEventKindSchema, ra as RECORD_QUERY_MAX, ri as pickFaceRescoreIntervalMinutes, rn as RECORDING_SOURCE_CAMSTACK_ADDON, rr as cosineSimilarity$1, rt as NC_ALARM_DELAY_FIELDS, s as FACE_EMBEDDING_STEP_ID, sa as defineRecordKinds, si as readDeviceStateFrom, sn as RetrainStatusSchema, sr as derivePostTriggeredAction, st as NC_ALARM_TRIGGERED_MAX_SEC, t as BUILTIN_CLIP_MODELS, ta as InvalidRecordError, ti as parseAlertEpisodePayload, tr as consumableLowPercentOf, tt as NC_ALARM_DEFAULT_PROFILE_ID, u as APPEARANCE_BIN_COUNT, ua as nodePin, ui as renameAlarmProfile, un as SCENE_DEFAULT_ANCHOR_THRESHOLD, ur as describeSystemEventFamilyProblem, ut as NC_CLIP_POST_ROLL_DEFAULT_SEC, v as BaseDevice, va as literal, vi as rootSupplyServes, vn as SetTrackPurityInputSchema, vr as encodeVectorBase64, vt as NC_DEFAULT_SNOOZE_MINUTES, w as CoverStateSchema, wa as strictObject, wi as sceneMonitorCapability, wn as TimelapseRulePatchSchema, wr as gifDeriveSpeed, wt as NC_STATE_SUMMARY_SECTION_IDS, x as COCO_TO_MACRO, xa as object, xi as ruleDeviceCompatCapQueries, xn as TIMELAPSE_DENSE_FLOOR_SEC, xr as evictionPolicyOfLocation, xt as NC_GROUPING_MIN_SEC, y as BirthDecisionRecordSchema, ya as looseObject, yi as ruleAutoTriggersAlarm, yn as SetTrackPurityResultSchema, yr as ensureAlarmProfiles, yt as NC_GROUPING_DEFAULT_SEC, z as FIRST_LEVEL_MACRO_CLASSES, zi as systemEventSummarySplitOf, zn as applyBlockingEdit, zr as isRetiredClearKey, zt as NcRuleTargetSchema } from "../clip-model-registry-DdgT3gdf.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";
|
|
@@ -750,6 +750,8 @@ var DEFAULT_ACTION_TTL_MS = 15 * 6e4;
|
|
|
750
750
|
* notification that is not fresh.
|
|
751
751
|
*/
|
|
752
752
|
var SNOOZE_ACTION_TTL_MS = 60 * 6e4;
|
|
753
|
+
/** How long a Correct / Wrong button stays live: one day. */
|
|
754
|
+
var VERDICT_ACTION_TTL_MS = 1440 * 6e4;
|
|
753
755
|
/**
|
|
754
756
|
* How long a DISARM button stays live: five minutes.
|
|
755
757
|
*
|
|
@@ -777,6 +779,7 @@ function actionTtlMs(subject) {
|
|
|
777
779
|
case "sequence": return DEFAULT_ACTION_TTL_MS;
|
|
778
780
|
case "addon-update": return DEFAULT_ACTION_TTL_MS;
|
|
779
781
|
case "server-update": return DEFAULT_ACTION_TTL_MS;
|
|
782
|
+
case "detection-verdict": return VERDICT_ACTION_TTL_MS;
|
|
780
783
|
}
|
|
781
784
|
}
|
|
782
785
|
var NcActionTokenRegistry = class {
|
|
@@ -820,6 +823,30 @@ var NcActionTokenRegistry = class {
|
|
|
820
823
|
grant: found.grant
|
|
821
824
|
};
|
|
822
825
|
}
|
|
826
|
+
/**
|
|
827
|
+
* Read the grant without spending it. ONLY the confirm page of a link-only
|
|
828
|
+
* channel may call this: it exists so a link preview that opens the URL
|
|
829
|
+
* cannot spend the token, and it never runs anything.
|
|
830
|
+
*/
|
|
831
|
+
peek(id) {
|
|
832
|
+
const found = this.grants.get(id);
|
|
833
|
+
if (found === void 0) return {
|
|
834
|
+
ok: false,
|
|
835
|
+
reason: "unknown"
|
|
836
|
+
};
|
|
837
|
+
if (found.used) return {
|
|
838
|
+
ok: false,
|
|
839
|
+
reason: "already-used"
|
|
840
|
+
};
|
|
841
|
+
if (found.grant.expiresAt <= this.now()) return {
|
|
842
|
+
ok: false,
|
|
843
|
+
reason: "expired"
|
|
844
|
+
};
|
|
845
|
+
return {
|
|
846
|
+
ok: true,
|
|
847
|
+
grant: found.grant
|
|
848
|
+
};
|
|
849
|
+
}
|
|
823
850
|
/** Drop records that can no longer be claimed. Memory hygiene only — an
|
|
824
851
|
* expired record is already refused by {@link claim}, so a sweep that never
|
|
825
852
|
* ran would cost bytes, never safety. */
|
|
@@ -861,6 +888,7 @@ function describeGrant(grant) {
|
|
|
861
888
|
return grant.action === "disarm" ? "Alarm disarmed" : `Alarm armed${grant.mode !== void 0 ? ` (${grant.mode})` : ""}`;
|
|
862
889
|
case "addon-update": return `${grant.packages.length} addon update(s) on ${grant.nodeId}`;
|
|
863
890
|
case "server-update": return `Server update on ${grant.nodeId}`;
|
|
891
|
+
case "detection-verdict": return grant.verdict === "correct" ? "Marked correct — kept for retraining" : grant.suggestedClass === void 0 ? "Marked wrong — kept for retraining" : `Marked wrong, it was a ${grant.suggestedClass} — kept for retraining`;
|
|
864
892
|
}
|
|
865
893
|
}
|
|
866
894
|
/** The audit line's `meta`, per family. A snooze that logged a `sequence` it
|
|
@@ -914,6 +942,15 @@ function grantMeta(grant) {
|
|
|
914
942
|
...common,
|
|
915
943
|
nodeId: grant.nodeId
|
|
916
944
|
};
|
|
945
|
+
case "detection-verdict": return {
|
|
946
|
+
...common,
|
|
947
|
+
ruleId: grant.ruleId,
|
|
948
|
+
rule: grant.ruleName,
|
|
949
|
+
userId: grant.userId,
|
|
950
|
+
trackId: grant.trackId,
|
|
951
|
+
verdict: grant.verdict,
|
|
952
|
+
suggestedClass: grant.suggestedClass ?? null
|
|
953
|
+
};
|
|
917
954
|
}
|
|
918
955
|
}
|
|
919
956
|
/** What the human standing in front of the page is told. */
|
|
@@ -922,6 +959,11 @@ var FAILURE_COPY = {
|
|
|
922
959
|
expired: "This button has expired. Open CamStack to do it there.",
|
|
923
960
|
"already-used": "Already done — this button had been used."
|
|
924
961
|
};
|
|
962
|
+
/** The question a link-only channel lands on, answered by a POST form. */
|
|
963
|
+
function confirmPage(url, grant) {
|
|
964
|
+
const action = `${url.pathname}?exp=${encodeURIComponent(url.searchParams.get("exp") ?? "")}&sig=${encodeURIComponent(url.searchParams.get("sig") ?? "")}&confirm=1`;
|
|
965
|
+
return `<!doctype html><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Confirm</title><style>body{font:16px/1.5 system-ui,sans-serif;margin:0;min-height:100vh;display:grid;place-items:center;background:#111;color:#eee}main{max-width:24rem;padding:2rem;text-align:center}h1{font-size:1.25rem;margin:0 0 1rem}button{font:inherit;padding:.6rem 1.4rem;border-radius:.5rem;border:0;background:#3b82f6;color:#fff}</style><main><h1>Confirm</h1><p>${grant.verdict === "correct" ? "Mark this detection as correct?" : grant.suggestedClass === void 0 ? "Mark this detection as wrong?" : `Mark this detection as wrong, it was a ${grant.suggestedClass}?`}</p><form method="post" action="${action}"><button type="submit">Confirm</button></form></main>`;
|
|
966
|
+
}
|
|
925
967
|
function page(title, detail) {
|
|
926
968
|
return `<!doctype html><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>${title}</title><style>body{font:16px/1.5 system-ui,sans-serif;margin:0;min-height:100vh;display:grid;place-items:center;background:#111;color:#eee}main{max-width:24rem;padding:2rem;text-align:center}h1{font-size:1.25rem;margin:0 0 .5rem}p{margin:0;color:#aaa}</style><main><h1>${title}</h1><p>${detail}</p></main>`;
|
|
927
969
|
}
|
|
@@ -935,7 +977,8 @@ var NcActionPlane = class {
|
|
|
935
977
|
handler = async (req, res) => {
|
|
936
978
|
const url = new URL(req.url ?? "/", "http://placeholder");
|
|
937
979
|
const id = decodeURIComponent(url.pathname.split("/").filter(Boolean).pop() ?? "");
|
|
938
|
-
const
|
|
980
|
+
const posted = (req.method ?? "GET").toUpperCase() === "POST";
|
|
981
|
+
const background = posted && url.searchParams.get("confirm") !== "1";
|
|
939
982
|
if (!verifyActionSignature({
|
|
940
983
|
secret: this.deps.secret,
|
|
941
984
|
id,
|
|
@@ -947,6 +990,13 @@ var NcActionPlane = class {
|
|
|
947
990
|
this.reply(res, background, 404, "Not found", "This link is not valid.");
|
|
948
991
|
return;
|
|
949
992
|
}
|
|
993
|
+
if (!posted) {
|
|
994
|
+
const peeked = this.deps.registry.peek(id);
|
|
995
|
+
if (peeked.ok && peeked.grant.kind === "detection-verdict" && peeked.grant.viaLink === true) {
|
|
996
|
+
this.sendBody(res, 200, "text/html; charset=utf-8", confirmPage(url, peeked.grant));
|
|
997
|
+
return;
|
|
998
|
+
}
|
|
999
|
+
}
|
|
950
1000
|
const claim = this.deps.registry.claim(id);
|
|
951
1001
|
if (!claim.ok) {
|
|
952
1002
|
this.deps.logger.info("nc action callback not claimable", { meta: {
|
|
@@ -1092,6 +1142,7 @@ var ncDurableRecordKinds = defineRecordKinds({
|
|
|
1092
1142
|
"state-summary-stamps": ledger("digest delivery stamps per rule kind"),
|
|
1093
1143
|
meta: ledger("outbox boot-reconcile watermark and other single-key meta rows", "settings", { none: "one fixed key (watermark), overwritten in place, never deleted" }),
|
|
1094
1144
|
snoozes: ledger("operator opens or closes a snooze window (write-through)"),
|
|
1145
|
+
"detection-verdicts": ledger("operator taps Correct or Wrong on a detection notification; one row per track"),
|
|
1095
1146
|
"snooze-suppressed": {
|
|
1096
1147
|
...QUERIED,
|
|
1097
1148
|
class: "ledger",
|
|
@@ -9226,6 +9277,9 @@ var en_default = {
|
|
|
9226
9277
|
"action.addon-update.uptodate": "Already up to date on {{nodeId}} — nothing to do",
|
|
9227
9278
|
"action.addon-update.unknown": "Could not read what needs updating on {{nodeId}} — nothing was changed. Open CamStack.",
|
|
9228
9279
|
"button.server-update.apply": "Update server on {{nodeId}}",
|
|
9280
|
+
"button.verdict.correct": "Correct",
|
|
9281
|
+
"button.verdict.wrong": "Wrong",
|
|
9282
|
+
"button.verdict.wrongAs": "Wrong: it is {{class}}",
|
|
9229
9283
|
"action.server-update.title": "Server update",
|
|
9230
9284
|
"action.server-update.started": "Updating server on {{nodeId}}…",
|
|
9231
9285
|
"action.server-update.restarting": "Server update staged on {{nodeId}} — the node is restarting. You will hear when it comes back.",
|
|
@@ -9627,6 +9681,9 @@ var it_default = {
|
|
|
9627
9681
|
"action.addon-update.uptodate": "Già aggiornato su {{nodeId}} — niente da fare",
|
|
9628
9682
|
"action.addon-update.unknown": "Non è stato possibile leggere cosa aggiornare su {{nodeId}} — non è stato cambiato nulla. Apri CamStack.",
|
|
9629
9683
|
"button.server-update.apply": "Aggiorna server su {{nodeId}}",
|
|
9684
|
+
"button.verdict.correct": "Corretto",
|
|
9685
|
+
"button.verdict.wrong": "Sbagliato",
|
|
9686
|
+
"button.verdict.wrongAs": "Sbagliato: è {{class}}",
|
|
9630
9687
|
"action.server-update.title": "Aggiornamento server",
|
|
9631
9688
|
"action.server-update.started": "Aggiornamento server su {{nodeId}}…",
|
|
9632
9689
|
"action.server-update.restarting": "Aggiornamento server predisposto su {{nodeId}} — il nodo si riavvia. Ti avviseremo quando torna.",
|
|
@@ -53035,6 +53092,15 @@ var SESSION_STILLNESS_MIN_POINTS = 4;
|
|
|
53035
53092
|
* long (object removed while unobserved, or a long occlusion) → retire it. */
|
|
53036
53093
|
var ENTRY_TTL_MS = 5 * 6e4;
|
|
53037
53094
|
/**
|
|
53095
|
+
* The most one gap between two consecutive processed frames counts toward an
|
|
53096
|
+
* entry's WATCHED unconfirmed time. Frames inside a motion session arrive every
|
|
53097
|
+
* 0.2-2 s; the silence between on-motion sessions is tens of seconds to hours.
|
|
53098
|
+
* 10 s sits above any real in-session cadence (a slower frame still counts
|
|
53099
|
+
* nearly in full) and far below a session gap, so a gap contributes at most
|
|
53100
|
+
* one bound, never its length. Under-counting only delays a retirement.
|
|
53101
|
+
*/
|
|
53102
|
+
var WATCHED_GAP_CAP_MS = 1e4;
|
|
53103
|
+
/**
|
|
53038
53104
|
* How far apart the two reads of a departure must be before the second one
|
|
53039
53105
|
* counts as CONFIRMING the first.
|
|
53040
53106
|
*
|
|
@@ -59702,6 +59768,25 @@ var TrackAlreadyTrainedError = class extends Error {
|
|
|
59702
59768
|
}
|
|
59703
59769
|
};
|
|
59704
59770
|
/**
|
|
59771
|
+
* Classify a failed `setTrackFlags` as one of the lifecycle's DELIBERATE
|
|
59772
|
+
* refusals, or `null` when it is a failure of the call itself.
|
|
59773
|
+
*
|
|
59774
|
+
* Needed because the caller that matters (a notification button) reaches the
|
|
59775
|
+
* method over `ctx.api`, where the error class does not survive the hop and
|
|
59776
|
+
* only the message does. The class check comes first; the message check is the
|
|
59777
|
+
* transported form, and `track-flags.spec.ts` pins it against the real
|
|
59778
|
+
* messages so a reworded refusal cannot silently turn into a generic failure.
|
|
59779
|
+
*/
|
|
59780
|
+
function retrainRefusalReason(err) {
|
|
59781
|
+
if (err instanceof TrackAlreadyTrainedError) return "trained";
|
|
59782
|
+
if (err instanceof StagingBudgetExceededError) return "budget";
|
|
59783
|
+
const message = err instanceof Error ? err.message : "";
|
|
59784
|
+
if (message.includes("is already trained")) return "trained";
|
|
59785
|
+
if (message.includes("in retrain staging")) return "budget";
|
|
59786
|
+
if (message.includes("unknown track")) return "unknown-track";
|
|
59787
|
+
return null;
|
|
59788
|
+
}
|
|
59789
|
+
/**
|
|
59705
59790
|
* The `debugNote` half of the patch — `{}` when nothing should be written.
|
|
59706
59791
|
*
|
|
59707
59792
|
* The note is not an independent column: it is the operator's sentence about
|
|
@@ -62265,6 +62350,19 @@ var StationaryObjectRegistry = class {
|
|
|
62265
62350
|
* so quiet minutes must not age the entries (see {@link sweep}). */
|
|
62266
62351
|
lastFrameAtByDevice = /* @__PURE__ */ new Map();
|
|
62267
62352
|
/**
|
|
62353
|
+
* WATCHED time each entry has gone unconfirmed, in ms. Entry expiry is judged
|
|
62354
|
+
* on this, never on the span between two frame timestamps: a session-dispatch
|
|
62355
|
+
* camera's silence between motion sessions would otherwise be counted in full
|
|
62356
|
+
* the moment the next session's first frame arrives (measured: a car parked
|
|
62357
|
+
* 3.3 h was retired after seconds of watching, 316 s after its last
|
|
62358
|
+
* confirmation). Each frame adds its delta from the previous one, capped at
|
|
62359
|
+
* {@link WATCHED_GAP_CAP_MS}; a confirmation resets it. `confirmedAt` is the
|
|
62360
|
+
* `lastConfirmedAt` the counter was last reset for, so a changed value (any of
|
|
62361
|
+
* the places that confirm an entry) restarts the count without a hook at each.
|
|
62362
|
+
* An entry that was just hydrated has no record here and starts at zero.
|
|
62363
|
+
*/
|
|
62364
|
+
unconfirmedWatched = /* @__PURE__ */ new Map();
|
|
62365
|
+
/**
|
|
62268
62366
|
* Entries carrying ONE unconfirmed departure read, per device (D49, D174,
|
|
62269
62367
|
* D279).
|
|
62270
62368
|
*
|
|
@@ -62378,7 +62476,27 @@ var StationaryObjectRegistry = class {
|
|
|
62378
62476
|
/** Record that a frame was processed for a device — advances the OBSERVED
|
|
62379
62477
|
* clock that drives entry expiry in {@link sweep}. */
|
|
62380
62478
|
noteFrame(deviceId, timestamp) {
|
|
62381
|
-
|
|
62479
|
+
const known = this.lastFrameAtByDevice.get(deviceId);
|
|
62480
|
+
if (timestamp <= (known ?? 0)) return;
|
|
62481
|
+
this.lastFrameAtByDevice.set(deviceId, timestamp);
|
|
62482
|
+
const ids = this.idsByDevice.get(deviceId);
|
|
62483
|
+
if (!ids) return;
|
|
62484
|
+
const delta = known === void 0 ? 0 : Math.min(timestamp - known, WATCHED_GAP_CAP_MS);
|
|
62485
|
+
for (const id of ids) {
|
|
62486
|
+
const e = this.ledger.get(id);
|
|
62487
|
+
if (!e) continue;
|
|
62488
|
+
const rec = this.unconfirmedWatched.get(id);
|
|
62489
|
+
if (!rec || rec.confirmedAt !== e.lastConfirmedAt) this.unconfirmedWatched.set(id, {
|
|
62490
|
+
confirmedAt: e.lastConfirmedAt,
|
|
62491
|
+
ms: 0
|
|
62492
|
+
});
|
|
62493
|
+
else rec.ms += delta;
|
|
62494
|
+
}
|
|
62495
|
+
}
|
|
62496
|
+
/** Watched ms an entry has gone unconfirmed (0 when not yet tracked). */
|
|
62497
|
+
watchedUnconfirmedMs(e) {
|
|
62498
|
+
const rec = this.unconfirmedWatched.get(e.id);
|
|
62499
|
+
return rec && rec.confirmedAt === e.lastConfirmedAt ? rec.ms : 0;
|
|
62382
62500
|
}
|
|
62383
62501
|
/**
|
|
62384
62502
|
* Per-frame gate: partition this frame's detections against the device's
|
|
@@ -62623,12 +62741,14 @@ var StationaryObjectRegistry = class {
|
|
|
62623
62741
|
* logged by `MacMiniAgent.localdomain` and by `agent-a`, the same
|
|
62624
62742
|
* rows, seven seconds apart.
|
|
62625
62743
|
*
|
|
62626
|
-
* Expiry is measured
|
|
62627
|
-
*
|
|
62628
|
-
*
|
|
62629
|
-
*
|
|
62744
|
+
* Expiry is measured in WATCHED time ({@link noteFrame}): the sum of the
|
|
62745
|
+
* gaps between consecutive processed frames, each capped at
|
|
62746
|
+
* {@link WATCHED_GAP_CAP_MS}, since the entry's last confirmation. Neither the
|
|
62747
|
+
* wall clock nor the span between frame timestamps: a session-dispatch
|
|
62748
|
+
* camera emits no frames between motion sessions, and a silent gap must not
|
|
62749
|
+
* age the object. Only when the camera has actually been WATCHING for `ttl`
|
|
62630
62750
|
* beyond the last confirmation (frames flowed, object never matched) is the
|
|
62631
|
-
* object considered removed. A device with no recorded frame yet never
|
|
62751
|
+
* object considered removed. A freshly hydrated entry starts at zero. A device with no recorded frame yet never
|
|
62632
62752
|
* expires its entries. `now` only stamps the departed telemetry.
|
|
62633
62753
|
*/
|
|
62634
62754
|
async sweep(now) {
|
|
@@ -62647,9 +62767,10 @@ var StationaryObjectRegistry = class {
|
|
|
62647
62767
|
ids.delete(id);
|
|
62648
62768
|
continue;
|
|
62649
62769
|
}
|
|
62650
|
-
const
|
|
62770
|
+
const watchedMs = this.watchedUnconfirmedMs(e);
|
|
62771
|
+
const overdue = watchedMs > ttl;
|
|
62651
62772
|
const proven = this.detectorProvedItself(e);
|
|
62652
|
-
const unprovenBackstop =
|
|
62773
|
+
const unprovenBackstop = watchedMs > ttl * 12;
|
|
62653
62774
|
if (overdue && !proven && !unprovenBackstop) {
|
|
62654
62775
|
this.bumpStrikeCounters(deviceId, { ttlHeldUnproven: 1 });
|
|
62655
62776
|
continue;
|
|
@@ -62665,7 +62786,8 @@ var StationaryObjectRegistry = class {
|
|
|
62665
62786
|
className: e.className,
|
|
62666
62787
|
reason: proven ? "ttl" : "ttl-unproven",
|
|
62667
62788
|
ttlMs: ttl,
|
|
62668
|
-
unconfirmedForMs:
|
|
62789
|
+
unconfirmedForMs: watchedMs,
|
|
62790
|
+
wallGapMs: observedAt - e.lastConfirmedAt,
|
|
62669
62791
|
parkedForMs: observedAt - e.becameStationaryAt
|
|
62670
62792
|
}
|
|
62671
62793
|
});
|
|
@@ -62749,6 +62871,7 @@ var StationaryObjectRegistry = class {
|
|
|
62749
62871
|
for (const id of ids) {
|
|
62750
62872
|
this.dirty.delete(id);
|
|
62751
62873
|
this.weakRuns.delete(id);
|
|
62874
|
+
this.unconfirmedWatched.delete(id);
|
|
62752
62875
|
this.ledger.evict(id);
|
|
62753
62876
|
}
|
|
62754
62877
|
this.idsByDevice.delete(deviceId);
|
|
@@ -62936,6 +63059,7 @@ var StationaryObjectRegistry = class {
|
|
|
62936
63059
|
return at !== void 0 && at > entry.lastConfirmedAt;
|
|
62937
63060
|
}
|
|
62938
63061
|
dropEntry(deviceId, id) {
|
|
63062
|
+
this.unconfirmedWatched.delete(id);
|
|
62939
63063
|
const dropped = this.ledger.get(id);
|
|
62940
63064
|
this.idsByDevice.get(deviceId)?.delete(id);
|
|
62941
63065
|
this.dirty.delete(id);
|
|
@@ -81843,6 +81967,10 @@ var NC_DEVICE_ROW_KINDS = [
|
|
|
81843
81967
|
{
|
|
81844
81968
|
key: "nc-artifacts",
|
|
81845
81969
|
kind: ncDurableRecordKinds.artifacts
|
|
81970
|
+
},
|
|
81971
|
+
{
|
|
81972
|
+
key: "nc-detection-verdicts",
|
|
81973
|
+
kind: ncDurableRecordKinds["detection-verdicts"]
|
|
81846
81974
|
}
|
|
81847
81975
|
];
|
|
81848
81976
|
/**
|
|
@@ -82262,6 +82390,82 @@ var NcSequenceStore = class NcSequenceStore {
|
|
|
82262
82390
|
}
|
|
82263
82391
|
};
|
|
82264
82392
|
//#endregion
|
|
82393
|
+
//#region src/notification-center/detection-verdict-ledger.ts
|
|
82394
|
+
/**
|
|
82395
|
+
* @durable class=ledger owner=notification-center
|
|
82396
|
+
* write="the operator taps Correct / Wrong on a detection notification; one row per track, the latest answer replaces the earlier one"
|
|
82397
|
+
* retention="none — bounded by the tracks a rule asked about; deleted with the camera by the device-removal hook"
|
|
82398
|
+
*/
|
|
82399
|
+
var NC_DETECTION_VERDICTS_COLLECTION = "notification-center:detection-verdicts";
|
|
82400
|
+
var NC_DETECTION_VERDICTS_COLUMNS = [
|
|
82401
|
+
{
|
|
82402
|
+
name: "id",
|
|
82403
|
+
type: "TEXT",
|
|
82404
|
+
primaryKey: true,
|
|
82405
|
+
notNull: true
|
|
82406
|
+
},
|
|
82407
|
+
{
|
|
82408
|
+
name: "ruleId",
|
|
82409
|
+
type: "TEXT",
|
|
82410
|
+
notNull: true
|
|
82411
|
+
},
|
|
82412
|
+
{
|
|
82413
|
+
name: "at",
|
|
82414
|
+
type: "INTEGER",
|
|
82415
|
+
notNull: true
|
|
82416
|
+
},
|
|
82417
|
+
(
|
|
82418
|
+
/** The FULL row (Zod-validated on read). */
|
|
82419
|
+
{
|
|
82420
|
+
name: "row",
|
|
82421
|
+
type: "JSON",
|
|
82422
|
+
notNull: true
|
|
82423
|
+
})
|
|
82424
|
+
];
|
|
82425
|
+
var NcDetectionVerdictRecordSchema = object({
|
|
82426
|
+
trackId: string().min(1),
|
|
82427
|
+
deviceId: number().int(),
|
|
82428
|
+
verdict: _enum(["correct", "wrong"]),
|
|
82429
|
+
/** The class the operator said it really was. Only with `wrong`. */
|
|
82430
|
+
suggestedClass: string().min(1).optional(),
|
|
82431
|
+
/** Whose notification it was (the token's frozen owner), NOT who tapped. */
|
|
82432
|
+
userId: string().min(1),
|
|
82433
|
+
ruleId: string().min(1),
|
|
82434
|
+
ruleName: string(),
|
|
82435
|
+
at: number()
|
|
82436
|
+
});
|
|
82437
|
+
var NC_DETECTION_VERDICTS_SPEC = {
|
|
82438
|
+
collection: NC_DETECTION_VERDICTS_COLLECTION,
|
|
82439
|
+
columns: [...NC_DETECTION_VERDICTS_COLUMNS],
|
|
82440
|
+
writeMode: "write-through",
|
|
82441
|
+
keyOf: (row) => row.trackId,
|
|
82442
|
+
toValue: (row) => ({
|
|
82443
|
+
ruleId: row.ruleId,
|
|
82444
|
+
at: row.at,
|
|
82445
|
+
row
|
|
82446
|
+
}),
|
|
82447
|
+
fromRecord: (_key, data) => {
|
|
82448
|
+
const parsed = NcDetectionVerdictRecordSchema.safeParse(data["row"]);
|
|
82449
|
+
return parsed.success ? parsed.data : null;
|
|
82450
|
+
},
|
|
82451
|
+
deviceIdOf: (row) => row.deviceId,
|
|
82452
|
+
loadLimit: 1e4
|
|
82453
|
+
};
|
|
82454
|
+
var NcDetectionVerdictLedger = class {
|
|
82455
|
+
ledger;
|
|
82456
|
+
constructor(deps) {
|
|
82457
|
+
this.ledger = new DurableLedger({
|
|
82458
|
+
spec: NC_DETECTION_VERDICTS_SPEC,
|
|
82459
|
+
kind: deps.records.kind(ncDurableRecordKinds["detection-verdicts"]),
|
|
82460
|
+
logger: deps.logger
|
|
82461
|
+
});
|
|
82462
|
+
}
|
|
82463
|
+
/** Write-through; throws on a failed write so the tap reports it. */
|
|
82464
|
+
async record(row) {
|
|
82465
|
+
await this.ledger.put(NcDetectionVerdictRecordSchema.parse(row));
|
|
82466
|
+
}
|
|
82467
|
+
};
|
|
82468
|
+
//#endregion
|
|
82265
82469
|
//#region src/notification-center/device-prune.ts
|
|
82266
82470
|
function judgeList(list, isDead) {
|
|
82267
82471
|
const dead = list.filter(isDead);
|
|
@@ -83216,6 +83420,64 @@ var NcDeviceStateCache = class {
|
|
|
83216
83420
|
}
|
|
83217
83421
|
};
|
|
83218
83422
|
//#endregion
|
|
83423
|
+
//#region src/notification-center/detection-verdict-buttons.ts
|
|
83424
|
+
var VERDICT_CORRECT_ID = "detection-verdict-correct";
|
|
83425
|
+
var VERDICT_WRONG_ID = "detection-verdict-wrong";
|
|
83426
|
+
/** `detection-verdict-wrong:<class>` — Wrong, and what it really was. */
|
|
83427
|
+
var VERDICT_WRONG_AS_PREFIX = "detection-verdict-wrong:";
|
|
83428
|
+
/** The macro classes offered as "it was really…". Short on purpose. */
|
|
83429
|
+
var VERDICT_CLASS_CHOICES = [
|
|
83430
|
+
"person",
|
|
83431
|
+
"vehicle",
|
|
83432
|
+
"animal"
|
|
83433
|
+
];
|
|
83434
|
+
/** At most this many class buttons, and only when the channel has room. */
|
|
83435
|
+
var VERDICT_MAX_CLASS_CHOICES = 2;
|
|
83436
|
+
function verdictButtonRefusal(subject) {
|
|
83437
|
+
if (!subject.askVerdict) return "rule-off";
|
|
83438
|
+
if (subject.trackId === void 0) return "no-track";
|
|
83439
|
+
if (subject.ownerUserId === void 0) return "unowned-target";
|
|
83440
|
+
return null;
|
|
83441
|
+
}
|
|
83442
|
+
/** The classes worth offering for a subject of `className`. */
|
|
83443
|
+
function verdictClassChoices(className) {
|
|
83444
|
+
return VERDICT_CLASS_CHOICES.filter((c) => c !== className).slice(0, VERDICT_MAX_CLASS_CHOICES);
|
|
83445
|
+
}
|
|
83446
|
+
/**
|
|
83447
|
+
* Which buttons a channel with `maxActions` slots gets. `maxActions` absent
|
|
83448
|
+
* (the kind catalog did not answer) is treated as the common floor of three:
|
|
83449
|
+
* the two plain choices, never the class ones. The class choices appear only
|
|
83450
|
+
* when the channel declared room for a fourth button.
|
|
83451
|
+
*/
|
|
83452
|
+
function verdictButtonSpecs(input) {
|
|
83453
|
+
const base = [{
|
|
83454
|
+
actionId: VERDICT_CORRECT_ID,
|
|
83455
|
+
verdict: "correct"
|
|
83456
|
+
}, {
|
|
83457
|
+
actionId: VERDICT_WRONG_ID,
|
|
83458
|
+
verdict: "wrong"
|
|
83459
|
+
}];
|
|
83460
|
+
if (input.maxActions === void 0 || input.maxActions <= 3) return base;
|
|
83461
|
+
const room = input.maxActions - base.length;
|
|
83462
|
+
const extra = verdictClassChoices(input.className).slice(0, room).map((suggestedClass) => ({
|
|
83463
|
+
actionId: `${VERDICT_WRONG_AS_PREFIX}${suggestedClass}`,
|
|
83464
|
+
verdict: "wrong",
|
|
83465
|
+
suggestedClass
|
|
83466
|
+
}));
|
|
83467
|
+
return [...base, ...extra];
|
|
83468
|
+
}
|
|
83469
|
+
/** Is this one of our buttons (so a link-only channel can lift it into the body)? */
|
|
83470
|
+
function isVerdictAction(action) {
|
|
83471
|
+
return action.id === VERDICT_CORRECT_ID || action.id.startsWith(VERDICT_WRONG_ID);
|
|
83472
|
+
}
|
|
83473
|
+
/**
|
|
83474
|
+
* The body lines that carry the verdict choices on a channel with no buttons.
|
|
83475
|
+
* A bare URL per line: every chat and mail client linkifies it.
|
|
83476
|
+
*/
|
|
83477
|
+
function verdictLinkLines(actions) {
|
|
83478
|
+
return actions.filter(isVerdictAction).map((a) => `${a.label}: ${a.url ?? ""}`).join("\n");
|
|
83479
|
+
}
|
|
83480
|
+
//#endregion
|
|
83219
83481
|
//#region src/notification-center/state-summary/state-model.ts
|
|
83220
83482
|
/**
|
|
83221
83483
|
* The STATE SUMMARY's vocabulary (D647): its sections, and what one reported
|
|
@@ -86924,6 +87186,8 @@ var NcDispatcher = class {
|
|
|
86924
87186
|
targetId: target.id,
|
|
86925
87187
|
...target.ownerUserId !== void 0 ? { ownerUserId: target.ownerUserId } : {},
|
|
86926
87188
|
...entry.payload.subject.className !== void 0 ? { className: entry.payload.subject.className } : {},
|
|
87189
|
+
...entry.payload.subject.trackId !== void 0 ? { trackId: entry.payload.subject.trackId } : {},
|
|
87190
|
+
...target.maxActions !== void 0 ? { maxActions: target.maxActions } : {},
|
|
86927
87191
|
...entry.payload.subject.systemEvent !== void 0 ? { systemEvent: entry.payload.subject.systemEvent } : {}
|
|
86928
87192
|
});
|
|
86929
87193
|
} catch (err) {
|
|
@@ -87019,9 +87283,13 @@ var NcDispatcher = class {
|
|
|
87019
87283
|
...summarySectionOf(systemEvent.data)
|
|
87020
87284
|
} } : {}
|
|
87021
87285
|
}) : null;
|
|
87022
|
-
const
|
|
87286
|
+
const minted = await this.mintActions(entry, target);
|
|
87287
|
+
const linkOnly = target.maxActions === 0;
|
|
87288
|
+
const verdictLinks = linkOnly ? verdictLinkLines(minted) : "";
|
|
87289
|
+
const actions = linkOnly ? minted.filter((a) => !isVerdictAction(a)) : minted;
|
|
87290
|
+
const withLinks = (text) => verdictLinks === "" ? text : `${text}\n\n${verdictLinks}`;
|
|
87023
87291
|
const notification = {
|
|
87024
|
-
body,
|
|
87292
|
+
body: withLinks(body),
|
|
87025
87293
|
title,
|
|
87026
87294
|
priority: clampPriority(paramNumber(entry.payload.params, "priority") ?? entry.payload.priority),
|
|
87027
87295
|
...params,
|
|
@@ -87043,7 +87311,7 @@ var NcDispatcher = class {
|
|
|
87043
87311
|
grouped: resolved.grouped,
|
|
87044
87312
|
withAiText: (aiText) => ({
|
|
87045
87313
|
...notification,
|
|
87046
|
-
body: renderBody(aiText)
|
|
87314
|
+
body: withLinks(renderBody(aiText))
|
|
87047
87315
|
})
|
|
87048
87316
|
};
|
|
87049
87317
|
}
|
|
@@ -99656,6 +99924,55 @@ async function mintButtons(host, input) {
|
|
|
99656
99924
|
const announcement = stored === null && input.ruleId === NC_ALARM_ANNOUNCE_RULE_ID;
|
|
99657
99925
|
if (stored === null && !announcement) return [];
|
|
99658
99926
|
const drafts = [];
|
|
99927
|
+
const verdictRefusal = verdictButtonRefusal({
|
|
99928
|
+
askVerdict: stored?.askVerdict === true,
|
|
99929
|
+
...input.trackId !== void 0 ? { trackId: input.trackId } : {},
|
|
99930
|
+
...input.ownerUserId !== void 0 ? { ownerUserId: input.ownerUserId } : {}
|
|
99931
|
+
});
|
|
99932
|
+
if (stored?.askVerdict === true && verdictRefusal !== null) host.logger.info("detection notification carries no verdict buttons", {
|
|
99933
|
+
tags: { deviceId: input.deviceId },
|
|
99934
|
+
meta: {
|
|
99935
|
+
ruleId: input.ruleId,
|
|
99936
|
+
reason: verdictRefusal,
|
|
99937
|
+
targetId: input.targetId
|
|
99938
|
+
}
|
|
99939
|
+
});
|
|
99940
|
+
const verdictTrackId = input.trackId;
|
|
99941
|
+
const verdictOwner = input.ownerUserId;
|
|
99942
|
+
const verdictButtons = verdictRefusal !== null || verdictTrackId === void 0 || verdictOwner === void 0 ? [] : verdictButtonSpecs({
|
|
99943
|
+
className: input.className,
|
|
99944
|
+
maxActions: input.maxActions
|
|
99945
|
+
}).map((spec) => {
|
|
99946
|
+
const id = randomUUID();
|
|
99947
|
+
drafts.push({
|
|
99948
|
+
id,
|
|
99949
|
+
ttlMs: actionTtlMs({ kind: "detection-verdict" }),
|
|
99950
|
+
grant: (expiresAt) => ({
|
|
99951
|
+
kind: "detection-verdict",
|
|
99952
|
+
id,
|
|
99953
|
+
verdict: spec.verdict,
|
|
99954
|
+
trackId: verdictTrackId,
|
|
99955
|
+
ruleId: input.ruleId,
|
|
99956
|
+
ruleName: input.ruleName,
|
|
99957
|
+
userId: verdictOwner,
|
|
99958
|
+
...spec.suggestedClass !== void 0 ? { suggestedClass: spec.suggestedClass } : {},
|
|
99959
|
+
...input.maxActions === 0 ? { viaLink: true } : {},
|
|
99960
|
+
deviceId: input.deviceId,
|
|
99961
|
+
actionId: spec.actionId,
|
|
99962
|
+
targetId: input.targetId,
|
|
99963
|
+
expiresAt
|
|
99964
|
+
})
|
|
99965
|
+
});
|
|
99966
|
+
return {
|
|
99967
|
+
id: spec.actionId,
|
|
99968
|
+
label: spec.suggestedClass === void 0 ? host.texts.text({ key: spec.verdict === "correct" ? "button.verdict.correct" : "button.verdict.wrong" }) : host.texts.text({
|
|
99969
|
+
key: "button.verdict.wrongAs",
|
|
99970
|
+
vars: { class: spec.suggestedClass }
|
|
99971
|
+
}),
|
|
99972
|
+
url: id,
|
|
99973
|
+
mode: "background"
|
|
99974
|
+
};
|
|
99975
|
+
});
|
|
99659
99976
|
const sequenceButtons = host.actionRunner === null || stored === null ? [] : buildActionButtons({
|
|
99660
99977
|
actions: stored.actions,
|
|
99661
99978
|
knownSequenceIds: host.sequences.knownIds(),
|
|
@@ -99868,6 +100185,7 @@ async function mintButtons(host, input) {
|
|
|
99868
100185
|
}
|
|
99869
100186
|
});
|
|
99870
100187
|
const out = [
|
|
100188
|
+
...verdictButtons,
|
|
99871
100189
|
...sequenceButtons,
|
|
99872
100190
|
...snoozeButtons,
|
|
99873
100191
|
...alarmButtons,
|
|
@@ -100091,8 +100409,53 @@ async function runGrantedAction(host, grant) {
|
|
|
100091
100409
|
case "sequence": return host.runGrantedSequence(grant);
|
|
100092
100410
|
case "addon-update": return host.applyGrantedAddonUpdate(grant);
|
|
100093
100411
|
case "server-update": return host.applyGrantedServerUpdate(grant);
|
|
100412
|
+
case "detection-verdict": return host.applyGrantedDetectionVerdict(grant);
|
|
100094
100413
|
}
|
|
100095
100414
|
}
|
|
100415
|
+
/** What a person is told when the retrain lifecycle refuses the mark. */
|
|
100416
|
+
var VERDICT_REFUSAL_COPY = {
|
|
100417
|
+
trained: "This track was already used for training — nothing was changed",
|
|
100418
|
+
budget: "This camera already holds as many tracks for retraining as it may — nothing was changed",
|
|
100419
|
+
"unknown-track": "This track is no longer available — nothing was changed"
|
|
100420
|
+
};
|
|
100421
|
+
/**
|
|
100422
|
+
* Mark the track one notification reported for retraining, and record who was
|
|
100423
|
+
* asked and when.
|
|
100424
|
+
*
|
|
100425
|
+
* Order matters. The MARK goes first and is the authority: a refusal ("already
|
|
100426
|
+
* trained", "budget full") means the operator's answer changed nothing, so no
|
|
100427
|
+
* ledger row is written for an answer that was not applied. The token is
|
|
100428
|
+
* already spent (D47) — the refusal is shown as the reason, not a retry.
|
|
100429
|
+
*/
|
|
100430
|
+
async function applyGrantedDetectionVerdict(host, grant) {
|
|
100431
|
+
const mark = host.deps.markTrackForRetrain;
|
|
100432
|
+
if (mark === void 0) throw new Error("no retrain mark is wired on this node");
|
|
100433
|
+
const outcome = await mark({
|
|
100434
|
+
deviceId: grant.deviceId,
|
|
100435
|
+
trackId: grant.trackId
|
|
100436
|
+
});
|
|
100437
|
+
if (!outcome.ok) {
|
|
100438
|
+
host.logger.info("detection verdict changed nothing — the retrain flow refused the mark", {
|
|
100439
|
+
tags: { deviceId: grant.deviceId },
|
|
100440
|
+
meta: {
|
|
100441
|
+
trackId: grant.trackId,
|
|
100442
|
+
reason: outcome.reason,
|
|
100443
|
+
verdict: grant.verdict
|
|
100444
|
+
}
|
|
100445
|
+
});
|
|
100446
|
+
throw new NcActionRefusedError(VERDICT_REFUSAL_COPY[outcome.reason]);
|
|
100447
|
+
}
|
|
100448
|
+
await host.verdicts.record({
|
|
100449
|
+
trackId: grant.trackId,
|
|
100450
|
+
deviceId: grant.deviceId,
|
|
100451
|
+
verdict: grant.verdict,
|
|
100452
|
+
...grant.suggestedClass !== void 0 ? { suggestedClass: grant.suggestedClass } : {},
|
|
100453
|
+
userId: grant.userId,
|
|
100454
|
+
ruleId: grant.ruleId,
|
|
100455
|
+
ruleName: grant.ruleName,
|
|
100456
|
+
at: host.now()
|
|
100457
|
+
});
|
|
100458
|
+
}
|
|
100096
100459
|
/**
|
|
100097
100460
|
* Apply the addon updates one notification was about.
|
|
100098
100461
|
*
|
|
@@ -105269,6 +105632,7 @@ var NotificationCenter = class {
|
|
|
105269
105632
|
* evaluating one.
|
|
105270
105633
|
*/
|
|
105271
105634
|
pruneLedger;
|
|
105635
|
+
verdicts;
|
|
105272
105636
|
/** D905: which rules cannot work, announced once per distinct reason. */
|
|
105273
105637
|
ruleHealth = new NcRuleHealthMonitor();
|
|
105274
105638
|
/** The prune itself — see `device-prune-runner.ts`. */
|
|
@@ -105497,6 +105861,11 @@ var NotificationCenter = class {
|
|
|
105497
105861
|
applyGrantedArmAnyway: (panel, grant) => self.applyGrantedArmAnyway(panel, grant),
|
|
105498
105862
|
applyGrantedBypassInput: (panel, grant) => self.applyGrantedBypassInput(panel, grant),
|
|
105499
105863
|
applyGrantedServerUpdate: (grant) => self.applyGrantedServerUpdate(grant),
|
|
105864
|
+
applyGrantedDetectionVerdict: (grant) => self.applyGrantedDetectionVerdict(grant),
|
|
105865
|
+
now: self.now,
|
|
105866
|
+
get verdicts() {
|
|
105867
|
+
return self.verdicts;
|
|
105868
|
+
},
|
|
105500
105869
|
applyGrantedSnooze: (grant) => self.applyGrantedSnooze(grant),
|
|
105501
105870
|
get deps() {
|
|
105502
105871
|
return self.deps;
|
|
@@ -105547,6 +105916,9 @@ var NotificationCenter = class {
|
|
|
105547
105916
|
async applyGrantedAddonUpdate(grant) {
|
|
105548
105917
|
return applyGrantedAddonUpdate(this.grantedActionsHost(), grant);
|
|
105549
105918
|
}
|
|
105919
|
+
async applyGrantedDetectionVerdict(grant) {
|
|
105920
|
+
return applyGrantedDetectionVerdict(this.grantedActionsHost(), grant);
|
|
105921
|
+
}
|
|
105550
105922
|
async applyGrantedServerUpdate(grant) {
|
|
105551
105923
|
return applyGrantedServerUpdate(this.grantedActionsHost(), grant);
|
|
105552
105924
|
}
|
|
@@ -105786,6 +106158,10 @@ var NotificationCenter = class {
|
|
|
105786
106158
|
}
|
|
105787
106159
|
this.summaryRules = NcSummaryStore.of(deps.records, this.logger.child("summary"), deps.now);
|
|
105788
106160
|
this.calendarEventsRules = NcCalendarEventsStore.of(deps.records, this.logger.child("calendar-events"), deps.now);
|
|
106161
|
+
this.verdicts = new NcDetectionVerdictLedger({
|
|
106162
|
+
...durableStore,
|
|
106163
|
+
logger: this.logger.child("detection-verdicts")
|
|
106164
|
+
});
|
|
105789
106165
|
this.pruneLedger = new NcPruneLedger({
|
|
105790
106166
|
...durableStore,
|
|
105791
106167
|
logger: this.logger.child("device-prune")
|
|
@@ -108393,6 +108769,23 @@ var BuildNotificationCenter = class extends BuildNotificationCenterBase {
|
|
|
108393
108769
|
};
|
|
108394
108770
|
}
|
|
108395
108771
|
},
|
|
108772
|
+
markTrackForRetrain: async ({ deviceId, trackId }) => {
|
|
108773
|
+
try {
|
|
108774
|
+
await this.ctx.api.pipelineAnalytics.setTrackFlags.mutate({
|
|
108775
|
+
deviceId,
|
|
108776
|
+
trackId,
|
|
108777
|
+
flags: { markForTrain: true }
|
|
108778
|
+
});
|
|
108779
|
+
return { ok: true };
|
|
108780
|
+
} catch (err) {
|
|
108781
|
+
const reason = retrainRefusalReason(err);
|
|
108782
|
+
if (reason === null) throw err;
|
|
108783
|
+
return {
|
|
108784
|
+
ok: false,
|
|
108785
|
+
reason
|
|
108786
|
+
};
|
|
108787
|
+
}
|
|
108788
|
+
},
|
|
108396
108789
|
readDeviceStates: async (ids) => {
|
|
108397
108790
|
const out = /* @__PURE__ */ new Map();
|
|
108398
108791
|
for (const id of ids) try {
|
|
@@ -108464,9 +108857,11 @@ var BuildNotificationCenter = class extends BuildNotificationCenterBase {
|
|
|
108464
108857
|
const targets = await api.notificationOutput.listTargets.query({});
|
|
108465
108858
|
const kinds = await api.notificationOutput.listTargetKinds.query({}).catch(() => []);
|
|
108466
108859
|
const bodyMaxLenByKind = new Map(kinds.map((k) => [k.kind, k.caps.bodyMaxLen]));
|
|
108860
|
+
const maxActionsByKind = new Map(kinds.map((k) => [k.kind, k.caps.actions]));
|
|
108467
108861
|
return targets.map((t) => {
|
|
108468
108862
|
const owner = t.config["ownerUserId"];
|
|
108469
108863
|
const bodyMaxLen = bodyMaxLenByKind.get(t.kind);
|
|
108864
|
+
const maxActions = maxActionsByKind.get(t.kind);
|
|
108470
108865
|
return {
|
|
108471
108866
|
id: t.id,
|
|
108472
108867
|
addonId: t.addonId,
|
|
@@ -108474,7 +108869,8 @@ var BuildNotificationCenter = class extends BuildNotificationCenterBase {
|
|
|
108474
108869
|
kind: t.kind,
|
|
108475
108870
|
enabled: t.enabled,
|
|
108476
108871
|
...typeof owner === "string" && owner.length > 0 ? { ownerUserId: owner } : {},
|
|
108477
|
-
...typeof bodyMaxLen === "number" ? { bodyMaxLen } : {}
|
|
108872
|
+
...typeof bodyMaxLen === "number" ? { bodyMaxLen } : {},
|
|
108873
|
+
...typeof maxActions === "number" ? { maxActions } : {}
|
|
108478
108874
|
};
|
|
108479
108875
|
});
|
|
108480
108876
|
},
|