@camstack/addon-post-analysis 1.2.312 → 1.2.314

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.
@@ -906,6 +906,14 @@ var propertyKeyTypes = /* @__PURE__*/ new Set([
906
906
  "number",
907
907
  "symbol"
908
908
  ]);
909
+ var primitiveTypes = /* @__PURE__*/ new Set([
910
+ "string",
911
+ "number",
912
+ "bigint",
913
+ "boolean",
914
+ "symbol",
915
+ "undefined"
916
+ ]);
909
917
  function escapeRegex(str) {
910
918
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
911
919
  }
@@ -3153,6 +3161,43 @@ function handleReadonlyResult(payload) {
3153
3161
  payload.value = Object.freeze(payload.value);
3154
3162
  return payload;
3155
3163
  }
3164
+ var $ZodTemplateLiteral = /*@__PURE__*/ $constructor("$ZodTemplateLiteral", (inst, def) => {
3165
+ $ZodType.init(inst, def);
3166
+ const regexParts = [];
3167
+ for (const part of def.parts) if (typeof part === "object" && part !== null) {
3168
+ if (!part._zod.pattern) throw new Error(`Invalid template literal part, no pattern found: ${[...part._zod.traits].shift()}`);
3169
+ const source = part._zod.pattern instanceof RegExp ? part._zod.pattern.source : part._zod.pattern;
3170
+ if (!source) throw new Error(`Invalid template literal part: ${part._zod.traits}`);
3171
+ const start = source.startsWith("^") ? 1 : 0;
3172
+ const end = source.endsWith("$") ? source.length - 1 : source.length;
3173
+ regexParts.push(source.slice(start, end));
3174
+ } else if (part === null || primitiveTypes.has(typeof part)) regexParts.push(escapeRegex(`${part}`));
3175
+ else throw new Error(`Invalid template literal part: ${part}`);
3176
+ inst._zod.pattern = new RegExp(`^${regexParts.join("")}$`);
3177
+ inst._zod.parse = (payload, _ctx) => {
3178
+ if (typeof payload.value !== "string") {
3179
+ payload.issues.push({
3180
+ input: payload.value,
3181
+ inst,
3182
+ expected: "string",
3183
+ code: "invalid_type"
3184
+ });
3185
+ return payload;
3186
+ }
3187
+ inst._zod.pattern.lastIndex = 0;
3188
+ if (!inst._zod.pattern.test(payload.value)) {
3189
+ payload.issues.push({
3190
+ input: payload.value,
3191
+ inst,
3192
+ code: "invalid_format",
3193
+ format: def.format ?? "template_literal",
3194
+ pattern: inst._zod.pattern.source
3195
+ });
3196
+ return payload;
3197
+ }
3198
+ return payload;
3199
+ };
3200
+ });
3156
3201
  var $ZodLazy = /*@__PURE__*/ $constructor("$ZodLazy", (inst, def) => {
3157
3202
  $ZodType.init(inst, def);
3158
3203
  defineLazy(inst._zod, "innerType", () => {
@@ -4172,6 +4217,13 @@ var literalProcessor = (schema, ctx, json, _params) => {
4172
4217
  json.enum = vals;
4173
4218
  }
4174
4219
  };
4220
+ var templateLiteralProcessor = (schema, _ctx, json, _params) => {
4221
+ const _json = json;
4222
+ const pattern = schema._zod.pattern;
4223
+ if (!pattern) throw new Error("Pattern not found in template literal");
4224
+ _json.type = "string";
4225
+ _json.pattern = pattern.source;
4226
+ };
4175
4227
  var customProcessor = (_schema, ctx, _json, _params) => {
4176
4228
  if (ctx.unrepresentable === "throw") throw new Error("Custom types cannot be represented in JSON Schema");
4177
4229
  };
@@ -5345,6 +5397,18 @@ function readonly(innerType) {
5345
5397
  innerType
5346
5398
  });
5347
5399
  }
5400
+ var ZodTemplateLiteral = /*@__PURE__*/ $constructor("ZodTemplateLiteral", (inst, def) => {
5401
+ $ZodTemplateLiteral.init(inst, def);
5402
+ ZodType.init(inst, def);
5403
+ inst._zod.processJSONSchema = (ctx, json, params) => templateLiteralProcessor(inst, ctx, json, params);
5404
+ });
5405
+ function templateLiteral(parts, params) {
5406
+ return new ZodTemplateLiteral({
5407
+ type: "template_literal",
5408
+ parts,
5409
+ ...normalizeParams(params)
5410
+ });
5411
+ }
5348
5412
  var ZodLazy = /*@__PURE__*/ $constructor("ZodLazy", (inst, def) => {
5349
5413
  $ZodLazy.init(inst, def);
5350
5414
  ZodType.init(inst, def);
@@ -7677,7 +7741,7 @@ function errMsg(err) {
7677
7741
  return String(err);
7678
7742
  }
7679
7743
  //#endregion
7680
- //#region ../types/dist/composition-43aqsZQj.mjs
7744
+ //#region ../types/dist/composition-D7ULvLdD.mjs
7681
7745
  /**
7682
7746
  * Deterministic SHA-256 hash of an arbitrary serialisable value. The
7683
7747
  * canonical form sorts object keys alphabetically at every depth so two
@@ -7762,20 +7826,20 @@ function portable(target) {
7762
7826
  }
7763
7827
  portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac64");
7764
7828
  /**
7765
- * LA tabella "quale booleano di questo tipo di device conta come ALTO", e il
7766
- * valutatore puro del suo FRONTE.
7829
+ * THE table "which boolean of this device type counts as HIGH", and the
7830
+ * pure evaluator of its EDGE.
7767
7831
  *
7768
- * UNA tabella per tutti quelli che chiedono "questo device è ALTO?": il
7769
- * trigger `RecordingTriggers.sensorDeviceIds` del recorder, i marker dei
7770
- * sensori della post-analysis, il bridge camera-sensors dell'orchestratore e
7771
- * le sorgenti di un campanello composto (`doorbellFeatureSources`, D671).
7772
- * Una seconda copia divergerebbe alla prima cap aggiunta, e il sintomo — "il
7773
- * sensore fa suonare il campanello ma non registra" — è esattamente D62.
7832
+ * ONE table for everyone who asks "is this device HIGH?": the
7833
+ * recorder's `RecordingTriggers.sensorDeviceIds` trigger, the post-analysis
7834
+ * sensor markers, the orchestrator's camera-sensors bridge and
7835
+ * the sources of a composite doorbell (`doorbellFeatureSources`, D671).
7836
+ * A second copy would diverge at the first cap added, and the symptom — "the
7837
+ * sensor rings the doorbell but does not record" — is exactly D62.
7774
7838
  *
7775
- * ⚠ NON è `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), e le
7776
- * due non vanno unificate: quella risponde a "qual è la PAROLA di stato per una
7777
- * regola" (e include `presence`, `cover`, `alarm-panel`), questa a "qual è il
7778
- * booleano il cui FRONTE conta". Vocabolari deliberatamente diversi.
7839
+ * ⚠ NOT `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), and the
7840
+ * two must not be unified: that one answers "what is the state WORD for a
7841
+ * rule" (and includes `presence`, `cover`, `alarm-panel`), this one "which
7842
+ * boolean's EDGE counts". Deliberately different vocabularies.
7779
7843
  */
7780
7844
  /**
7781
7845
  * Known binary / switch source caps → the boolean slice field whose
@@ -7867,17 +7931,17 @@ function evaluateSensorLevelEdge(input) {
7867
7931
  };
7868
7932
  }
7869
7933
  /**
7870
- * IL fronte. Puro: nessun orologio proprio, nessuna memoria — il chiamante
7871
- * porta `prior`, `nowMs` e il proprio `startedAtMs`.
7934
+ * THE edge. Pure: no clock of its own, no memory — the caller
7935
+ * brings `prior`, `nowMs` and its own `startedAtMs`.
7872
7936
  *
7873
- * Il caso della PRIMA slice già attiva è trattato esplicitamente e vale come
7874
- * fronte solo se il timestamp UPSTREAM della transizione è posteriore a
7875
- * `startedAtMs` **e** entro `firstSightingFreshnessMs`. Entrambe le metà
7876
- * servono: la sola freschezza scatterebbe su un'idratazione al boot di uno
7877
- * stato flippato pochi secondi prima del riavvio, e il solo "dopo che abbiamo
7878
- * iniziato" scatterebbe, su un processo di lunga vita, per una sorgente
7879
- * adottata oggi il cui stato è cambiato ieri. Il caso ambiguo ERRA VERSO IL
7880
- * SILENZIO e lo dichiara (`baseline-seeded-stale-active`).
7937
+ * The case of the FIRST slice already active is treated explicitly and counts as an
7938
+ * edge only if the UPSTREAM timestamp of the transition is later than
7939
+ * `startedAtMs` **and** within `firstSightingFreshnessMs`. Both halves
7940
+ * are needed: freshness alone would fire on a boot-time hydration of a
7941
+ * state flipped a few seconds before the restart, and "after we started"
7942
+ * alone would fire, on a long-lived process, for a source
7943
+ * adopted today whose state changed yesterday. The ambiguous case ERRS TOWARD
7944
+ * SILENCE and declares it (`baseline-seeded-stale-active`).
7881
7945
  */
7882
7946
  function evaluateSensorEdge(input) {
7883
7947
  const value = sliceActiveValue(input.capName, input.slice);
@@ -9777,22 +9841,22 @@ var CLASS_MAP_MACRO_TARGETS = [
9777
9841
  "package"
9778
9842
  ];
9779
9843
  /**
9780
- * Le macro classi di PRIMO LIVELLO: quelle che un object detector emette e che
9781
- * un operatore può selezionare.
9844
+ * The FIRST-LEVEL macro classes: those an object detector emits and that
9845
+ * an operator can select.
9782
9846
  *
9783
- * Sono le tre offerte dallo step `object-detection`
9847
+ * They are the three offered by the `object-detection` step
9784
9848
  * (`addon-pipeline/src/detection-pipeline/registry/step-definitions.ts`,
9785
- * `enabledMacroClasses`). `package` sta in {@link CLASS_MAP_MACRO_TARGETS} e in
9786
- * `MACRO_LABELS` — è una macro vera — ma NON qui: appartiene allo step
9787
- * `package-detection`, la cui abilitazione è guidata dalle zone, e offrire la
9788
- * stessa parola due volte ha già fatto accendere a un operatore il proxy COCO
9849
+ * `enabledMacroClasses`). `package` is in {@link CLASS_MAP_MACRO_TARGETS} and in
9850
+ * `MACRO_LABELS` — it is a true macro — but NOT here: it belongs to the step
9851
+ * `package-detection`, whose enablement is driven by zones, and offering the
9852
+ * same word twice has already made an operator turn on the COCO proxy
9789
9853
  * (suitcase/backpack/handbag) lasciando spento il detector dedicato.
9790
9854
  *
9791
- * UNA lista. Prima di oggi le stesse tre erano scritte a mano nell'offerta
9792
- * dello step e una seconda volta come union `FirstLevelMacro`
9793
- * (`types/detection.ts`); una terza copia per il trigger di registrazione
9794
- * (`RecordingTriggers.objectClasses`) avrebbe reso invisibile la divergenza
9795
- * successiva.
9855
+ * ONE list. Before today the same three were hand-written in the step's offer
9856
+ * and a second time as the union `FirstLevelMacro`
9857
+ * (`types/detection.ts`); a third copy for the recording trigger
9858
+ * (`RecordingTriggers.objectClasses`) would have made the later divergence
9859
+ * invisible.
9796
9860
  */
9797
9861
  var FIRST_LEVEL_MACRO_CLASSES = [
9798
9862
  "person",
@@ -9857,17 +9921,17 @@ var RecordingStorageModeSchema = _enum([
9857
9921
  "on-device-decision"
9858
9922
  ]);
9859
9923
  /**
9860
- * Le macro classi che possono aprire una finestra di registrazione — le stesse
9861
- * tre offerte dallo step `object-detection`, da UNA lista
9924
+ * The macro classes that can open a recording window — the same
9925
+ * three offered by the `object-detection` step, from ONE list
9862
9926
  * ({@link FIRST_LEVEL_MACRO_CLASSES}).
9863
9927
  */
9864
9928
  var RecordingObjectTriggerClassSchema = _enum(FIRST_LEVEL_MACRO_CLASSES);
9865
9929
  /**
9866
- * True quando `values` non ripete un elemento.
9930
+ * True when `values` does not repeat an element.
9867
9931
  *
9868
- * Un duplicato non è innocuo: ogni voce di `objectClasses` / `sensorDeviceIds`
9869
- * diventa una SORGENTE in `bandTriggerSources`, e la stessa sorgente due volte
9870
- * conterebbe due volte le sue finestre in `segmentMissedByMs`.
9932
+ * A duplicate is not harmless: every entry of `objectClasses` / `sensorDeviceIds`
9933
+ * becomes a SOURCE in `bandTriggerSources`, and the same source twice
9934
+ * would count its windows twice in `segmentMissedByMs`.
9871
9935
  */
9872
9936
  var noDuplicates = (values) => new Set(values).size === values.length;
9873
9937
  /** Which detectors trigger an `events`-mode band. */
@@ -9875,34 +9939,34 @@ var RecordingTriggersSchema = object({
9875
9939
  motion: boolean().optional(),
9876
9940
  audioThresholdDbfs: number().optional(),
9877
9941
  /**
9878
- * Le macro classi la cui detection apre una finestra. ASSENTE = la sorgente
9879
- * non è ascoltata; un array VUOTO è rifiutato, perché "banda events, trigger
9880
- * object acceso, nessuna classe" è la stessa forma "abilitata e non registra
9881
- * nulla, per sempre" contro cui è scritto `eventsBandCanEverDemand`.
9942
+ * The macro classes whose detection opens a window. ABSENT = the source
9943
+ * is not listened to; an EMPTY array is rejected, because "events band, object
9944
+ * trigger on, no class" is the same shape "enabled and records
9945
+ * nothing, forever" that `eventsBandCanEverDemand` is written against.
9882
9946
  *
9883
- * Il segnale letto è GIÀ FILTRATO: solo detection `source: 'pipeline'`, cioè
9884
- * quelle che hanno attraversato `enabledMacroClasses`, i
9885
- * `minConfidence<Macro>` e il full-frame guard. L'AI a bordo camera
9886
- * (`source: 'onboard'`) non attraversa nessuno di quei gate e NON apre
9887
- * finestre — vedi `recorder/object-trigger.ts`.
9947
+ * The signal read is ALREADY FILTERED: only `source: 'pipeline'` detections, i.e.
9948
+ * those that went through `enabledMacroClasses`, the
9949
+ * `minConfidence<Macro>` and the full-frame guard. The camera's onboard AI
9950
+ * (`source: 'onboard'`) goes through none of those gates and does NOT open
9951
+ * windows — see `recorder/object-trigger.ts`.
9888
9952
  */
9889
9953
  objectClasses: array(RecordingObjectTriggerClassSchema).min(1).refine(noDuplicates, { message: "objectClasses must not repeat a class" }).optional(),
9890
9954
  /**
9891
- * I device LINKED il cui FRONTE ALTO apre una finestra. Assente = la sorgente
9892
- * non è ascoltata; un array vuoto è rifiutato per la stessa ragione di
9955
+ * The LINKED devices whose RISING EDGE opens a window. Absent = the source
9956
+ * is not listened to; an empty array is rejected for the same reason as
9893
9957
  * `objectClasses`.
9894
9958
  *
9895
- * Sono id di device SORGENTE, non camere: la banda li nomina, quindi il
9896
- * percorso caldo (`DeviceStateChanged`, a ritmo di bus su tutta la flotta)
9897
- * non fa RPC. L'OFFERTA da cui l'operatore li sceglie è un'altra domanda, e
9898
- * si risolve con `deviceManager.getLinkedDevices` + `getBindingsBatch` per
9899
- * device (D12) — mai un elenco globale di cap.
9959
+ * These are SOURCE device ids, not cameras: the band names them, so the
9960
+ * hot path (`DeviceStateChanged`, at bus rate across the whole fleet)
9961
+ * does no RPC. The OFFER from which the operator picks them is another question, and
9962
+ * is resolved with `deviceManager.getLinkedDevices` + `getBindingsBatch` per
9963
+ * device (D12) — never a global list of caps.
9900
9964
  *
9901
- * Cosa vuol dire "alto" dipende dal TIPO di device e non è deciso qui:
9902
- * `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) è LA tabella,
9903
- * la stessa del campanello composto (D671). Ed è il FRONTE, non
9904
- * il livello: un contatto trovato già aperto al riavvio del runner non fa
9905
- * registrare.
9965
+ * What "high" means depends on the device TYPE and is not decided here:
9966
+ * `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) is THE table,
9967
+ * the same one as the composite doorbell (D671). And it is the EDGE, not
9968
+ * the level: a contact found already open at runner restart does not
9969
+ * record.
9906
9970
  */
9907
9971
  sensorDeviceIds: array(number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional()
9908
9972
  });
@@ -11076,7 +11140,7 @@ var DecoderSessionConfigSchema = object({
11076
11140
  * - **VALUE** — at which level, for which scope, until when. That stays ONE
11077
11141
  * thing: the logging settings document on the `system` cap. Two authorities
11078
11142
  * over the values is the exact defect
11079
- * `docs/design/plans/2026-08-26-logging-per-componente.md` was written to
11143
+ * `docs/design/plans/2026-08-26-per-component-logging.md` was written to
11080
11144
  * remove; re-introducing it from the cure side would be grotesque.
11081
11145
  *
11082
11146
  * Nothing in this file reads a clock, an env var or a store. The registry is
@@ -14799,7 +14863,7 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
14799
14863
  *
14800
14864
  * ⚠ An earlier version of this comment blamed Zod stripping, and that
14801
14865
  * was wrong — corrected 2026-08-26 after the hop map
14802
- * (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
14866
+ * (`docs/design/2026-08-26-topic-hop-map.md`) traced the path.
14803
14867
  * There is **no Zod parse at all** between the door and the engine: the
14804
14868
  * dispatcher forwards the payload verbatim and UDS carries it whole. A
14805
14869
  * field declared here reaches `SqliteSettingsBackend` either way.
@@ -16879,7 +16943,7 @@ var embeddingEncoderCapability = {
16879
16943
  * per-device window, `KeyFrameCaptureLog`, `bumpCropMetric`. Every one of them
16880
16944
  * ends in a log line, and a log line is the thing the operator asked to stop
16881
16945
  * needing: *"possiamo armare questi errori intanto? Così al prossimo giro
16882
- * ricontrolliamo tutti questi punti"*. Reading them meant grepping Loki and
16946
+ * ricontrolliamo tutti questi punti"* [can we instrument these errors in the meantime? That way next round we recheck all these points]. Reading them meant grepping Loki and
16883
16947
  * hand-correlating timestamps, which is how a 22% thumbnail gap and a 3-hour
16884
16948
  * media blackout were both diagnosed. The counters stay; this is where they can
16885
16949
  * be READ.
@@ -20537,6 +20601,19 @@ var NcConfirmSchema = object({
20537
20601
  /** Longest edge the judged image is downscaled to before it is sent. */
20538
20602
  maxImagePx: number().int().min(64).max(2048).default(448)
20539
20603
  });
20604
+ /**
20605
+ * IMMEDIATE GROUPED (D692) — the window bounds. ONE owner; both editors import them.
20606
+ * MIN: below it nothing has time to be promoted, and operator decision 1 (2026-10-01) makes
20607
+ * it the window's floor too — a window never closes earlier, so companions arriving
20608
+ * together share one message.
20609
+ * DEFAULT: equals the tracker's face-settle cap (`FACE_SETTLE_HOLD_MS`, D683 (f)); what an
20610
+ * editor PRE-FILLS, never what absence means (absent = plain immediate).
20611
+ * MAX: equals {@link NC_CLIP_RETENTION_MAX_SEC} — past it a gif/clip is always a recordings cut,
20612
+ * and a lock-screen alert a minute late has lost its purpose.
20613
+ */
20614
+ var NC_GROUPING_MIN_SEC = 5;
20615
+ var NC_GROUPING_DEFAULT_SEC = 20;
20616
+ var NC_GROUPING_MAX_SEC = 60;
20540
20617
  /** Client-supplied rule fields (server stamps id/createdBy/createdAt/updatedAt). */
20541
20618
  var NcRuleInputSchema = object({
20542
20619
  name: string().min(1).max(200),
@@ -20639,78 +20716,16 @@ var NcRuleInputSchema = object({
20639
20716
  */
20640
20717
  confirm: NcConfirmSchema.optional(),
20641
20718
  /**
20642
- * WAIT for face/plate recognition before saying anything.
20643
- *
20644
- * A notification's TEXT is frozen at enqueue and its media is re-resolved at
20645
- * send; the identity is neither. A face is confirmed after `confirmFrames`
20646
- * agreeing observations — p50 **11.4 s** after the track was first seen,
20647
- * measured on this hub — and an `immediate` rule enqueues on the first object
20648
- * event, seconds before that. So "Gianluca è arrivato" is unsayable on the
20649
- * immediate path, and no amount of media re-resolution fixes a sentence.
20650
- *
20651
- * Only two honest answers exist, and this flag picks between them. It has
20652
- * effect ONLY on a rule that declares a recognition scope
20653
- * ({@link NcConditions.identities} or {@link NcConditions.plates}) — on any
20654
- * other rule there is nothing to wait for and the flag is inert.
20655
- *
20656
- * | value | what happens |
20657
- * | --- | --- |
20658
- * | `true` | the rule stops firing on the object event and fires at TRACK CLOSE instead, once, with the name — later, and complete |
20659
- * | absent / `false` | it fires at once WITHOUT the name, and if recognition lands before the track closes a SECOND, "…is Gianluca" notification follows (one per track, per rule, per target) |
20660
- *
20661
- * `.optional()` and deliberately NOT `.default()`: a Zod default does not run
20662
- * on the addon cap path, and absent has to keep meaning exactly what every
20663
- * rule authored before this field meant.
20664
- *
20665
- * The cost of `true` is stated here because the editor states it too: a rule
20666
- * that waits also inherits track-close SEMANTICS — its `zones` condition
20667
- * tests every zone the track visited and a `crossing` condition can no longer
20668
- * be satisfied, because a closed track carries no crossing.
20669
- */
20670
- waitForEnhancement: boolean().optional(),
20671
- /**
20672
- * GROUP a burst of subjects into ONE notification that grows.
20673
- *
20674
- * Seconds of quiet after the last matching subject before the burst is
20675
- * considered over. While it is open, the first subject enqueues immediately —
20676
- * **exactly as today, with no added latency** — and every real growth (a new
20677
- * subject, or a name confirmed on one already in it) REPLACES that
20678
- * notification with an updated one naming everybody. The push carries the
20679
- * group's own coalescing tag, so the phone replaces rather than stacks.
20680
- *
20681
- * `0` / absent = off, and off is today's behaviour byte for byte.
20682
- *
20683
- * ### Why an idle cutoff and not a window
20684
- *
20685
- * The measured seven-person arrival on device 590 spans 110 s with every
20686
- * internal gap under 30 s. A 12 s fixed window cuts it into three groups; an
20687
- * idle cutoff holds it as one and ends it when the arrival actually ends.
20688
- * 30 s is a widely shipped value for the same decision.
20689
- *
20690
- * ### What it replaces
20691
- *
20692
- * The blind cooldown, which collapses a burst by DISCARDING it. Measured on
20693
- * device 615 / *Persona su Uscio* over six days: 116 qualifying tracks → 74
20694
- * notifications, **44 (37.9%) suppressed outright**, 23 of them overlapping a
20695
- * track that did fire and 7 carrying a confirmed identity nobody heard about.
20696
- * A group collapses the same volume by MERGING, so the cooldown becomes a
20697
- * budget over GROUPS — which is what it always meant — and a growth is never
20698
- * throttled by the window its own first member spent.
20699
- *
20700
- * ### Interaction with {@link waitForEnhancement}
20701
- *
20702
- * They compose, and the order matters. `waitForEnhancement` defers the rule to
20703
- * TRACK CLOSE, so with both set the group is opened by the first member to
20704
- * CLOSE — already carrying its name — and grows as later members close. That
20705
- * is later, and complete. With grouping alone the group opens on the first
20706
- * object event and picks up names as they are confirmed, through the growth
20707
- * path. Neither combination fires twice for one subject.
20708
- *
20709
- * `.optional()` and deliberately NOT `.default()`: a Zod default does not run
20710
- * on the addon cap path, so absent must keep meaning what it meant before this
20711
- * field existed.
20719
+ * IMMEDIATE GROUPED (D692): the first matching subject opens a window of this many
20720
+ * seconds; the rule sends ONE message when the window closes — early, once every
20721
+ * subject in it is final, never before {@link NC_GROUPING_MIN_SEC} — naming everybody
20722
+ * the rule matched, with one mosaic tile per subject.
20723
+ * Absent = plain immediate (one message per track, at the first match).
20724
+ * Only an `immediate` DETECTION rule may carry it (`ruleGroupingApplies`, enforced on
20725
+ * save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
20726
+ * path does not run Zod defaults.
20712
20727
  */
20713
- groupIdleSec: number().int().min(0).max(600).optional()
20728
+ groupingSec: number().int().min(5).max(60).optional()
20714
20729
  });
20715
20730
  /**
20716
20731
  * Partial patch for `updateRule` — any subset of the input fields, plus the
@@ -20752,15 +20767,31 @@ var NcRulePatchSchema = NcRuleInputSchema.partial().extend({
20752
20767
  throttle: NcThrottleSchema.optional(),
20753
20768
  priority: number().int().min(1).max(5).optional()
20754
20769
  });
20770
+ /**
20771
+ * Keys an older client may still name in `clear` (D692 §2.3). Accepted so its saves are never
20772
+ * refused. They are no longer rule fields: `NcRuleStore.update` only strips them from the
20773
+ * STORED row, and `NcRuleStore.load` projects what a stored row still carries (D692 §9).
20774
+ * Removed one release after the viewer pin in camstack-server stops sending them.
20775
+ */
20776
+ var NC_RULE_RETIRED_CLEAR_KEYS = ["waitForEnhancement", "groupIdleSec"];
20777
+ /**
20778
+ * Is this clearable key one of the retired ones? A type guard, so the store can split the
20779
+ * `clear` list WITHOUT a cast: a retired key is no property of `NcRulePatch` or `NcRule`, and
20780
+ * indexing either with it does not compile.
20781
+ */
20782
+ function isRetiredClearKey(key) {
20783
+ return NC_RULE_RETIRED_CLEAR_KEYS.some((retired) => retired === key);
20784
+ }
20755
20785
  var NcRuleClearableKeySchema = _enum([
20756
20786
  "template",
20757
20787
  "schedule",
20758
20788
  "targetUsers",
20759
20789
  "snoozeOptions",
20760
20790
  "snoozeAllowGlobal",
20761
- "waitForEnhancement",
20762
20791
  "actions",
20763
20792
  "confirm",
20793
+ "groupingSec",
20794
+ "waitForEnhancement",
20764
20795
  "groupIdleSec"
20765
20796
  ]);
20766
20797
  var NcRuleUpdateInputSchema = object({
@@ -21312,7 +21343,7 @@ var NC_CONDITION_CATALOG = [
21312
21343
  operator: "in",
21313
21344
  appliesTo: ["immediate", "track-end"],
21314
21345
  phase: "P1",
21315
- description: "Only recognised people. Selecting NOBODY means every identity in the face gallery; selecting some narrows to those. Matched on the gallery id, so renaming a person does not break the rule. On immediate delivery the name is not known yet when the notification is enqueued — see the rule’s \"wait for recognition\" switch."
21346
+ description: "Only recognised people. Selecting NOBODY means every identity in the face gallery; selecting some narrows to those. Matched on the gallery id, so renaming a person does not break the rule. On Immediate delivery the name must already be known when an event is written — choose Immediate, grouped to wait for it (D692)."
21316
21347
  },
21317
21348
  {
21318
21349
  id: "plates",
@@ -23508,14 +23539,14 @@ var TrackSchema = object({
23508
23539
  * `derive-returned-null tile=standin`,
23509
23540
  * `native-tile tile=native no-key-frame-at-close`, …) written at close and
23510
23541
  * CLEARED by the late-keyFrame upgrade when a native tile lands after all.
23511
- * The operator-facing answer to "perché manca l'immagine?" on a track whose
23542
+ * The operator-facing answer to "perché manca l'immagine?" [why is the image missing?] on a track whose
23512
23543
  * tile is a face/plate stand-in, a raster crop, or an icon.
23513
23544
  *
23514
23545
  * **`no-key-frame-at-close` (D400).** The line used to be written ONLY when
23515
23546
  * the TILE ranked below native, so a track whose thumbnail landed natively
23516
23547
  * while its key frame missed carried no reason at all — three of the four
23517
23548
  * `MISSING_KEYFRAME` tracks in the 2026-09-07 operator audit were exactly
23518
- * that shape, and their "niente ultimo" had no cause anywhere on the row.
23549
+ * that shape, and their "niente ultimo" [no last frame] had no cause anywhere on the row.
23519
23550
  * The key frame is the head of a cascade (`keyFrame ⇒ keyFrameSmall ⇒ the
23520
23551
  * lastFrame copy source`), so its absence is now on this line whatever the
23521
23552
  * tile ended up being.
@@ -23602,7 +23633,7 @@ var MotionEventSchema = object({
23602
23633
  /**
23603
23634
  * Ms offsets from `timestamp` (the episode's own first rising edge, so the
23604
23635
  * first entry is always `0`) of every genuine off→on transition the
23605
- * episode saw — "ogni evento on si deve salvare" (D475). NOT one entry per
23636
+ * episode saw — "ogni evento on si deve salvare" [every ON event must be saved] (D475). NOT one entry per
23606
23637
  * push: a firmware source that keepalives at ~1 Hz for the whole burst
23607
23638
  * (Reolink, Hikvision) produces exactly one edge; a source that reports an
23608
23639
  * explicit `false` mid-episode and then resumes before the quiet window
@@ -29659,7 +29690,7 @@ var ClipPlaybackSchema = object({
29659
29690
  * **One authorised yes is one wake.** `next-natural` — take the clip the next
29660
29691
  * time the camera is awake for its own reasons — is deliberately not a member:
29661
29692
  * it was proposed, it is free on the battery, and the operator declined it on
29662
- * 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."*,
29693
+ * 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."* [When an export is requested the camera wakes up],
29663
29694
  * D558 "Considered and not taken").
29664
29695
  */
29665
29696
  var ClipWakeSchema = _enum(["authorised"]);
@@ -29920,7 +29951,7 @@ DeviceType.Camera, method(object({
29920
29951
  * It replaced `sources?: string[]`, a VIEW filter over source ids that
29921
29952
  * assumed the answer was a fan-out over everything a camera has. The
29922
29953
  * operator settled otherwise on 2026-09-20 — *"l'utilizzatore è uno
29923
- * solo"* — so the list is asked of one provider at a time and there is
29954
+ * solo"* [there is only one user] — so the list is asked of one provider at a time and there is
29924
29955
  * nothing to filter out of it.
29925
29956
  */
29926
29957
  provider: string().min(1)
@@ -34814,7 +34845,7 @@ authKey: string().optional() }), object({
34814
34845
  */
34815
34846
  /**
34816
34847
  * How long after a camera's last rising edge `pipeline-analytics` closes the
34817
- * motion EPISODE row it kept open for it (D475) — "il delay della cap", in
34848
+ * motion EPISODE row it kept open for it (D475) — "il delay della cap" [the cap's delay], in
34818
34849
  * the operator's words. One authority for the whole system: the writer of a
34819
34850
  * `Camera` device's slice (the orchestrator, D696) writes this SAME constant
34820
34851
  * in `autoClearAfterMs` while `detected: true` (never a camera's own clock —
@@ -38054,7 +38085,7 @@ var ReadGopBytesResultSchema = object({
38054
38085
  /**
38055
38086
  * A time WINDOW of one finalized segment, cut by byte range — the multi-GOP
38056
38087
  * twin of {@link ReadGopBytesResultSchema}'s single instant. Built for the
38057
- * replay clip's `recording` source (`docs/design/plans/2026-08-26-replay-clip-su-pipeline.md`):
38088
+ * replay clip's `recording` source (`docs/design/plans/2026-08-26-clip-replay-on-pipeline.md`):
38058
38089
  * a replay needs several seconds of native pixels, not one frame.
38059
38090
  *
38060
38091
  * `ok.data` is standalone-demuxable, same as a GOP read. `ok.reachesRequestedEnd`
@@ -51127,6 +51158,11 @@ Object.freeze({
51127
51158
  }
51128
51159
  });
51129
51160
  Object.freeze({
51161
+ "accessories.getStatus": [{
51162
+ name: "deviceId",
51163
+ form: "single",
51164
+ optional: false
51165
+ }],
51130
51166
  "accessories.setChildHidden": [{
51131
51167
  name: "childDeviceId",
51132
51168
  form: "single",
@@ -51146,6 +51182,11 @@ Object.freeze({
51146
51182
  form: "single",
51147
51183
  optional: false
51148
51184
  }],
51185
+ "airQualitySensor.getStatus": [{
51186
+ name: "deviceId",
51187
+ form: "single",
51188
+ optional: false
51189
+ }],
51149
51190
  "alarmPanel.arm": [{
51150
51191
  name: "deviceId",
51151
51192
  form: "single",
@@ -51156,11 +51197,36 @@ Object.freeze({
51156
51197
  form: "single",
51157
51198
  optional: false
51158
51199
  }],
51200
+ "alarmPanel.getStatus": [{
51201
+ name: "deviceId",
51202
+ form: "single",
51203
+ optional: false
51204
+ }],
51159
51205
  "alarmPanel.trigger": [{
51160
51206
  name: "deviceId",
51161
51207
  form: "single",
51162
51208
  optional: false
51163
51209
  }],
51210
+ "ambientLightSensor.getStatus": [{
51211
+ name: "deviceId",
51212
+ form: "single",
51213
+ optional: false
51214
+ }],
51215
+ "audioAnalysis.applyDeviceSettingsPatch": [{
51216
+ name: "deviceId",
51217
+ form: "single",
51218
+ optional: false
51219
+ }],
51220
+ "audioAnalysis.getDeviceLiveContribution": [{
51221
+ name: "deviceId",
51222
+ form: "single",
51223
+ optional: false
51224
+ }],
51225
+ "audioAnalysis.getDeviceSettingsContribution": [{
51226
+ name: "deviceId",
51227
+ form: "single",
51228
+ optional: false
51229
+ }],
51164
51230
  "audioAnalysis.resolveDeviceSettings": [{
51165
51231
  name: "deviceId",
51166
51232
  form: "single",
@@ -51201,16 +51267,36 @@ Object.freeze({
51201
51267
  form: "single",
51202
51268
  optional: false
51203
51269
  }],
51270
+ "automationControl.getStatus": [{
51271
+ name: "deviceId",
51272
+ form: "single",
51273
+ optional: false
51274
+ }],
51204
51275
  "automationControl.trigger": [{
51205
51276
  name: "deviceId",
51206
51277
  form: "single",
51207
51278
  optional: false
51208
51279
  }],
51280
+ "battery.getStatus": [{
51281
+ name: "deviceId",
51282
+ form: "single",
51283
+ optional: false
51284
+ }],
51209
51285
  "battery.wakeForStream": [{
51210
51286
  name: "deviceId",
51211
51287
  form: "single",
51212
51288
  optional: false
51213
51289
  }],
51290
+ "binary.getStatus": [{
51291
+ name: "deviceId",
51292
+ form: "single",
51293
+ optional: false
51294
+ }],
51295
+ "brightness.getStatus": [{
51296
+ name: "deviceId",
51297
+ form: "single",
51298
+ optional: false
51299
+ }],
51214
51300
  "brightness.setBrightness": [{
51215
51301
  name: "deviceId",
51216
51302
  form: "single",
@@ -51226,6 +51312,26 @@ Object.freeze({
51226
51312
  form: "single",
51227
51313
  optional: false
51228
51314
  }],
51315
+ "cameraCredentials.getStatus": [{
51316
+ name: "deviceId",
51317
+ form: "single",
51318
+ optional: false
51319
+ }],
51320
+ "cameraGridLayout.applyDeviceSettingsPatch": [{
51321
+ name: "deviceId",
51322
+ form: "single",
51323
+ optional: false
51324
+ }],
51325
+ "cameraGridLayout.getDeviceLiveContribution": [{
51326
+ name: "deviceId",
51327
+ form: "single",
51328
+ optional: false
51329
+ }],
51330
+ "cameraGridLayout.getDeviceSettingsContribution": [{
51331
+ name: "deviceId",
51332
+ form: "single",
51333
+ optional: false
51334
+ }],
51229
51335
  "cameraGridLayout.getLayout": [{
51230
51336
  name: "deviceId",
51231
51337
  form: "single",
@@ -51241,6 +51347,21 @@ Object.freeze({
51241
51347
  form: "single",
51242
51348
  optional: false
51243
51349
  }],
51350
+ "cameraPipelineConfig.applyDeviceSettingsPatch": [{
51351
+ name: "deviceId",
51352
+ form: "single",
51353
+ optional: false
51354
+ }],
51355
+ "cameraPipelineConfig.getDeviceLiveContribution": [{
51356
+ name: "deviceId",
51357
+ form: "single",
51358
+ optional: false
51359
+ }],
51360
+ "cameraPipelineConfig.getDeviceSettingsContribution": [{
51361
+ name: "deviceId",
51362
+ form: "single",
51363
+ optional: false
51364
+ }],
51244
51365
  "cameraStreams.getBrokerStreams": [{
51245
51366
  name: "deviceId",
51246
51367
  form: "single",
@@ -51266,6 +51387,16 @@ Object.freeze({
51266
51387
  form: "single",
51267
51388
  optional: false
51268
51389
  }],
51390
+ "carbonMonoxide.getStatus": [{
51391
+ name: "deviceId",
51392
+ form: "single",
51393
+ optional: false
51394
+ }],
51395
+ "climateControl.getStatus": [{
51396
+ name: "deviceId",
51397
+ form: "single",
51398
+ optional: false
51399
+ }],
51269
51400
  "climateControl.setFanMode": [{
51270
51401
  name: "deviceId",
51271
51402
  form: "single",
@@ -51306,16 +51437,41 @@ Object.freeze({
51306
51437
  form: "single",
51307
51438
  optional: false
51308
51439
  }],
51440
+ "color.getStatus": [{
51441
+ name: "deviceId",
51442
+ form: "single",
51443
+ optional: false
51444
+ }],
51309
51445
  "color.setColor": [{
51310
51446
  name: "deviceId",
51311
51447
  form: "single",
51312
51448
  optional: false
51313
51449
  }],
51450
+ "connectivity.getStatus": [{
51451
+ name: "deviceId",
51452
+ form: "single",
51453
+ optional: false
51454
+ }],
51455
+ "consumables.getStatus": [{
51456
+ name: "deviceId",
51457
+ form: "single",
51458
+ optional: false
51459
+ }],
51314
51460
  "consumables.reset": [{
51315
51461
  name: "deviceId",
51316
51462
  form: "single",
51317
51463
  optional: false
51318
51464
  }],
51465
+ "contact.getStatus": [{
51466
+ name: "deviceId",
51467
+ form: "single",
51468
+ optional: false
51469
+ }],
51470
+ "control.getStatus": [{
51471
+ name: "deviceId",
51472
+ form: "single",
51473
+ optional: false
51474
+ }],
51319
51475
  "control.setValue": [{
51320
51476
  name: "deviceId",
51321
51477
  form: "single",
@@ -51326,6 +51482,11 @@ Object.freeze({
51326
51482
  form: "single",
51327
51483
  optional: false
51328
51484
  }],
51485
+ "cover.getStatus": [{
51486
+ name: "deviceId",
51487
+ form: "single",
51488
+ optional: false
51489
+ }],
51329
51490
  "cover.open": [{
51330
51491
  name: "deviceId",
51331
51492
  form: "single",
@@ -51351,6 +51512,11 @@ Object.freeze({
51351
51512
  form: "single",
51352
51513
  optional: false
51353
51514
  }],
51515
+ "dayNight.getStatus": [{
51516
+ name: "deviceId",
51517
+ form: "single",
51518
+ optional: false
51519
+ }],
51354
51520
  "dayNight.setSettings": [{
51355
51521
  name: "deviceId",
51356
51522
  form: "single",
@@ -51361,11 +51527,31 @@ Object.freeze({
51361
51527
  form: "single",
51362
51528
  optional: true
51363
51529
  }],
51530
+ "detectionPipeline.applyDeviceSettingsPatch": [{
51531
+ name: "deviceId",
51532
+ form: "single",
51533
+ optional: false
51534
+ }],
51535
+ "detectionPipeline.getDeviceLiveContribution": [{
51536
+ name: "deviceId",
51537
+ form: "single",
51538
+ optional: false
51539
+ }],
51540
+ "detectionPipeline.getDeviceSettingsContribution": [{
51541
+ name: "deviceId",
51542
+ form: "single",
51543
+ optional: false
51544
+ }],
51364
51545
  "deviceAdminLink.getAdminLink": [{
51365
51546
  name: "deviceId",
51366
51547
  form: "single",
51367
51548
  optional: false
51368
51549
  }],
51550
+ "deviceAdoption.getStatus": [{
51551
+ name: "deviceId",
51552
+ form: "single",
51553
+ optional: false
51554
+ }],
51369
51555
  "deviceAdoption.release": [{
51370
51556
  name: "camDeviceId",
51371
51557
  form: "single",
@@ -51381,6 +51567,11 @@ Object.freeze({
51381
51567
  form: "single",
51382
51568
  optional: false
51383
51569
  }],
51570
+ "deviceDiscovery.getStatus": [{
51571
+ name: "deviceId",
51572
+ form: "single",
51573
+ optional: false
51574
+ }],
51384
51575
  "deviceDiscovery.listDiscovered": [{
51385
51576
  name: "deviceId",
51386
51577
  form: "single",
@@ -51400,6 +51591,21 @@ Object.freeze({
51400
51591
  form: "single",
51401
51592
  optional: false
51402
51593
  }],
51594
+ "deviceExport.applyDeviceSettingsPatch": [{
51595
+ name: "deviceId",
51596
+ form: "single",
51597
+ optional: false
51598
+ }],
51599
+ "deviceExport.getDeviceLiveContribution": [{
51600
+ name: "deviceId",
51601
+ form: "single",
51602
+ optional: false
51603
+ }],
51604
+ "deviceExport.getDeviceSettingsContribution": [{
51605
+ name: "deviceId",
51606
+ form: "single",
51607
+ optional: false
51608
+ }],
51403
51609
  "deviceExtension.listCandidates": [{
51404
51610
  name: "deviceId",
51405
51611
  form: "single",
@@ -51748,6 +51954,26 @@ Object.freeze({
51748
51954
  form: "single",
51749
51955
  optional: false
51750
51956
  }],
51957
+ "deviceStatus.getStatus": [{
51958
+ name: "deviceId",
51959
+ form: "single",
51960
+ optional: false
51961
+ }],
51962
+ "doorbell.getStatus": [{
51963
+ name: "deviceId",
51964
+ form: "single",
51965
+ optional: false
51966
+ }],
51967
+ "enumSensor.getStatus": [{
51968
+ name: "deviceId",
51969
+ form: "single",
51970
+ optional: false
51971
+ }],
51972
+ "eventEmitter.getStatus": [{
51973
+ name: "deviceId",
51974
+ form: "single",
51975
+ optional: false
51976
+ }],
51751
51977
  "faceGallery.getFaceByTrack": [{
51752
51978
  name: "deviceId",
51753
51979
  form: "single",
@@ -51762,6 +51988,11 @@ Object.freeze({
51762
51988
  form: "array",
51763
51989
  optional: true
51764
51990
  }],
51991
+ "fanControl.getStatus": [{
51992
+ name: "deviceId",
51993
+ form: "single",
51994
+ optional: false
51995
+ }],
51765
51996
  "fanControl.setDirection": [{
51766
51997
  name: "deviceId",
51767
51998
  form: "single",
@@ -51782,6 +52013,26 @@ Object.freeze({
51782
52013
  form: "single",
51783
52014
  optional: false
51784
52015
  }],
52016
+ "featureProbe.getStatus": [{
52017
+ name: "deviceId",
52018
+ form: "single",
52019
+ optional: false
52020
+ }],
52021
+ "flood.getStatus": [{
52022
+ name: "deviceId",
52023
+ form: "single",
52024
+ optional: false
52025
+ }],
52026
+ "gas.getStatus": [{
52027
+ name: "deviceId",
52028
+ form: "single",
52029
+ optional: false
52030
+ }],
52031
+ "humidifier.getStatus": [{
52032
+ name: "deviceId",
52033
+ form: "single",
52034
+ optional: false
52035
+ }],
51785
52036
  "humidifier.setMode": [{
51786
52037
  name: "deviceId",
51787
52038
  form: "single",
@@ -51797,11 +52048,26 @@ Object.freeze({
51797
52048
  form: "single",
51798
52049
  optional: false
51799
52050
  }],
52051
+ "humiditySensor.getStatus": [{
52052
+ name: "deviceId",
52053
+ form: "single",
52054
+ optional: false
52055
+ }],
52056
+ "image.getStatus": [{
52057
+ name: "deviceId",
52058
+ form: "single",
52059
+ optional: false
52060
+ }],
51800
52061
  "imageSettings.getOptions": [{
51801
52062
  name: "deviceId",
51802
52063
  form: "single",
51803
52064
  optional: false
51804
52065
  }],
52066
+ "imageSettings.getStatus": [{
52067
+ name: "deviceId",
52068
+ form: "single",
52069
+ optional: false
52070
+ }],
51805
52071
  "imageSettings.setSettings": [{
51806
52072
  name: "deviceId",
51807
52073
  form: "single",
@@ -51812,6 +52078,11 @@ Object.freeze({
51812
52078
  form: "single",
51813
52079
  optional: false
51814
52080
  }],
52081
+ "intercom.getStatus": [{
52082
+ name: "deviceId",
52083
+ form: "single",
52084
+ optional: false
52085
+ }],
51815
52086
  "intercom.handleAnswer": [{
51816
52087
  name: "deviceId",
51817
52088
  form: "single",
@@ -51842,6 +52113,11 @@ Object.freeze({
51842
52113
  form: "single",
51843
52114
  optional: false
51844
52115
  }],
52116
+ "lawnMowerControl.getStatus": [{
52117
+ name: "deviceId",
52118
+ form: "single",
52119
+ optional: false
52120
+ }],
51845
52121
  "lawnMowerControl.pause": [{
51846
52122
  name: "deviceId",
51847
52123
  form: "single",
@@ -51852,6 +52128,11 @@ Object.freeze({
51852
52128
  form: "single",
51853
52129
  optional: false
51854
52130
  }],
52131
+ "lockControl.getStatus": [{
52132
+ name: "deviceId",
52133
+ form: "single",
52134
+ optional: false
52135
+ }],
51855
52136
  "lockControl.lock": [{
51856
52137
  name: "deviceId",
51857
52138
  form: "single",
@@ -51867,6 +52148,11 @@ Object.freeze({
51867
52148
  form: "single",
51868
52149
  optional: false
51869
52150
  }],
52151
+ "mediaPlayer.getStatus": [{
52152
+ name: "deviceId",
52153
+ form: "single",
52154
+ optional: false
52155
+ }],
51870
52156
  "mediaPlayer.next": [{
51871
52157
  name: "deviceId",
51872
52158
  form: "single",
@@ -51927,6 +52213,11 @@ Object.freeze({
51927
52213
  form: "single",
51928
52214
  optional: false
51929
52215
  }],
52216
+ "motion.getStatus": [{
52217
+ name: "deviceId",
52218
+ form: "single",
52219
+ optional: false
52220
+ }],
51930
52221
  "motion.isDetected": [{
51931
52222
  name: "deviceId",
51932
52223
  form: "single",
@@ -51937,11 +52228,31 @@ Object.freeze({
51937
52228
  form: "single",
51938
52229
  optional: false
51939
52230
  }],
52231
+ "motionDetection.applyDeviceSettingsPatch": [{
52232
+ name: "deviceId",
52233
+ form: "single",
52234
+ optional: false
52235
+ }],
52236
+ "motionDetection.getDeviceLiveContribution": [{
52237
+ name: "deviceId",
52238
+ form: "single",
52239
+ optional: false
52240
+ }],
52241
+ "motionDetection.getDeviceSettingsContribution": [{
52242
+ name: "deviceId",
52243
+ form: "single",
52244
+ optional: false
52245
+ }],
51940
52246
  "motionDetection.removeCamera": [{
51941
52247
  name: "deviceId",
51942
52248
  form: "single",
51943
52249
  optional: false
51944
52250
  }],
52251
+ "motionTrigger.getStatus": [{
52252
+ name: "deviceId",
52253
+ form: "single",
52254
+ optional: false
52255
+ }],
51945
52256
  "motionTrigger.setMotionTrigger": [{
51946
52257
  name: "deviceId",
51947
52258
  form: "single",
@@ -51952,6 +52263,11 @@ Object.freeze({
51952
52263
  form: "single",
51953
52264
  optional: false
51954
52265
  }],
52266
+ "motionZones.getStatus": [{
52267
+ name: "deviceId",
52268
+ form: "single",
52269
+ optional: false
52270
+ }],
51955
52271
  "motionZones.setZone": [{
51956
52272
  name: "deviceId",
51957
52273
  form: "single",
@@ -51962,6 +52278,11 @@ Object.freeze({
51962
52278
  form: "single",
51963
52279
  optional: false
51964
52280
  }],
52281
+ "nativeObjectDetection.getStatus": [{
52282
+ name: "deviceId",
52283
+ form: "single",
52284
+ optional: false
52285
+ }],
51965
52286
  "nativeObjectDetection.setEnabled": [{
51966
52287
  name: "deviceId",
51967
52288
  form: "single",
@@ -51977,6 +52298,11 @@ Object.freeze({
51977
52298
  form: "single",
51978
52299
  optional: false
51979
52300
  }],
52301
+ "navigation.getStatus": [{
52302
+ name: "deviceId",
52303
+ form: "single",
52304
+ optional: false
52305
+ }],
51980
52306
  "navigation.goToPoint": [{
51981
52307
  name: "deviceId",
51982
52308
  form: "single",
@@ -52022,6 +52348,11 @@ Object.freeze({
52022
52348
  form: "single",
52023
52349
  optional: false
52024
52350
  }],
52351
+ "networkLink.getStatus": [{
52352
+ name: "deviceId",
52353
+ form: "single",
52354
+ optional: false
52355
+ }],
52025
52356
  "networkQuality.getDeviceStats": [{
52026
52357
  name: "deviceId",
52027
52358
  form: "single",
@@ -52047,11 +52378,26 @@ Object.freeze({
52047
52378
  form: "single",
52048
52379
  optional: false
52049
52380
  }],
52381
+ "notifier.getStatus": [{
52382
+ name: "deviceId",
52383
+ form: "single",
52384
+ optional: false
52385
+ }],
52050
52386
  "notifier.send": [{
52051
52387
  name: "deviceId",
52052
52388
  form: "single",
52053
52389
  optional: false
52054
52390
  }],
52391
+ "numericSensor.getStatus": [{
52392
+ name: "deviceId",
52393
+ form: "single",
52394
+ optional: false
52395
+ }],
52396
+ "osd.getStatus": [{
52397
+ name: "deviceId",
52398
+ form: "single",
52399
+ optional: false
52400
+ }],
52055
52401
  "osd.setOverlay": [{
52056
52402
  name: "deviceId",
52057
52403
  form: "single",
@@ -52111,6 +52457,11 @@ Object.freeze({
52111
52457
  form: "single",
52112
52458
  optional: false
52113
52459
  }],
52460
+ "petFeeder.getStatus": [{
52461
+ name: "deviceId",
52462
+ form: "single",
52463
+ optional: false
52464
+ }],
52114
52465
  "petFeeder.markFoodReplenished": [{
52115
52466
  name: "deviceId",
52116
52467
  form: "single",
@@ -52146,6 +52497,11 @@ Object.freeze({
52146
52497
  form: "single",
52147
52498
  optional: false
52148
52499
  }],
52500
+ "pipelineAnalytics.applyDeviceSettingsPatch": [{
52501
+ name: "deviceId",
52502
+ form: "single",
52503
+ optional: false
52504
+ }],
52149
52505
  "pipelineAnalytics.clearTrackRelation": [{
52150
52506
  name: "deviceId",
52151
52507
  form: "single",
@@ -52186,6 +52542,16 @@ Object.freeze({
52186
52542
  form: "single",
52187
52543
  optional: false
52188
52544
  }],
52545
+ "pipelineAnalytics.getDeviceLiveContribution": [{
52546
+ name: "deviceId",
52547
+ form: "single",
52548
+ optional: false
52549
+ }],
52550
+ "pipelineAnalytics.getDeviceSettingsContribution": [{
52551
+ name: "deviceId",
52552
+ form: "single",
52553
+ optional: false
52554
+ }],
52189
52555
  "pipelineAnalytics.getEventDensity": [{
52190
52556
  name: "deviceId",
52191
52557
  form: "single",
@@ -52401,6 +52767,11 @@ Object.freeze({
52401
52767
  form: "single",
52402
52768
  optional: true
52403
52769
  }],
52770
+ "pipelineOrchestrator.applyDeviceSettingsPatch": [{
52771
+ name: "deviceId",
52772
+ form: "single",
52773
+ optional: false
52774
+ }],
52404
52775
  "pipelineOrchestrator.assignAudio": [{
52405
52776
  name: "deviceId",
52406
52777
  form: "single",
@@ -52446,6 +52817,16 @@ Object.freeze({
52446
52817
  form: "single",
52447
52818
  optional: false
52448
52819
  }],
52820
+ "pipelineOrchestrator.getDeviceLiveContribution": [{
52821
+ name: "deviceId",
52822
+ form: "single",
52823
+ optional: false
52824
+ }],
52825
+ "pipelineOrchestrator.getDeviceSettingsContribution": [{
52826
+ name: "deviceId",
52827
+ form: "single",
52828
+ optional: false
52829
+ }],
52449
52830
  "pipelineOrchestrator.getPipelineAssignment": [{
52450
52831
  name: "deviceId",
52451
52832
  form: "single",
@@ -52566,11 +52947,31 @@ Object.freeze({
52566
52947
  form: "single",
52567
52948
  optional: true
52568
52949
  }],
52950
+ "powerMeter.getStatus": [{
52951
+ name: "deviceId",
52952
+ form: "single",
52953
+ optional: false
52954
+ }],
52955
+ "presence.getStatus": [{
52956
+ name: "deviceId",
52957
+ form: "single",
52958
+ optional: false
52959
+ }],
52960
+ "pressureSensor.getStatus": [{
52961
+ name: "deviceId",
52962
+ form: "single",
52963
+ optional: false
52964
+ }],
52569
52965
  "privacyMask.getOptions": [{
52570
52966
  name: "deviceId",
52571
52967
  form: "single",
52572
52968
  optional: false
52573
52969
  }],
52970
+ "privacyMask.getStatus": [{
52971
+ name: "deviceId",
52972
+ form: "single",
52973
+ optional: false
52974
+ }],
52574
52975
  "privacyMask.setAudioEnabled": [{
52575
52976
  name: "deviceId",
52576
52977
  form: "single",
@@ -52621,6 +53022,11 @@ Object.freeze({
52621
53022
  form: "single",
52622
53023
  optional: false
52623
53024
  }],
53025
+ "ptz.getStatus": [{
53026
+ name: "deviceId",
53027
+ form: "single",
53028
+ optional: false
53029
+ }],
52624
53030
  "ptz.goHome": [{
52625
53031
  name: "deviceId",
52626
53032
  form: "single",
@@ -52711,6 +53117,11 @@ Object.freeze({
52711
53117
  form: "single",
52712
53118
  optional: false
52713
53119
  }],
53120
+ "recordingArchive.applyDeviceSettingsPatch": [{
53121
+ name: "deviceId",
53122
+ form: "single",
53123
+ optional: false
53124
+ }],
52714
53125
  "recordingArchive.deleteFootprint": [{
52715
53126
  name: "deviceId",
52716
53127
  form: "single",
@@ -52731,6 +53142,21 @@ Object.freeze({
52731
53142
  form: "single",
52732
53143
  optional: false
52733
53144
  }],
53145
+ "recordingArchive.getDeviceLiveContribution": [{
53146
+ name: "deviceId",
53147
+ form: "single",
53148
+ optional: false
53149
+ }],
53150
+ "recordingArchive.getDeviceSettingsContribution": [{
53151
+ name: "deviceId",
53152
+ form: "single",
53153
+ optional: false
53154
+ }],
53155
+ "recordingArchive.getStatus": [{
53156
+ name: "deviceId",
53157
+ form: "single",
53158
+ optional: false
53159
+ }],
52734
53160
  "recordingArchive.listOpsLog": [{
52735
53161
  name: "deviceId",
52736
53162
  form: "single",
@@ -52816,6 +53242,11 @@ Object.freeze({
52816
53242
  form: "single",
52817
53243
  optional: false
52818
53244
  }],
53245
+ "recordingOnboard.getStatus": [{
53246
+ name: "deviceId",
53247
+ form: "single",
53248
+ optional: false
53249
+ }],
52819
53250
  "recordingOnboard.setSettings": [{
52820
53251
  name: "deviceId",
52821
53252
  form: "single",
@@ -52846,6 +53277,11 @@ Object.freeze({
52846
53277
  form: "single",
52847
53278
  optional: false
52848
53279
  }],
53280
+ "sceneMonitor.getStatus": [{
53281
+ name: "deviceId",
53282
+ form: "single",
53283
+ optional: false
53284
+ }],
52849
53285
  "sceneMonitor.listScenes": [{
52850
53286
  name: "deviceId",
52851
53287
  form: "single",
@@ -52871,6 +53307,11 @@ Object.freeze({
52871
53307
  form: "single",
52872
53308
  optional: false
52873
53309
  }],
53310
+ "scriptRunner.getStatus": [{
53311
+ name: "deviceId",
53312
+ form: "single",
53313
+ optional: false
53314
+ }],
52874
53315
  "scriptRunner.run": [{
52875
53316
  name: "deviceId",
52876
53317
  form: "single",
@@ -52881,11 +53322,31 @@ Object.freeze({
52881
53322
  form: "single",
52882
53323
  optional: false
52883
53324
  }],
53325
+ "smoke.getStatus": [{
53326
+ name: "deviceId",
53327
+ form: "single",
53328
+ optional: false
53329
+ }],
53330
+ "snapshot.applyDeviceSettingsPatch": [{
53331
+ name: "deviceId",
53332
+ form: "single",
53333
+ optional: false
53334
+ }],
52884
53335
  "snapshot.getDebugState": [{
52885
53336
  name: "deviceId",
52886
53337
  form: "single",
52887
53338
  optional: false
52888
53339
  }],
53340
+ "snapshot.getDeviceLiveContribution": [{
53341
+ name: "deviceId",
53342
+ form: "single",
53343
+ optional: false
53344
+ }],
53345
+ "snapshot.getDeviceSettingsContribution": [{
53346
+ name: "deviceId",
53347
+ form: "single",
53348
+ optional: false
53349
+ }],
52889
53350
  "snapshot.getSnapshot": [{
52890
53351
  name: "deviceId",
52891
53352
  form: "single",
@@ -52902,6 +53363,11 @@ Object.freeze({
52902
53363
  form: "array",
52903
53364
  optional: false
52904
53365
  }],
53366
+ "snapshot.getStatus": [{
53367
+ name: "deviceId",
53368
+ form: "single",
53369
+ optional: false
53370
+ }],
52905
53371
  "snapshot.invalidateCache": [{
52906
53372
  name: "deviceId",
52907
53373
  form: "single",
@@ -52912,6 +53378,11 @@ Object.freeze({
52912
53378
  form: "single",
52913
53379
  optional: false
52914
53380
  }],
53381
+ "streamBroker.applyDeviceSettingsPatch": [{
53382
+ name: "deviceId",
53383
+ form: "single",
53384
+ optional: false
53385
+ }],
52915
53386
  "streamBroker.assignProfile": [{
52916
53387
  name: "deviceId",
52917
53388
  form: "single",
@@ -52927,6 +53398,16 @@ Object.freeze({
52927
53398
  form: "single",
52928
53399
  optional: false
52929
53400
  }],
53401
+ "streamBroker.getDeviceLiveContribution": [{
53402
+ name: "deviceId",
53403
+ form: "single",
53404
+ optional: false
53405
+ }],
53406
+ "streamBroker.getDeviceSettingsContribution": [{
53407
+ name: "deviceId",
53408
+ form: "single",
53409
+ optional: false
53410
+ }],
52930
53411
  "streamBroker.getStreamWithCodec": [{
52931
53412
  name: "deviceId",
52932
53413
  form: "single",
@@ -52987,16 +53468,46 @@ Object.freeze({
52987
53468
  form: "single",
52988
53469
  optional: false
52989
53470
  }],
53471
+ "streamParams.getStatus": [{
53472
+ name: "deviceId",
53473
+ form: "single",
53474
+ optional: false
53475
+ }],
52990
53476
  "streamParams.setProfile": [{
52991
53477
  name: "deviceId",
52992
53478
  form: "single",
52993
53479
  optional: false
52994
53480
  }],
53481
+ "switch.getStatus": [{
53482
+ name: "deviceId",
53483
+ form: "single",
53484
+ optional: false
53485
+ }],
52995
53486
  "switch.setState": [{
52996
53487
  name: "deviceId",
52997
53488
  form: "single",
52998
53489
  optional: false
52999
53490
  }],
53491
+ "tamper.getStatus": [{
53492
+ name: "deviceId",
53493
+ form: "single",
53494
+ optional: false
53495
+ }],
53496
+ "temperatureSensor.getStatus": [{
53497
+ name: "deviceId",
53498
+ form: "single",
53499
+ optional: false
53500
+ }],
53501
+ "update.getStatus": [{
53502
+ name: "deviceId",
53503
+ form: "single",
53504
+ optional: false
53505
+ }],
53506
+ "vacuumControl.getStatus": [{
53507
+ name: "deviceId",
53508
+ form: "single",
53509
+ optional: false
53510
+ }],
53000
53511
  "vacuumControl.locate": [{
53001
53512
  name: "deviceId",
53002
53513
  form: "single",
@@ -53032,6 +53543,11 @@ Object.freeze({
53032
53543
  form: "single",
53033
53544
  optional: false
53034
53545
  }],
53546
+ "valve.getStatus": [{
53547
+ name: "deviceId",
53548
+ form: "single",
53549
+ optional: false
53550
+ }],
53035
53551
  "valve.open": [{
53036
53552
  name: "deviceId",
53037
53553
  form: "single",
@@ -53047,6 +53563,11 @@ Object.freeze({
53047
53563
  form: "single",
53048
53564
  optional: false
53049
53565
  }],
53566
+ "vibration.getStatus": [{
53567
+ name: "deviceId",
53568
+ form: "single",
53569
+ optional: false
53570
+ }],
53050
53571
  "videoclips.dialClipStream": [{
53051
53572
  name: "deviceId",
53052
53573
  form: "single",
@@ -53082,6 +53603,11 @@ Object.freeze({
53082
53603
  form: "single",
53083
53604
  optional: false
53084
53605
  }],
53606
+ "waterHeater.getStatus": [{
53607
+ name: "deviceId",
53608
+ form: "single",
53609
+ optional: false
53610
+ }],
53085
53611
  "waterHeater.setAway": [{
53086
53612
  name: "deviceId",
53087
53613
  form: "single",
@@ -53097,6 +53623,11 @@ Object.freeze({
53097
53623
  form: "single",
53098
53624
  optional: false
53099
53625
  }],
53626
+ "weather.getStatus": [{
53627
+ name: "deviceId",
53628
+ form: "single",
53629
+ optional: false
53630
+ }],
53100
53631
  "webrtcSession.addIceCandidate": [{
53101
53632
  name: "deviceId",
53102
53633
  form: "single",
@@ -53716,6 +54247,16 @@ function ruleKindOf(rule) {
53716
54247
  return "detection";
53717
54248
  }
53718
54249
  /**
54250
+ * May this rule carry `groupingSec` (D692 §2.2)? Only an `immediate` DETECTION rule: a
54251
+ * track-end rule fires at close and already carries the name; a parcel, a sound (its
54252
+ * `trackId` is a photograph owner, not a subject), a sensor, an occupancy edge and every
54253
+ * system family have no subject to promote and no tile per subject. ONE predicate, read by
54254
+ * both editors and the hub's save guard.
54255
+ */
54256
+ function ruleGroupingApplies(rule) {
54257
+ return rule.delivery === "immediate" && ruleKindOf(rule) === "detection";
54258
+ }
54259
+ /**
53719
54260
  * A system rule's kind: its one family, or `mixed` (D637).
53720
54261
  *
53721
54262
  * Takes the UNTYPED condition for the same reason {@link NcRuleConditionsSubject}
@@ -55163,7 +55704,7 @@ var PreviewTextField = string().max(200);
55163
55704
  * Whether the notification's preview is a STILL or a short animation.
55164
55705
  *
55165
55706
  * The operator's ask, verbatim: *"inviato come gif o video (come per le altre
55166
- * rule)"* — the other rules already offer an animated preview, and a ten-hour
55707
+ * rule)"* [sent as a gif or video (as for the other rules)] — the other rules already offer an animated preview, and a ten-hour
55167
55708
  * night reads better as three seconds of motion than as one frame of it. Both
55168
55709
  * modes get the SAME treatment (blurred frame, large centred title); `'gif'`
55169
55710
  * simply applies it to a dozen frames sampled across the render and assembles
@@ -56733,6 +57274,24 @@ Object.defineProperty(exports, "NC_DEFAULT_SNOOZE_MINUTES", {
56733
57274
  return NC_DEFAULT_SNOOZE_MINUTES;
56734
57275
  }
56735
57276
  });
57277
+ Object.defineProperty(exports, "NC_GROUPING_DEFAULT_SEC", {
57278
+ enumerable: true,
57279
+ get: function() {
57280
+ return NC_GROUPING_DEFAULT_SEC;
57281
+ }
57282
+ });
57283
+ Object.defineProperty(exports, "NC_GROUPING_MAX_SEC", {
57284
+ enumerable: true,
57285
+ get: function() {
57286
+ return NC_GROUPING_MAX_SEC;
57287
+ }
57288
+ });
57289
+ Object.defineProperty(exports, "NC_GROUPING_MIN_SEC", {
57290
+ enumerable: true,
57291
+ get: function() {
57292
+ return NC_GROUPING_MIN_SEC;
57293
+ }
57294
+ });
56736
57295
  Object.defineProperty(exports, "NC_SENSOR_TRANSITION_KINDS", {
56737
57296
  enumerable: true,
56738
57297
  get: function() {
@@ -57333,6 +57892,12 @@ Object.defineProperty(exports, "isMediaOwnerType", {
57333
57892
  return isMediaOwnerType;
57334
57893
  }
57335
57894
  });
57895
+ Object.defineProperty(exports, "isRetiredClearKey", {
57896
+ enumerable: true,
57897
+ get: function() {
57898
+ return isRetiredClearKey;
57899
+ }
57900
+ });
57336
57901
  Object.defineProperty(exports, "isScheduleActive", {
57337
57902
  enumerable: true,
57338
57903
  get: function() {
@@ -57525,6 +58090,12 @@ Object.defineProperty(exports, "ruleDeviceCompatCapQueries", {
57525
58090
  return ruleDeviceCompatCapQueries;
57526
58091
  }
57527
58092
  });
58093
+ Object.defineProperty(exports, "ruleGroupingApplies", {
58094
+ enumerable: true,
58095
+ get: function() {
58096
+ return ruleGroupingApplies;
58097
+ }
58098
+ });
57528
58099
  Object.defineProperty(exports, "ruleKindOf", {
57529
58100
  enumerable: true,
57530
58101
  get: function() {
@@ -57615,6 +58186,12 @@ Object.defineProperty(exports, "templateCarriesSummary", {
57615
58186
  return templateCarriesSummary;
57616
58187
  }
57617
58188
  });
58189
+ Object.defineProperty(exports, "templateLiteral", {
58190
+ enumerable: true,
58191
+ get: function() {
58192
+ return templateLiteral;
58193
+ }
58194
+ });
57618
58195
  Object.defineProperty(exports, "templateVarsFor", {
57619
58196
  enumerable: true,
57620
58197
  get: function() {