@camstack/addon-model-studio 1.1.187 → 1.1.188

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 (18) hide show
  1. package/dist/{MotionZonesSettings-Ctu2jUw5.mjs → MotionZonesSettings-C3Q6uGN6.mjs} +2 -2
  2. package/dist/{PrivacyMaskSettings-BklhxSXj.mjs → PrivacyMaskSettings-BTYQ0naD.mjs} +4 -4
  3. package/dist/{SceneMonitorEditor-BZRgxah0.mjs → SceneMonitorEditor-Cp7WaMLv.mjs} +3 -3
  4. package/dist/_stub.js +11 -10
  5. package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_model_studio_page-CVGJSgs1.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_model_studio_page-DsTZQf95.mjs} +3 -3
  6. package/dist/_virtual_mf___mfe_internal__addon_model_studio_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-4iTjY_Pt.mjs +26 -0
  7. package/dist/{hostInit-D34VXjYA.mjs → hostInit-DdDrweKo.mjs} +2 -2
  8. package/dist/model-studio.addon.js +152 -88
  9. package/dist/model-studio.addon.mjs +152 -88
  10. package/dist/{player-overlays-WyG3CO8M.mjs → player-overlays-DKT8GX77.mjs} +1 -1
  11. package/dist/remoteEntry.js +1 -1
  12. package/dist/{responsive-DM13bMuN.mjs → responsive-DIe_729f.mjs} +1 -1
  13. package/dist/{scene-monitor-copy-NEMFgUTn.mjs → scene-monitor-copy-BPMddHmu.mjs} +1 -1
  14. package/dist/{square-BI5Xsmdj.mjs → square-BV6C5eVN.mjs} +1 -1
  15. package/dist/{trash-2-D1YC9gXH.mjs → trash-2-pItW1ij8.mjs} +1 -1
  16. package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_model_studio_page__remoteEntry_js-C_9FXI-l.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_model_studio_page__remoteEntry_js-xPDjO4M6.mjs} +1 -1
  17. package/package.json +1 -1
  18. package/dist/_virtual_mf___mfe_internal__addon_model_studio_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-a-ZV2LaP.mjs +0 -26
@@ -570,7 +570,7 @@ async function importScryptedCatalogModel(input, deps) {
570
570
  }
571
571
  }
572
572
  //#endregion
573
- //#region ../types/dist/event-category-C5xZWqz6.mjs
573
+ //#region ../types/dist/event-category-BGmz_oxW.mjs
574
574
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
575
575
  EventCategory["SystemBoot"] = "system.boot";
576
576
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -1103,6 +1103,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
1103
1103
  */
1104
1104
  EventCategory["PipelineAudioInferenceResult"] = "pipeline.audio-inference-result";
1105
1105
  EventCategory["DetectionPhaseTransition"] = "detection.phase-transition";
1106
+ /**
1107
+ * A camera provider's RAW onboard motion push (D673): the `MotionOnMotionChanged`
1108
+ * data shape without `triggeredBy`, built by `providerMotionEvent`. Its one
1109
+ * consumer is the orchestrator's camera-sensors bridge, which re-emits the
1110
+ * camera's EFFECTIVE onboard motion as `MotionOnMotionChanged` (a pass-through
1111
+ * for a camera with no attached sensor). Providers must not emit
1112
+ * `MotionOnMotionChanged` themselves; `scripts/check-onboard-motion-emitters.ts`
1113
+ * keeps it so (camera-grid is a named, deferred exception).
1114
+ */
1106
1115
  EventCategory["ProviderMotion"] = "provider.motion";
1107
1116
  EventCategory["ProviderDetection"] = "provider.detection";
1108
1117
  EventCategory["EnrichmentEmbeddingStored"] = "enrichment.embedding.stored";
@@ -5941,7 +5950,7 @@ var ZodIssueCode = {
5941
5950
  var ZodFirstPartyTypeKind;
5942
5951
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5943
5952
  //#endregion
5944
- //#region ../types/dist/sleep-gU6hqv4_.mjs
5953
+ //#region ../types/dist/sleep-CDCONfkt.mjs
5945
5954
  /**
5946
5955
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5947
5956
  * window to float samples (D455).
@@ -8051,7 +8060,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
8051
8060
  return DeviceRole;
8052
8061
  }({});
8053
8062
  //#endregion
8054
- //#region ../types/dist/composition-Dq42XWp0.mjs
8063
+ //#region ../types/dist/composition-43aqsZQj.mjs
8055
8064
  /**
8056
8065
  * The ffmpeg build every CamStack node downloads, per platform and arch.
8057
8066
  *
@@ -8108,13 +8117,12 @@ portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac
8108
8117
  * LA tabella "quale booleano di questo tipo di device conta come ALTO", e il
8109
8118
  * valutatore puro del suo FRONTE.
8110
8119
  *
8111
- * Viveva dentro il builtin virtual-doorbell
8112
- * (`@camstack/system` — `builtins/doorbell/trigger-engine.ts`) e i suoi
8113
- * predicati erano privati al modulo. Il recorder ne ha bisogno per il trigger
8114
- * `RecordingTriggers.sensorDeviceIds`: copiarla avrebbe creato la SECONDA
8115
- * tabella, che diverge alla prima cap aggiunta e il cui sintomo — "il sensore
8116
- * fa suonare il campanello ma non registra" — è esattamente D62. Quindi si
8117
- * SPOSTA qui e il doorbell la ri-esporta.
8120
+ * UNA tabella per tutti quelli che chiedono "questo device è ALTO?": il
8121
+ * trigger `RecordingTriggers.sensorDeviceIds` del recorder, i marker dei
8122
+ * sensori della post-analysis, il bridge camera-sensors dell'orchestratore e
8123
+ * le sorgenti di un campanello composto (`doorbellFeatureSources`, D671).
8124
+ * Una seconda copia divergerebbe alla prima cap aggiunta, e il sintomo — "il
8125
+ * sensore fa suonare il campanello ma non registra" — è esattamente D62.
8118
8126
  *
8119
8127
  * ⚠ NON è `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), e le
8120
8128
  * due non vanno unificate: quella risponde a "qual è la PAROLA di stato per una
@@ -9849,7 +9857,7 @@ var RecordingTriggersSchema = object({
9849
9857
  *
9850
9858
  * Cosa vuol dire "alto" dipende dal TIPO di device e non è deciso qui:
9851
9859
  * `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) è LA tabella,
9852
- * la stessa che il virtual-doorbell usa dal 2026-08-05. Ed è il FRONTE, non
9860
+ * la stessa del campanello composto (D671). Ed è il FRONTE, non
9853
9861
  * il livello: un contatto trovato già aperto al riavvio del runner non fa
9854
9862
  * registrare.
9855
9863
  */
@@ -15969,28 +15977,10 @@ method(object({
15969
15977
  deviceIds: array(number()).readonly(),
15970
15978
  caps: array(string()).readonly().optional()
15971
15979
  }), record(string(), record(string(), unknown().nullable())));
15972
- object({
15973
- /** Ms epoch of the last press. null = never observed since this provider started. */
15974
- lastPressedAt: number().nullable(),
15975
- /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
15976
- pressCountSinceStart: number()
15977
- });
15978
- object({
15979
- deviceId: number(),
15980
- timestamp: number()
15981
- });
15982
- /**
15983
- * The `doorbell-source` extension slot's editable value (D648): the camera's
15984
- * virtual-doorbell trigger devices, exactly what the wrapper's
15985
- * `doorbellSources` persists (as `{ deviceId }` records).
15986
- */
15987
- var DoorbellSourceSlotValueSchema = object({ deviceIds: array(number().int().positive()) });
15980
+ var ExtensionSlotIdSchema = _enum(["linked-devices"]);
15988
15981
  DeviceType.Camera;
15989
- DeviceType.Button, DeviceType.Camera;
15990
- var ExtensionSlotIdSchema = _enum(["doorbell-source", "linked-devices"]);
15991
- DeviceType.Camera, DeviceType.Camera;
15992
15982
  /** A slot's editable value, discriminated on `slot`. */
15993
- var ExtensionSlotValueSchema = discriminatedUnion("slot", [DoorbellSourceSlotValueSchema.extend({ slot: literal("doorbell-source") }), LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
15983
+ var ExtensionSlotValueSchema = discriminatedUnion("slot", [LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
15994
15984
  DeviceType.Camera;
15995
15985
  var ExtensionSourceAvailabilitySchema = discriminatedUnion("state", [object({ state: literal("ok") }), object({
15996
15986
  state: literal("unreachable"),
@@ -16027,10 +16017,11 @@ var ExtensionSlotSourceSchema = object({
16027
16017
  });
16028
16018
  /**
16029
16019
  * A DIFFERENT authority that gates whether the slot's sources do anything —
16030
- * reported read-only, named, never written through this contract (D62). The
16031
- * virtual doorbell's sources ring only while the wrapper is bound to the
16032
- * camera, and that binding belongs to `deviceManager.setWrapperActive`.
16033
- * `unknown` means the gate could not be read; it is not "inactive" (D315).
16020
+ * reported read-only, named, never written through this contract (D62) — e.g.
16021
+ * a slot whose sources act only while a wrapper is bound to the host, a
16022
+ * binding that belongs to `deviceManager.setWrapperActive`. No slot reports
16023
+ * one today (`linked-devices` answers `null`). `unknown` means the gate could
16024
+ * not be read; it is not "inactive" (D315).
16034
16025
  */
16035
16026
  var ExtensionSlotActivationSchema = object({
16036
16027
  state: _enum([
@@ -16046,7 +16037,7 @@ var ExtensionSlotRowSchema = discriminatedUnion("state", [object({
16046
16037
  /** `<source>:<slotId>` — the routing key for `listCandidates` / `setSlot`. */
16047
16038
  slotRef: string(),
16048
16039
  slot: ExtensionSlotIdSchema,
16049
- /** Names the store written (D62), e.g. `virtual-doorbell:doorbellSources`. */
16040
+ /** Names the store written (D62), e.g. `device-manager:_linkedDeviceIds`. */
16050
16041
  authority: string(),
16051
16042
  activation: ExtensionSlotActivationSchema.nullable(),
16052
16043
  value: ExtensionSlotValueSchema,
@@ -21136,12 +21127,26 @@ var CameraSensorRefSchema = object({
21136
21127
  function cameraSensorRefKey(ref) {
21137
21128
  return `${ref.addonId}/${ref.stableId}`;
21138
21129
  }
21139
- /** CS-1 accepts exactly one mode; CS-2 (D673) widens it to confirm / replace. */
21140
- var CameraSensorsModeSchema = _enum(["in-addition"]);
21141
- var CameraSensorsConfigSchema = object({
21142
- mode: CameraSensorsModeSchema,
21143
- sensors: array(CameraSensorRefSchema).min(1).max(8)
21144
- }).superRefine((value, ctx) => {
21130
+ /**
21131
+ * A sensor's mode (D673). `in-addition`: its motion is the camera's motion too.
21132
+ * `replace`: its motion is the camera's, and while one is READY the camera's
21133
+ * own motion no longer counts on its own. `confirm`: while one is READY the
21134
+ * camera's own motion counts only while a confirm sensor is active — with or
21135
+ * without a replace sensor (spec C2, the controller's ruling on Q1).
21136
+ */
21137
+ var CameraSensorModeSchema = _enum([
21138
+ "in-addition",
21139
+ "confirm",
21140
+ "replace"
21141
+ ]);
21142
+ /** A stored sensor with no mode — every CS-1 row — is in addition. */
21143
+ var DEFAULT_CAMERA_SENSOR_MODE = "in-addition";
21144
+ /**
21145
+ * A camera's attached sensors. A CS-1 row carried an envelope
21146
+ * `mode: 'in-addition'`: `z.object` drops it on parse, and the PARSED value is
21147
+ * what the write stores (D672 rule 3), so it is never written again.
21148
+ */
21149
+ var CameraSensorsConfigSchema = object({ sensors: array(CameraSensorRefSchema.extend({ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE) })).min(1).max(8) }).superRefine((value, ctx) => {
21145
21150
  const seen = /* @__PURE__ */ new Set();
21146
21151
  value.sensors.forEach((ref, index) => {
21147
21152
  const key = cameraSensorRefKey(ref);
@@ -21153,39 +21158,41 @@ var CameraSensorsConfigSchema = object({
21153
21158
  seen.add(key);
21154
21159
  });
21155
21160
  });
21156
- var RefFields = {
21161
+ /** Every attachment names its mode; an older orchestrator that does not is in addition. */
21162
+ var AttachmentFields = {
21157
21163
  addonId: string(),
21158
- stableId: string()
21164
+ stableId: string(),
21165
+ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE)
21159
21166
  };
21160
21167
  var CameraSensorAttachmentSchema = discriminatedUnion("state", [
21161
21168
  object({
21162
- ...RefFields,
21169
+ ...AttachmentFields,
21163
21170
  state: literal("ready"),
21164
21171
  deviceId: number(),
21165
21172
  name: string(),
21166
21173
  caps: array(string()).readonly()
21167
21174
  }),
21168
21175
  object({
21169
- ...RefFields,
21176
+ ...AttachmentFields,
21170
21177
  state: literal("offline"),
21171
21178
  deviceId: number(),
21172
21179
  name: string(),
21173
21180
  reason: _enum(["offline", "disabled"])
21174
21181
  }),
21175
21182
  object({
21176
- ...RefFields,
21183
+ ...AttachmentFields,
21177
21184
  state: literal("missing"),
21178
21185
  reason: string()
21179
21186
  }),
21180
21187
  object({
21181
- ...RefFields,
21188
+ ...AttachmentFields,
21182
21189
  state: literal("unsupported"),
21183
21190
  deviceId: number(),
21184
21191
  name: string(),
21185
21192
  reason: string()
21186
21193
  }),
21187
21194
  object({
21188
- ...RefFields,
21195
+ ...AttachmentFields,
21189
21196
  state: literal("unreadable"),
21190
21197
  reason: string()
21191
21198
  })
@@ -21198,17 +21205,49 @@ var CameraSensorAttachmentSchema = discriminatedUnion("state", [
21198
21205
  * say.
21199
21206
  */
21200
21207
  var CameraSensorsNotForwardedSchema = _enum(["onboard-not-listed", "no-active-detection"]);
21208
+ /** Whether the camera's OWN motion counts on its own (D673 C2), from its READY sensors (C3). */
21209
+ var CameraOwnMotionSchema = _enum([
21210
+ "always",
21211
+ "when-confirmed",
21212
+ "never"
21213
+ ]);
21214
+ /** Confirm / Replace cannot suppress this camera's motion: its provider still emits it directly (D673 C13). */
21215
+ var CameraSensorsNotEnforcedSchema = _enum(["provider-not-split"]);
21216
+ /**
21217
+ * The camera's OWN onboard motion (D696): the raw input the bridge combines,
21218
+ * never the effective value. The camera's `motion` slice is the effective one,
21219
+ * so a view of the camera's own row reads this.
21220
+ * - `atMs`: when the bridge received the camera's last own edge.
21221
+ * - `detected`: evaluated WHEN THE STATUS IS ASKED — the last edge said `true`
21222
+ * AND it is younger than the window the bridge counts the camera's own motion
21223
+ * for (`motionCooldownMs`, floored at two sustain ticks). A camera that never
21224
+ * sends a clear (heartbeats only) therefore reads `false` once no push came
21225
+ * within the window; a status read is a snapshot, so a live view re-asks.
21226
+ * Absent = this orchestrator has not received the camera's own motion since it
21227
+ * started (unknown, never "quiet"), or an orchestrator older than D696.
21228
+ */
21229
+ var CameraRawLevelSchema = object({
21230
+ detected: boolean(),
21231
+ atMs: number()
21232
+ });
21201
21233
  var CameraSensorsStatusSchema = discriminatedUnion("state", [
21202
- object({ state: literal("not-configured") }),
21234
+ object({
21235
+ state: literal("not-configured"),
21236
+ cameraLevel: CameraRawLevelSchema.optional()
21237
+ }),
21203
21238
  object({
21204
21239
  state: literal("unreadable"),
21205
- reason: string()
21240
+ reason: string(),
21241
+ cameraLevel: CameraRawLevelSchema.optional()
21206
21242
  }),
21207
21243
  object({
21208
21244
  state: literal("configured"),
21209
- mode: CameraSensorsModeSchema,
21245
+ cameraLevel: CameraRawLevelSchema.optional(),
21210
21246
  sensors: array(CameraSensorAttachmentSchema).readonly(),
21211
- notForwarded: CameraSensorsNotForwardedSchema.optional()
21247
+ /** Absent = an orchestrator older than CS-2: it does not say (D315). */
21248
+ cameraMotion: CameraOwnMotionSchema.optional(),
21249
+ notForwarded: CameraSensorsNotForwardedSchema.optional(),
21250
+ notEnforced: CameraSensorsNotEnforcedSchema.optional()
21212
21251
  })
21213
21252
  ]);
21214
21253
  Object.freeze({
@@ -24399,8 +24438,10 @@ var RunnerCameraConfigSchema = object({
24399
24438
  * - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
24400
24439
  * analyzer providers) running on decoded frames in this runner.
24401
24440
  * - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
24402
- * analytics). The provider emits ProviderMotion
24403
- * events; the orchestrator forwards to `reportMotion`.
24441
+ * analytics). The provider emits its raw push as `ProviderMotion`
24442
+ * (D673); the orchestrator's camera-sensors bridge re-emits the camera's
24443
+ * effective motion as `MotionOnMotionChanged`, which is what reaches
24444
+ * `reportMotion`.
24404
24445
  */
24405
24446
  motionSources: MotionSourcesSchema.default(["analyzer"]),
24406
24447
  /**
@@ -24577,7 +24618,15 @@ var RunnerLocalLoadSchema = object({
24577
24618
  hasGpu: boolean(),
24578
24619
  inferenceBackend: string().optional(),
24579
24620
  cpuCores: number().optional()
24580
- })
24621
+ }),
24622
+ /**
24623
+ * Who writes a camera's `motion` runtime slice (D696). `'orchestrator'`: this
24624
+ * runner never writes it. ABSENT = a runner older than D696, which still
24625
+ * writes the slice from its phase machine; the orchestrator does not write
24626
+ * while any runner node is absent-or-unanswered, so one slice never has two
24627
+ * writers.
24628
+ */
24629
+ motionSliceWriter: literal("orchestrator").optional()
24581
24630
  });
24582
24631
  /**
24583
24632
  * Aggregate runtime metrics for the runner's whole local pool. Mirrors the
@@ -29418,6 +29467,17 @@ object({
29418
29467
  deviceId: number(),
29419
29468
  status: DeviceStatusSchema
29420
29469
  });
29470
+ object({
29471
+ /** Ms epoch of the last press. null = never observed since this provider started. */
29472
+ lastPressedAt: number().nullable(),
29473
+ /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
29474
+ pressCountSinceStart: number()
29475
+ });
29476
+ object({
29477
+ deviceId: number(),
29478
+ timestamp: number()
29479
+ });
29480
+ DeviceType.Button, DeviceType.Camera;
29421
29481
  /**
29422
29482
  * Enum-state sensor — a string value picked from a finite option set.
29423
29483
  * Drives HA `sensor` entries with `state_class: enum` (HVAC action
@@ -31062,9 +31122,9 @@ object({
31062
31122
  /** Ms epoch of the last detected-true observation. Null if never detected. */
31063
31123
  lastDetectedAt: number().nullable(),
31064
31124
  /**
31065
- * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device,
31066
- * `null` while false and on every `Sensor` device (D475) — see that
31067
- * constant's doc for the one-authority rule.
31125
+ * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device (the
31126
+ * orchestrator writes it, D696), `null` while false and on every `Sensor`
31127
+ * device (D475) — see that constant's doc for the one-authority rule.
31068
31128
  *
31069
31129
  * ## Reading this field still arms nothing
31070
31130
  *
@@ -31082,38 +31142,41 @@ object({
31082
31142
  * `addon-export-alexa/src/motion-clear-hold.ts` and
31083
31143
  * `addon-export-hap`'s `RESET_DEBOUNCE_MS` both do.
31084
31144
  *
31085
- * ## Who writes it
31086
- *
31087
- * - **Cameras** — the runner's phase machine, `active → watching` on
31088
- * `cooldown_expired`, which then writes this slice with
31089
- * `detected: false` (`handlePhaseChanged` in
31090
- * `pipeline-runner/index.ts`). It produces the FALLING edge, which
31091
- * matters most for the sources that only ever push a rising one:
31092
- * Reolink emits `MotionOnMotionChanged { detected: true }` and never
31093
- * a false.
31094
- * - **Sensors** (Home Assistant binary sensors, Homematic) — the
31095
- * provider pushes the false itself, from the upstream system's own
31096
- * state change. No phase machine is involved.
31097
- *
31098
- * ### The phase machine is CANONICAL, not sole — and that is a defect
31099
- *
31100
- * An earlier revision of this docblock (mine, 2026-09-12) claimed the
31101
- * phase machine is the sole writer for a camera. It is not.
31102
- * `hikvision-camera.ts:3464` and `amcrest-camera.ts:445` both call
31103
- * `setCapSlice(motionCapability, …)` on their own rising edge, and
31104
- * Hikvision's comment says why: it read THIS docblock, agreed the
31105
- * runner is canonical, and wrote anyway to avoid per-tick churn. So
31106
- * two authorities can disagree about one slice, which this repo
31107
- * forbids, and the doc said otherwise — which is worse than saying
31108
- * nothing, because it reads as verification.
31109
- *
31110
- * This predates D475 and is not fixed there: the fix touches every
31111
- * camera provider. Recorded in D475's Consequences. Do not restore the
31112
- * "sole writer" wording without also removing the other writers.
31145
+ * ## Who writes it (D696)
31146
+ *
31147
+ * - **Cameras** — the orchestrator, and nothing else. It writes the camera's
31148
+ * EFFECTIVE motion (`addon-pipeline-orchestrator`
31149
+ * `camera-sensors/motion-slice.ts`), alongside the effective
31150
+ * `MotionOnMotionChanged` it emits or receives: the camera-sensors bridge
31151
+ * for a split camera, an unsplit emitter's direct event, the analyzer and
31152
+ * device activity, as the camera's `motionSources` counts them. A source
31153
+ * that never sends a clear falls one window after its last `true`.
31154
+ * `lastDetectedAt` moves only on an effective rise. No camera provider
31155
+ * writes this slice (not even a boot seed), and neither does the runner's
31156
+ * phase machine: its phase is "a session is attached" for every on-motion
31157
+ * session, not motion, and it now has its own `DetectionPhaseTransition`.
31158
+ * A provider's `isDetected` answers from the hub's slice.
31159
+ * - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
31160
+ * imports) — the provider pushes both edges itself, from the upstream
31161
+ * system's own state change. That is the sensor's own fact.
31162
+ *
31163
+ * `scripts/check-onboard-motion-emitters.ts` refuses any other writer of a
31164
+ * `motion` slice; each sensor writer is a named exemption.
31165
+ *
31166
+ * This replaces the D475 §4 rule ("the phase machine is the sole writer").
31167
+ * That rule was never true: Hikvision and Amcrest wrote the slice raw beside
31168
+ * it, every provider seeded it at boot, and every session left it
31169
+ * `detected: true` after its detach.
31113
31170
  */
31114
31171
  autoClearAfterMs: number().nullable()
31115
31172
  });
31116
- object({
31173
+ /**
31174
+ * Payload of `motion.onMotionChanged` event + the corresponding bus
31175
+ * event `EventCategory.MotionOnMotionChanged`. Single source of truth
31176
+ * — both the cap event surface and the bus payload type alias to this
31177
+ * schema.
31178
+ */
31179
+ var MotionOnMotionChangedDataSchema = object({
31117
31180
  deviceId: number(),
31118
31181
  detected: boolean(),
31119
31182
  timestamp: number(),
@@ -47590,6 +47653,7 @@ TimelapseRuleInputSchema.extend({
47590
47653
  createdAt: number(),
47591
47654
  updatedAt: number()
47592
47655
  });
47656
+ MotionOnMotionChangedDataSchema.omit({ triggeredBy: true });
47593
47657
  object({
47594
47658
  /**
47595
47659
  * Fraction of the box's own size added on EACH side before cutting.