@camstack/addon-post-analysis 1.2.280 → 1.2.282

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.
@@ -1,3 +1,4 @@
1
+ import { createHash } from "node:crypto";
1
2
  //#region ../types/dist/event-category-BVDXG4tB.mjs
2
3
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
3
4
  EventCategory["SystemBoot"] = "system.boot";
@@ -5359,7 +5360,7 @@ var ZodIssueCode = {
5359
5360
  var ZodFirstPartyTypeKind;
5360
5361
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5361
5362
  //#endregion
5362
- //#region ../types/dist/sleep-D_4W7xuQ.mjs
5363
+ //#region ../types/dist/sleep-DU7mu4wb.mjs
5363
5364
  /**
5364
5365
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5365
5366
  * window to float samples (D455).
@@ -7567,6 +7568,39 @@ function sleep(ms) {
7567
7568
  return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
7568
7569
  }
7569
7570
  //#endregion
7571
+ //#region ../types/dist/canonical-hash-CPK2Dy60.mjs
7572
+ /**
7573
+ * Deterministic SHA-256 hash of an arbitrary serialisable value. The
7574
+ * canonical form sorts object keys alphabetically at every depth so two
7575
+ * structurally-equal inputs with different key insertion orders produce
7576
+ * the same hash. Returns a 64-char lowercase hex digest.
7577
+ *
7578
+ * Used by export adapters (Alexa, HAP) to short-circuit re-discovery /
7579
+ * accessory-rebuild work when the upstream shape is byte-identical to
7580
+ * the last applied state — preventing user-visible "re-discovery"
7581
+ * notifications on every addon-runner respawn. Each respawn re-fires
7582
+ * `DeviceBindingsChanged` for every cap registration, which without
7583
+ * this guard would propagate redundant pushes.
7584
+ *
7585
+ * Note: this is a SYMPTOMATIC fix layered on top of the binding-change
7586
+ * subscription. The proper fix is a single "device ready" lifecycle
7587
+ * barrier so exports react only when the full cap set has landed —
7588
+ * tracked separately for post-HA-integration work.
7589
+ */
7590
+ function canonicalHash(value) {
7591
+ const canonical = JSON.stringify(value, replaceWithSortedKeys);
7592
+ return createHash("sha256").update(canonical ?? "").digest("hex");
7593
+ }
7594
+ function replaceWithSortedKeys(_key, value) {
7595
+ if (value && typeof value === "object" && !Array.isArray(value)) {
7596
+ const obj = value;
7597
+ const out = {};
7598
+ for (const k of Object.keys(obj).toSorted()) out[k] = obj[k];
7599
+ return out;
7600
+ }
7601
+ return value;
7602
+ }
7603
+ //#endregion
7570
7604
  //#region ../types/dist/err-msg-IQTHeDzc.mjs
7571
7605
  /**
7572
7606
  import { errMsg } from '@camstack/types'
@@ -18144,6 +18178,16 @@ var NcCrossingSchema = _enum([
18144
18178
  "exit",
18145
18179
  "any"
18146
18180
  ]);
18181
+ /**
18182
+ * Which edge of a BOOLEAN sensor fires a device-event rule (D640).
18183
+ * - `raised` — the sensor went high: water detected, smoke, open, tampered.
18184
+ * - `cleared` — it went back: dry, clear, closed.
18185
+ * - absent — both edges, which is what every rule authored before this did.
18186
+ *
18187
+ * There is no third member for "both": absence already says it, and a value
18188
+ * that means the same as absence is a second way to write one rule.
18189
+ */
18190
+ var NcSensorTransitionSchema = _enum(["raised", "cleared"]);
18147
18191
  /** Admin-zone membership condition (zone IDs as stamped by the ZoneEngine). */
18148
18192
  var NcZoneConditionSchema = object({
18149
18193
  ids: array(string().min(1)).min(1),
@@ -18333,6 +18377,20 @@ var NcConditionsSchema = object({
18333
18377
  scene: NcSceneConditionSchema.optional(),
18334
18378
  /** Device scope — absent = all devices. */
18335
18379
  devices: array(number()).optional(),
18380
+ /**
18381
+ * Device EXCLUSION (D641) — "every device except these". Judged on the SAME
18382
+ * subject ids {@link devices} is judged on (the camera, the sensor that
18383
+ * fired, a linked set's sensor and row cameras), so a sensor fanned out per
18384
+ * linked camera is excluded exactly where an include would have tested it.
18385
+ * `min(1)`: an empty exclusion excludes nothing and is written as absent.
18386
+ *
18387
+ * Not for `system-event` rules — those carry their own
18388
+ * `systemEvent.excludeDeviceIds` (D636), and the hub refuses this key there.
18389
+ * Editors present the two lists as ONE field (All | Only these | All except
18390
+ * these); the engine evaluates each independently, so a legacy rule
18391
+ * carrying both still means "these, minus those".
18392
+ */
18393
+ devicesExclude: array(number()).min(1).optional(),
18336
18394
  /** Detector class names (any overlap with the record's class set). */
18337
18395
  classes: array(string().min(1)).optional(),
18338
18396
  /** Veto classes — any overlap fails the rule. */
@@ -18466,6 +18524,16 @@ var NcConditionsSchema = object({
18466
18524
  */
18467
18525
  sensorKinds: array(string().min(1)).optional(),
18468
18526
  /**
18527
+ * DEVICE-EVENT only (D640). Fire on one edge of a boolean sensor —
18528
+ * {@link NcSensorTransitionSchema}. Which field of the slice means "raised"
18529
+ * is `@camstack/types` → `notification/sensor-raised.ts`. A reading the
18530
+ * engine cannot place (a kind with no raise, an unreadable slice) PASSES:
18531
+ * the condition fails open towards notifying, never towards silence. Editors
18532
+ * offer it only when every chosen {@link sensorKinds} member has a raise
18533
+ * (`sensorTransitionOffered`), and the hub refuses it on any other delivery.
18534
+ */
18535
+ sensorTransition: NcSensorTransitionSchema.optional(),
18536
+ /**
18469
18537
  * PACKAGE-EVENT only. Which package phase fires the rule — `delivered`
18470
18538
  * (a parked parcel appeared), `picked-up` (it departed), or `both`. Fails
18471
18539
  * when the subject's phase does not match (a subject always carries a phase
@@ -18965,9 +19033,29 @@ var NcTestResultSchema = object({
18965
19033
  className: string().optional(),
18966
19034
  label: string().optional()
18967
19035
  });
18968
- /** The five rule kinds, as data. `NcRuleKind` in `notification/rule-kinds.ts`
18969
- * is the same union; the template-vars spec pins the two together. */
19036
+ /** The rule kinds, as data. `NcRuleKind` in `notification/rule-kinds.ts` is the
19037
+ * same union; the template-vars spec pins the two together. `mixed` is DERIVED
19038
+ * (a stored system rule whose kinds span families, D637) and never authored. */
18970
19039
  var NcRuleKindSchema = _enum([
19040
+ "detection",
19041
+ "sensor",
19042
+ "occupancy",
19043
+ "sound",
19044
+ "device-events",
19045
+ "system",
19046
+ "alarm",
19047
+ "mixed"
19048
+ ]);
19049
+ /**
19050
+ * The kinds a SERVED template-variable descriptor may name: the five that
19051
+ * existed before D637, frozen. `getTemplateCatalog` ships `kinds` to every
19052
+ * installed viewer, and a viewer at `@camstack/types` 1.2.25x parses them with a
19053
+ * strict five-member enum — one `device-events` in one descriptor fails the
19054
+ * whole catalog parse. So the WIRE says `system`, and the MATCH widens it:
19055
+ * `templateVarKindApplies` reads a `system` descriptor as applying to every
19056
+ * system rule kind (`device-events`, `system`, `alarm`, `mixed`).
19057
+ */
19058
+ var NcTemplateVarKindSchema = _enum([
18971
19059
  "detection",
18972
19060
  "sensor",
18973
19061
  "occupancy",
@@ -19005,7 +19093,7 @@ var NcTemplateVarGroupSchema = _enum([
19005
19093
  *
19006
19094
  * `families` / `fields` / `kinds` / `deliveries` / `systemEventKinds` say WHERE
19007
19095
  * it has a value; absent = no restriction on that axis. `systemEventKinds` is
19008
- * read only for a `system` rule. `dynamic` declares a FAMILY of names
19096
+ * read only for a system-event rule (any family, or `mixed`). `dynamic` declares a FAMILY of names
19009
19097
  * (`count_<class>`): the descriptor's `name` is the example member.
19010
19098
  */
19011
19099
  var NcTemplateVarDescriptorSchema = object({
@@ -19016,7 +19104,7 @@ var NcTemplateVarDescriptorSchema = object({
19016
19104
  group: NcTemplateVarGroupSchema,
19017
19105
  families: array(NcTemplateFamilySchema).min(1),
19018
19106
  fields: array(NcTemplateFieldSchema).optional(),
19019
- kinds: array(NcRuleKindSchema).optional(),
19107
+ kinds: array(NcTemplateVarKindSchema).optional(),
19020
19108
  deliveries: array(NcDeliverySchema).optional(),
19021
19109
  systemEventKinds: array(NcSystemEventKindSchema).optional(),
19022
19110
  dynamic: object({
@@ -19064,6 +19152,7 @@ var NcConditionDescriptorSchema = object({
19064
19152
  /** Editor widget the UI renders — never hardcode per-condition forms. */
19065
19153
  valueType: _enum([
19066
19154
  "deviceIdList",
19155
+ "deviceIdExcludeList",
19067
19156
  "stringList",
19068
19157
  "number01",
19069
19158
  "number",
@@ -19074,6 +19163,7 @@ var NcConditionDescriptorSchema = object({
19074
19163
  "plateMatcher",
19075
19164
  "packagePhase",
19076
19165
  "crossingSelect",
19166
+ "sensorTransition",
19077
19167
  "polygonDraw",
19078
19168
  "occupancy",
19079
19169
  "audio",
@@ -19272,6 +19362,21 @@ var NC_CONDITION_CATALOG = [
19272
19362
  phase: "P1",
19273
19363
  description: "Restrict the rule to these devices; absent = all devices. A sensor event matches either the SENSOR that fired or the camera it is attributed to, so a rule may name either one."
19274
19364
  },
19365
+ {
19366
+ id: "devicesExclude",
19367
+ group: "scope",
19368
+ label: "Excluded devices",
19369
+ valueType: "deviceIdExcludeList",
19370
+ operator: "notIn",
19371
+ appliesTo: [
19372
+ "immediate",
19373
+ "track-end",
19374
+ "device-event",
19375
+ "package-event"
19376
+ ],
19377
+ phase: "P1",
19378
+ description: "Every device except these. Judged on the same device ids as Devices: a sensor event is excluded by the SENSOR that fired or by the camera it is attributed to."
19379
+ },
19275
19380
  {
19276
19381
  id: "classes",
19277
19382
  group: "class",
@@ -19528,6 +19633,33 @@ var NC_CONDITION_CATALOG = [
19528
19633
  phase: "P1",
19529
19634
  description: "Raw device event-type tokens (e.g. doorbell press / press_long) from the event-emitter slice; absent on doorbell-pulse / passive sensors."
19530
19635
  },
19636
+ {
19637
+ id: "sensorTransition",
19638
+ group: "device",
19639
+ label: "Notify when",
19640
+ valueType: "sensorTransition",
19641
+ options: [
19642
+ {
19643
+ value: "",
19644
+ label: "It triggers and when it clears",
19645
+ hint: "Every change: water detected, and back to dry."
19646
+ },
19647
+ {
19648
+ value: "raised",
19649
+ label: "Only when it triggers",
19650
+ hint: "Water detected, smoke, a contact opening — never the return to normal."
19651
+ },
19652
+ {
19653
+ value: "cleared",
19654
+ label: "Only when it clears",
19655
+ hint: "Back to dry, smoke gone, a contact closing — never the alert itself."
19656
+ }
19657
+ ],
19658
+ operator: "in",
19659
+ appliesTo: ["device-event"],
19660
+ phase: "P2",
19661
+ description: "Fire on one edge of a boolean sensor. Offered only when every chosen sensor kind raises and clears; a reading that cannot be placed still notifies."
19662
+ },
19531
19663
  {
19532
19664
  id: "packagePhase",
19533
19665
  group: "package",
@@ -19711,6 +19843,28 @@ var NcHistoryFilterSchema = object({
19711
19843
  limit: number().int().min(1).max(500).default(100)
19712
19844
  });
19713
19845
  /**
19846
+ * Every rule's last run, in one answer.
19847
+ *
19848
+ * A rule ABSENT from `runs` produced no delivery inside `horizonMs` — how far
19849
+ * back this answer looked, in ms before the hub's now. It is the outbox prune
19850
+ * window (7 days by default, operator-configurable), NARROWED when the read hit
19851
+ * its row bound: the answer never claims a window it did not read. `null` means
19852
+ * the operator keeps the outbox forever AND the read reached its end, so absent
19853
+ * means "never on record". A UI derives its "not in the last N days" from this
19854
+ * value, never from a constant — and only when the call ANSWERED (D315).
19855
+ */
19856
+ var NcRuleLastRunsSchema = object({
19857
+ runs: array(object({
19858
+ ruleId: string(),
19859
+ /** Fire time of the newest row (`createdAt`, epoch ms). */
19860
+ lastAt: number(),
19861
+ status: NcHistoryStatusSchema,
19862
+ /** The camera/device of that row (a digest row files under its first camera). */
19863
+ deviceId: number()
19864
+ })),
19865
+ horizonMs: number().nonnegative().nullable()
19866
+ });
19867
+ /**
19714
19868
  * What a snooze covers. Broader scopes win when several overlap, so one window
19715
19869
  * leaves ONE digest rather than a rule snooze and a whole-feed snooze both
19716
19870
  * summarising the same silence.
@@ -19892,6 +20046,14 @@ var NcAlarmModeCoverageSchema = object({
19892
20046
  /** Ids named by the covering rules. A SUBSET when `allDevices` is true. */
19893
20047
  deviceIds: array(number().int()),
19894
20048
  /**
20049
+ * D641: the ids NOT covered although `allDevices` is true — every unscoped
20050
+ * covering rule EXCLUDES them (`conditions.devicesExclude`) and no named rule
20051
+ * covers them. Always `[]` when `allDevices` is false. Excluded by the rules,
20052
+ * which is not the same as skipped by a switch: never in `skippedDevices`.
20053
+ * Defaulted so an answer computed before this field parses as "none".
20054
+ */
20055
+ allDevicesExcept: array(number().int()).default([]),
20056
+ /**
19895
20057
  * Devices this mode NAMES but cannot actually arm, each with the switch that
19896
20058
  * excludes it.
19897
20059
  *
@@ -20115,6 +20277,15 @@ var notificationRulesCapability = {
20115
20277
  */
20116
20278
  getHistory: method(object({ filter: NcHistoryFilterSchema.default({ limit: 100 }) }), object({ entries: array(NcHistoryEntrySchema) }), { auth: "admin" }),
20117
20279
  /**
20280
+ * The newest delivery of every rule, in ONE bounded read of the outbox —
20281
+ * the "Last run" column. Never a `getHistory` per rule. A rule with no
20282
+ * delivery inside `horizonMs` is absent from `runs`; see
20283
+ * {@link NcRuleLastRunsSchema} for what absent means. A store that cannot
20284
+ * answer FAILS the call rather than answering "nothing ran". Admin-only,
20285
+ * like `getHistory`, of which it is a projection.
20286
+ */
20287
+ getRuleLastRuns: method(object({}), NcRuleLastRunsSchema, { auth: "admin" }),
20288
+ /**
20118
20289
  * Mint a fresh, externally-reachable URL for one artefact a history row
20119
20290
  * named in {@link NcHistoryEntrySchema.shape.artifactIds} — the SAME
20120
20291
  * signed-link mechanism the dispatcher uses to attach media to an
@@ -33169,7 +33340,30 @@ var RenameNodeResultSchema = object({
33169
33340
  nodeId: string(),
33170
33341
  name: string()
33171
33342
  });
33172
- method(_void(), array(TopologyNodeSchema).readonly(), { auth: "admin" }), method(NodeAddonInputSchema, SuccessSchema, {
33343
+ /**
33344
+ * The cheap node list. A consumer's rule for a STORED node id (a rule's
33345
+ * `nodeIds`) that is missing from `nodes`, whatever `complete` says: render it
33346
+ * as a removable chip labelled unknown, never drop it (D49). Even a complete
33347
+ * list omits a node that joined and left between two history captures, so a
33348
+ * missing id means "not known to the hub", never "removed". Only the operator
33349
+ * removes it.
33350
+ *
33351
+ * `complete` changes only the WORDING: `false` = no history read has ever
33352
+ * answered, so the list may be missing offline nodes the hub does know (D315).
33353
+ *
33354
+ * `name` is the history row's name (≤ 30 s behind a rename), or the id when
33355
+ * the history has none.
33356
+ */
33357
+ var NodeDirectorySchema = object({
33358
+ nodes: array(object({
33359
+ id: string(),
33360
+ name: string(),
33361
+ isHub: boolean(),
33362
+ isOnline: boolean()
33363
+ })).readonly(),
33364
+ complete: boolean()
33365
+ });
33366
+ method(_void(), array(TopologyNodeSchema).readonly(), { auth: "admin" }), method(_void(), NodeDirectorySchema, { auth: "admin" }), method(NodeAddonInputSchema, SuccessSchema, {
33173
33367
  kind: "mutation",
33174
33368
  auth: "admin"
33175
33369
  }), method(NodeAddonInputSchema, SuccessSchema, {
@@ -44695,6 +44889,12 @@ Object.freeze({
44695
44889
  addonId: null,
44696
44890
  access: "create"
44697
44891
  },
44892
+ "nodes.directory": {
44893
+ capName: "nodes",
44894
+ capScope: "system",
44895
+ addonId: null,
44896
+ access: "view"
44897
+ },
44698
44898
  "nodes.executeQuery": {
44699
44899
  capName: "nodes",
44700
44900
  capScope: "system",
@@ -44863,6 +45063,12 @@ Object.freeze({
44863
45063
  addonId: null,
44864
45064
  access: "view"
44865
45065
  },
45066
+ "notificationRules.getRuleLastRuns": {
45067
+ capName: "notification-rules",
45068
+ capScope: "system",
45069
+ addonId: null,
45070
+ access: "view"
45071
+ },
44866
45072
  "notificationRules.getTemplateCatalog": {
44867
45073
  capName: "notification-rules",
44868
45074
  capScope: "system",
@@ -50479,6 +50685,253 @@ function audioModeOf(value) {
50479
50685
  return null;
50480
50686
  }
50481
50687
  new Set(["devices", "classes"]);
50688
+ /** Every filter, for the callers that must cover all four (guards, tests). */
50689
+ var NC_SYSTEM_EVENT_FILTER_KEYS = [
50690
+ "deviceIds",
50691
+ "deviceTypes",
50692
+ "nodeIds",
50693
+ "packageNames"
50694
+ ];
50695
+ /**
50696
+ * Does `filter` say anything about `kind`?
50697
+ *
50698
+ * `false` means the filter is not part of this kind's vocabulary: the engine
50699
+ * ignores it and an editor hides its input. It never means "excluded".
50700
+ */
50701
+ function systemEventFilterApplies(kind, filter) {
50702
+ switch (filter) {
50703
+ case "deviceIds": return kind.startsWith("device-") || kind.startsWith("stream-") || kind === "detection-blind" || kind === "alarm-triggered";
50704
+ case "deviceTypes": return kind.startsWith("device-") || kind === "detection-blind";
50705
+ case "nodeIds": return kind.startsWith("node-") || kind === "addon-crash-loop" || kind === "addon-update-available" || kind === "addon-updated" || kind === "server-update-available" || kind === "wrapper-update-available" || kind === "server-updated";
50706
+ case "packageNames": return kind.endsWith("update-available") || kind === "addon-updated" || kind === "server-updated";
50707
+ }
50708
+ }
50709
+ /**
50710
+ * WHICH FAMILY every system-event kind belongs to, and which narrowing filters
50711
+ * each family may carry: one table, read by the hub validator, by `ruleKindOf`
50712
+ * and by both rule editors (D637).
50713
+ *
50714
+ * A system rule used to be one editor for thirty-one kinds and five filters.
50715
+ * "Eventi di sistema" carried battery kinds under a liveness `deviceTypes` filter
50716
+ * and went silent for two weeks (D636). The three families are three questions:
50717
+ * about devices, about the installation, and about the alarm panel. A rule
50718
+ * answers one of them. The engine never needed to know, and it still does not:
50719
+ * a mixed stored rule keeps firing. Only AUTHORING is strict.
50720
+ *
50721
+ * The legacy `camera-*` tail has no family (`null`). It is parsed, never produced,
50722
+ * never offered.
50723
+ */
50724
+ var NC_SYSTEM_EVENT_FAMILIES = [
50725
+ "device-events",
50726
+ "system",
50727
+ "alarm"
50728
+ ];
50729
+ function isSystemEventFamily(value) {
50730
+ return NC_SYSTEM_EVENT_FAMILIES.some((family) => family === value);
50731
+ }
50732
+ /** Total over the enum: a kind added to the cap without a family fails tsc here. */
50733
+ var NC_SYSTEM_EVENT_FAMILY = {
50734
+ "device-online": "device-events",
50735
+ "device-offline": "device-events",
50736
+ "device-disabled": "device-events",
50737
+ "device-enabled": "device-events",
50738
+ "device-battery-low": "device-events",
50739
+ "device-battery-normal": "device-events",
50740
+ "device-consumable-low": "device-events",
50741
+ "device-consumable-normal": "device-events",
50742
+ "stream-online": "device-events",
50743
+ "stream-offline": "device-events",
50744
+ "detection-blind": "device-events",
50745
+ "node-online": "system",
50746
+ "node-offline": "system",
50747
+ "node-inference-unavailable": "system",
50748
+ "addon-crash-loop": "system",
50749
+ "addon-update-available": "system",
50750
+ "addon-updated": "system",
50751
+ "server-update-available": "system",
50752
+ "server-updated": "system",
50753
+ "wrapper-update-available": "system",
50754
+ "backup-completed": "system",
50755
+ "export-completed": "system",
50756
+ "alarm-triggered": "alarm",
50757
+ "alarm-armed": "alarm",
50758
+ "alarm-disarmed": "alarm",
50759
+ "alarm-arming": "alarm",
50760
+ "alarm-arm-refused": "alarm",
50761
+ "alarm-pending": "alarm",
50762
+ "alarm-rearmed": "alarm",
50763
+ "alarm-sensor-bypass": "alarm",
50764
+ "alarm-check-failed": "alarm",
50765
+ "camera-online": null,
50766
+ "camera-offline": null,
50767
+ "camera-disabled": null,
50768
+ "camera-enabled": null
50769
+ };
50770
+ new Map(Object.entries(NC_SYSTEM_EVENT_FAMILY));
50771
+ var NC_SYSTEM_EVENT_CONDITION_FILTER_KEYS = [...NC_SYSTEM_EVENT_FILTER_KEYS, "excludeDeviceIds"];
50772
+ /**
50773
+ * The filters a family may carry. The four base filters are the union of
50774
+ * `systemEventFilterApplies` over the family's kinds (the spec pins that
50775
+ * equality). `excludeDeviceIds` is a device-events filter only: an alarm is
50776
+ * narrowed to the camera that triggered it and excludes nothing.
50777
+ */
50778
+ var NC_SYSTEM_EVENT_FAMILY_FILTERS = {
50779
+ "device-events": [
50780
+ "deviceIds",
50781
+ "excludeDeviceIds",
50782
+ "deviceTypes"
50783
+ ],
50784
+ system: ["nodeIds", "packageNames"],
50785
+ alarm: ["deviceIds"]
50786
+ };
50787
+ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
50788
+ {
50789
+ id: "device-state",
50790
+ family: "device-events",
50791
+ label: "Device state",
50792
+ kinds: [
50793
+ "device-offline",
50794
+ "device-online",
50795
+ "device-disabled",
50796
+ "device-enabled"
50797
+ ]
50798
+ },
50799
+ {
50800
+ id: "streams",
50801
+ family: "device-events",
50802
+ label: "Streams",
50803
+ kinds: ["stream-offline", "stream-online"]
50804
+ },
50805
+ {
50806
+ id: "battery",
50807
+ family: "device-events",
50808
+ label: "Battery",
50809
+ kinds: ["device-battery-low", "device-battery-normal"]
50810
+ },
50811
+ {
50812
+ id: "consumables",
50813
+ family: "device-events",
50814
+ label: "Consumables",
50815
+ kinds: ["device-consumable-low", "device-consumable-normal"]
50816
+ },
50817
+ {
50818
+ id: "detection-blind",
50819
+ family: "device-events",
50820
+ label: "Detecting nothing",
50821
+ kinds: ["detection-blind"]
50822
+ },
50823
+ {
50824
+ id: "nodes",
50825
+ family: "system",
50826
+ label: "Nodes",
50827
+ kinds: [
50828
+ "node-offline",
50829
+ "node-online",
50830
+ "node-inference-unavailable"
50831
+ ]
50832
+ },
50833
+ {
50834
+ id: "addons",
50835
+ family: "system",
50836
+ label: "Addons",
50837
+ kinds: [
50838
+ "addon-crash-loop",
50839
+ "addon-update-available",
50840
+ "addon-updated"
50841
+ ]
50842
+ },
50843
+ {
50844
+ id: "updates",
50845
+ family: "system",
50846
+ label: "Server & container updates",
50847
+ kinds: [
50848
+ "server-update-available",
50849
+ "server-updated",
50850
+ "wrapper-update-available"
50851
+ ]
50852
+ },
50853
+ {
50854
+ id: "backups-exports",
50855
+ family: "system",
50856
+ label: "Backups & exports",
50857
+ kinds: ["backup-completed", "export-completed"]
50858
+ },
50859
+ {
50860
+ id: "alarm",
50861
+ family: "alarm",
50862
+ label: "Alarm",
50863
+ kinds: NC_ALARM_SYSTEM_EVENT_KINDS
50864
+ }
50865
+ ];
50866
+ function systemEventKindsOfFamily(family) {
50867
+ return NC_SYSTEM_EVENT_KIND_GROUP_SPECS.filter((g) => g.family === family).flatMap((g) => g.kinds);
50868
+ }
50869
+ /**
50870
+ * Why the hub refuses this condition on a new or updated rule. Empty = accepted.
50871
+ * Families are reported in `NC_SYSTEM_EVENT_FAMILIES` order, and filters in
50872
+ * `NC_SYSTEM_EVENT_CONDITION_FILTER_KEYS` order, so a refusal reads the same
50873
+ * every time.
50874
+ */
50875
+ function systemEventFamilyProblems(condition) {
50876
+ if (condition === void 0 || condition.kinds.length === 0) return [{ code: "no-kinds" }];
50877
+ const problems = [];
50878
+ const present = /* @__PURE__ */ new Set();
50879
+ for (const kind of condition.kinds) {
50880
+ const family = NC_SYSTEM_EVENT_FAMILY[kind];
50881
+ if (family === null) problems.push({
50882
+ code: "legacy-kind",
50883
+ kind
50884
+ });
50885
+ else present.add(family);
50886
+ }
50887
+ const families = NC_SYSTEM_EVENT_FAMILIES.filter((f) => present.has(f));
50888
+ if (families.length > 1) problems.push({
50889
+ code: "mixed-families",
50890
+ families
50891
+ });
50892
+ const [family] = families;
50893
+ if (families.length !== 1 || family === void 0) return problems;
50894
+ const allowed = NC_SYSTEM_EVENT_FAMILY_FILTERS[family];
50895
+ for (const filter of NC_SYSTEM_EVENT_CONDITION_FILTER_KEYS) if (condition[filter] !== void 0 && !allowed.includes(filter)) problems.push({
50896
+ code: "filter-outside-family",
50897
+ filter,
50898
+ family
50899
+ });
50900
+ return problems;
50901
+ }
50902
+ function describeSystemEventFamilyProblem(problem) {
50903
+ switch (problem.code) {
50904
+ case "no-kinds": return "a system-event rule needs at least one event kind";
50905
+ case "legacy-kind": return `'${problem.kind}' is a legacy kind and cannot be authored`;
50906
+ case "mixed-families": return `event kinds span ${problem.families.join(" + ")} — one rule per family`;
50907
+ case "filter-outside-family": return `filter '${problem.filter}' is not allowed on a ${problem.family} rule`;
50908
+ }
50909
+ }
50910
+ /** Every kind a `system-event` rule can derive — the three families and `mixed`. */
50911
+ var NC_SYSTEM_RULE_KINDS = [
50912
+ "device-events",
50913
+ "system",
50914
+ "alarm",
50915
+ "mixed"
50916
+ ];
50917
+ /** Is this a kind a `system-event` rule derives (any family, or `mixed`)? */
50918
+ function isSystemRuleKind(kind) {
50919
+ return NC_SYSTEM_RULE_KINDS.some((k) => k === kind);
50920
+ }
50921
+ /** The family a kind authors, or undefined (a camera kind, or `mixed`). */
50922
+ function systemFamilyOfKind(kind) {
50923
+ return isSystemEventFamily(kind) ? kind : void 0;
50924
+ }
50925
+ /** The delivery a system rule rides — named once, compared everywhere. */
50926
+ var NC_SYSTEM_DELIVERY = "system-event";
50927
+ /**
50928
+ * Is this a SYSTEM rule — one about the installation rather than about anything
50929
+ * a camera saw? Takes a plain `string` so a rule carrying a delivery this build
50930
+ * has never heard of still gets an answer instead of a type error.
50931
+ */
50932
+ function isSystemDelivery(delivery) {
50933
+ return delivery === NC_SYSTEM_DELIVERY;
50934
+ }
50482
50935
  NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
50483
50936
  var WEEKDAY_TO_DAY = {
50484
50937
  Sun: 0,
@@ -50540,6 +50993,66 @@ function isScheduleActive(schedule, atMs) {
50540
50993
  }
50541
50994
  return schedule.invert === true ? !inside : inside;
50542
50995
  }
50996
+ var ARMED_WORD_PREFIX = "armed_";
50997
+ var ALARM_PANEL_CAP = "alarm-panel";
50998
+ var ALARM_PANEL_TRIGGER_METHOD = "trigger";
50999
+ /**
51000
+ * A rule belongs to the alarm when its `deviceState` gate names ANY device's
51001
+ * `armed_*` word, or an ENABLED `onTrigger` sequence pulls the alarm panel's
51002
+ * trigger (D630).
51003
+ */
51004
+ function ruleBelongsToAlarm(rule) {
51005
+ if ((rule.conditions.deviceState?.states ?? []).some((s) => s.trim().toLowerCase().startsWith(ARMED_WORD_PREFIX))) return true;
51006
+ return (rule.onTrigger ?? []).some((sequence) => sequence.enabled && sequence.actions.some((step) => step.kind === "cap" && step.cap === ALARM_PANEL_CAP && step.method === ALARM_PANEL_TRIGGER_METHOD));
51007
+ }
51008
+ /**
51009
+ * WHICH WAY A BOOLEAN SENSOR MOVED — read off the one slice a sensor event
51010
+ * persists (D640 "a sensor rule fires on the raise, the clear, or both").
51011
+ *
51012
+ * A device-event rule over a flood sensor notified on BOTH edges: water
51013
+ * detected, and back to dry. `NcConditions.sensorTransition` lets the rule
51014
+ * name one edge; this file answers, for one `SensorEvent`, which edge it is.
51015
+ *
51016
+ * NOT A SECOND TABLE. The "which boolean of this cap counts as HIGH" question
51017
+ * already has one answer, `SOURCE_CAP_ACTIVE_FIELD`
51018
+ * (`catalogs/sensor-active-state.ts`, the doorbell's and the recorder's edge
51019
+ * table), and a sensor event names its kind, not its cap. So the table here is
51020
+ * DERIVED: event kind → cap (`EVENT_KIND_BY_CAP`) → that cap's active field.
51021
+ * Only kinds whose taxonomy category is `sensor` take part — a switch has an
51022
+ * `on` boolean too, but "it triggers / it clears" is not a sentence about a
51023
+ * light, and offering it there would be a knob with a misleading label.
51024
+ * `presence` is a WORD (`home` / `not_home` / a zone), not a boolean, and is
51025
+ * absent from the source table, so it is absent here.
51026
+ *
51027
+ * `undefined` = never guessed: a kind with no raise (a doorbell press, a
51028
+ * button, a cover), or a slice whose field is missing or not a boolean. The
51029
+ * engine then does NOT filter — a flood alert must not go silent because one
51030
+ * read came back unreadable (the same stance as the alarm's `sensorEdgeOf`).
51031
+ *
51032
+ * Pure, RN-safe: the viewer imports the support rule from here.
51033
+ */
51034
+ /** Event kind → the boolean field of its cap slice that means "raised". */
51035
+ var NC_SENSOR_RAISED_FIELD_BY_KIND = Object.freeze(Object.fromEntries(Object.entries(EVENT_KIND_BY_CAP).flatMap(([capName, descriptor]) => {
51036
+ const field = SOURCE_CAP_ACTIVE_FIELD[capName];
51037
+ if (field === void 0 || descriptor.category !== "sensor") return [];
51038
+ return [[descriptor.kind, field]];
51039
+ })));
51040
+ /** The sensor kinds `sensorTransition` means something for. */
51041
+ var NC_SENSOR_TRANSITION_KINDS = Object.freeze(Object.keys(NC_SENSOR_RAISED_FIELD_BY_KIND));
51042
+ function normaliseKind(kind) {
51043
+ return kind.trim().toLowerCase();
51044
+ }
51045
+ /**
51046
+ * true = the sensor is raised (water, smoke, open, tampered…), false = it
51047
+ * cleared, undefined = this kind has no raise or the slice cannot say.
51048
+ */
51049
+ function sensorRaisedOf(kind, value) {
51050
+ if (value === null) return void 0;
51051
+ const field = NC_SENSOR_RAISED_FIELD_BY_KIND[normaliseKind(kind)];
51052
+ if (field === void 0) return void 0;
51053
+ const raw = Object.entries(value).find(([key]) => key === field)?.[1];
51054
+ return typeof raw === "boolean" ? raw : void 0;
51055
+ }
50543
51056
  var RULE_BODY_ONLY = ["body"];
50544
51057
  var RULE_TEXT = ["title", "body"];
50545
51058
  var BATTERY = ["device-battery-low", "device-battery-normal"];
@@ -51277,10 +51790,38 @@ var CAPTION_VARS = {
51277
51790
  function onAxis(declared, asked) {
51278
51791
  return declared === void 0 || asked === void 0 || declared.includes(asked);
51279
51792
  }
51280
- function onSystemAxis(d, ctx) {
51281
- if (ctx.kind !== "system" || d.systemEventKinds === void 0) return true;
51793
+ /**
51794
+ * Does a descriptor declared for `declared` kinds have a value for a rule of
51795
+ * `kind`?
51796
+ *
51797
+ * `system` on the WIRE stands for every system rule kind (D637): the served
51798
+ * catalog keeps the five pre-D637 tokens so installed viewers still parse it
51799
+ * (`NcTemplateVarKindSchema`), and the family split lives here, in the match.
51800
+ * Exported so the admin's local interpreter of the served catalog asks the
51801
+ * same question instead of restating it.
51802
+ */
51803
+ function templateVarKindApplies(declared, kind) {
51804
+ if (declared === void 0 || kind === void 0) return true;
51805
+ if (declared.some((k) => k === kind)) return true;
51806
+ return isSystemRuleKind(kind) && declared.includes("system");
51807
+ }
51808
+ /**
51809
+ * Is a descriptor that names `systemEventKinds` on the event-kind axis of a
51810
+ * system rule? Read only for a system rule kind; any other kind ignores it.
51811
+ *
51812
+ * Event kinds chosen: the descriptor must speak about one of them. None chosen
51813
+ * yet: a FAMILY kind watches its own family's event kinds (a device-events rule
51814
+ * is never offered the alarm's `{{mode}}`), and `mixed` watches all of them.
51815
+ */
51816
+ function templateVarSystemEventApplies(d, ctx) {
51817
+ if (!isSystemRuleKind(ctx.kind) || d.systemEventKinds === void 0) return true;
51818
+ const declared = d.systemEventKinds;
51282
51819
  const asked = ctx.systemEventKinds ?? [];
51283
- return asked.length === 0 || asked.some((k) => d.systemEventKinds?.includes(k) === true);
51820
+ if (asked.length > 0) return asked.some((k) => declared.includes(k));
51821
+ const family = ctx.kind === void 0 ? void 0 : systemFamilyOfKind(ctx.kind);
51822
+ if (family === void 0) return true;
51823
+ const own = systemEventKindsOfFamily(family);
51824
+ return declared.some((k) => own.includes(k));
51284
51825
  }
51285
51826
  /**
51286
51827
  * The variables that have a value in `ctx`, in catalog order. Pure.
@@ -51294,27 +51835,13 @@ function templateVarsFor(ctx) {
51294
51835
  const allowed = CAPTION_VARS[ctx.field];
51295
51836
  return NC_TEMPLATE_VARS.filter((d) => d.families.includes(ctx.family) && allowed.includes(d.name) && d.dynamic === void 0);
51296
51837
  }
51297
- return NC_TEMPLATE_VARS.filter((d) => d.families.includes(ctx.family) && onAxis(d.fields, ctx.field) && onAxis(d.kinds, ctx.kind) && onAxis(d.deliveries, ctx.delivery) && onSystemAxis(d, ctx));
51838
+ return NC_TEMPLATE_VARS.filter((d) => d.families.includes(ctx.family) && onAxis(d.fields, ctx.field) && templateVarKindApplies(d.kinds, ctx.kind) && onAxis(d.deliveries, ctx.delivery) && templateVarSystemEventApplies(d, ctx));
51298
51839
  }
51299
51840
  /** True when `name` is supplied in `ctx`, dynamic families (`count_<class>`) included. */
51300
51841
  function isKnownTemplateVar(name, ctx) {
51301
51842
  return templateVarsFor(ctx).some((d) => d.dynamic !== void 0 ? name.startsWith(d.dynamic.prefix) && name.length > d.dynamic.prefix.length : d.name === name);
51302
51843
  }
51303
51844
  /**
51304
- * Does `filter` say anything about `kind`?
51305
- *
51306
- * `false` means the filter is not part of this kind's vocabulary: the engine
51307
- * ignores it and an editor hides its input. It never means "excluded".
51308
- */
51309
- function systemEventFilterApplies(kind, filter) {
51310
- switch (filter) {
51311
- case "deviceIds": return kind.startsWith("device-") || kind.startsWith("stream-") || kind === "detection-blind" || kind === "alarm-triggered" || kind === "export-completed";
51312
- case "deviceTypes": return kind.startsWith("device-") || kind === "detection-blind";
51313
- case "nodeIds": return kind.startsWith("node-") || kind === "addon-crash-loop" || kind === "addon-update-available" || kind === "addon-updated" || kind === "server-update-available" || kind === "wrapper-update-available" || kind === "server-updated";
51314
- case "packageNames": return kind.endsWith("update-available") || kind === "addon-updated" || kind === "server-updated";
51315
- }
51316
- }
51317
- /**
51318
51845
  * TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
51319
51846
  *
51320
51847
  * Spec: `docs/superpowers/specs/2026-07-24-nc-occupancy-timelapse-design.md`
@@ -52318,4 +52845,4 @@ function vectorDimFromBase64(encoded) {
52318
52845
  return Math.floor(Buffer.from(encoded, "base64").byteLength / 4);
52319
52846
  }
52320
52847
  //#endregion
52321
- export { RECORDING_SOURCE_CAMSTACK_ADDON as $, CamProfileSchema as $t, NC_SNOOZE_MAX_MINUTES as A, isScheduleActive as At, NcRuleUpdateInputSchema as B, readDeviceStateFrom as Bt, MAX_BIRTH_DECISION_RECORDS as C, faceGalleryCapability as Ct, NC_ALARM_SYSTEM_EVENT_KINDS as D, isEventOwnerType as Dt, MediaFileKindEnum as E, isDetectionMacroClass as Et, NcConditionDescriptorSchema as F, occupancyScope as Ft, NcSystemEventKindSchema as G, storageOccupancyCapability as Gt, NcSnoozeInputSchema as H, resolveLocationMode as Ht, NcRuleInputSchema as I, parseProcStatus as It, NcTemplatePreviewSchema as J, templateVarsFor as Jt, NcTaxonomySchema as K, subKindsOf as Kt, NcRulePatchSchema as L, pickClusterStepModels as Lt, NC_TEMPLATE_VARS as M, kebabToCamel as Mt, NcAlarmConfigSchema as N, mayWriteToLocation as Nt, NC_CONDITION_CATALOG as O, isKnownTemplateVar as Ot, NcAlarmSettingsPatchSchema as P, notificationRulesCapability as Pt, RECORDING_EXPORT_MAX_READ_BYTES as Q, BaseAddon as Qt, NcRuleSchema as R, pipelineAnalyticsCapability as Rt, MAX_ARCHIVED_DEBUG_NOTES as S, evictionPolicyOfLocation as St, MOTION_CLOSE_AFTER_MS as T, hfModelUrl as Tt, NcSnoozeSchema as U, resolvePoolMemoryPolicy as Ut, NcScheduleSchema as V, readTimelapseGeneratedAt as Vt, NcSnoozeSuppressedSchema as W, sceneMonitorCapability as Wt, OpsLogEntrySchema as X, zoneAnalyticsCapability as Xt, NcTemplateVarDescriptorSchema as Y, vectorDimFromBase64 as Yt, PoolMemoryWatchdog as Z, errMsg as Zt, FIRST_LEVEL_MACRO_CLASSES as _, string as _n, cosineSimilarity as _t, BirthDecisionRecordSchema as a, isDeviceScopedCap as an, SceneMonitorSchema as at, LabelAttributionSchema as b, encodeVectorBase64 as bt, CoverStateSchema as c, _enum as cn, TimelapseRulePatchSchema as ct, DEFAULT_TIMELAPSE_PREVIEW_TEXT as d, discriminatedUnion as dn, addonWidgetsSourceCapability as dt, DeviceType as en, RetrainStatusSchema as et, DETECTION_MACRO_CLASSES as f, literal as fn, alarmPanelCapability as ft, EVENT_OWNER_TYPES as g, record as gn, buildEventKindDescriptor as gt, EVENT_KIND_BY_CAP as h, partialRecord as hn, audioModeOf as ht, BaseDevice as i, hydrateSchema as in, SCENE_DIVERGED as it, NC_TAXONOMY as j, isSourceCap as jt, NC_DEFAULT_SNOOZE_MINUTES as k, isMediaOwnerType as kt, DEFAULT_EVENT_COLOR as l, array as ln, TimelapseRuleSchema as lt, DeclaredDevices as m, object as mn, audioMetricsCapability as mt, AlarmArmModeSchema as n, customAction as nn, SCENE_DEFAULT_ANCHOR_THRESHOLD as nt, CLUSTER_MODEL_SCOPED_STEPS as o, nodePin as on, TIMELAPSE_DENSE_FLOOR_SEC as ot, DETECTION_PIPELINE_CAP_NAME as p, number as pn, assertTimelapseCadences as pt, NcTemplatePreviewInputSchema as q, systemEventFilterApplies as qt, ArchivedDebugNoteSchema as r, defineCustomActions as rn, SCENE_DEFAULT_UNCOVERED_POLICY as rt, COCO_TO_MACRO as s, sleep as sn, TimelapseRuleInputSchema as st, AUDIO_MACRO_LABELS as t, createEvent as tn, SCENE_CONFIRM_DEFAULT_TIMEOUT_MS as tt, DEFAULT_FIRST_SIGHTING_FRESHNESS_MS as u, boolean as un, TrackSourceSchema as ut, FULL_IMAGE_BBOX as v, unknown as vn, deriveRecordingMode as vt, MAX_BIRTH_LATENCY_PROXY_MS as w, failureContributionCapability as wt, LockStateSchema as x, evaluateSensorEdge as xt, FailureCounters as y, EventCategory as yn, embeddingEncoderCapability as yt, NcRuleTargetSchema as z, plateGalleryCapability as zt };
52848
+ export { PoolMemoryWatchdog as $, systemEventFamilyProblems as $t, NC_SENSOR_TRANSITION_KINDS as A, isEventOwnerType as At, NcRuleSchema as B, parseProcStatus as Bt, MAX_BIRTH_DECISION_RECORDS as C, partialRecord as Cn, encodeVectorBase64 as Ct, NC_ALARM_SYSTEM_EVENT_KINDS as D, EventCategory as Dn, failureContributionCapability as Dt, MediaFileKindEnum as E, unknown as En, faceGalleryCapability as Et, NcAlarmSettingsPatchSchema as F, isSystemDelivery as Ft, NcSnoozeSchema as G, readTimelapseGeneratedAt as Gt, NcRuleUpdateInputSchema as H, pipelineAnalyticsCapability as Ht, NcConditionDescriptorSchema as I, kebabToCamel as It, NcTaxonomySchema as J, ruleBelongsToAlarm as Jt, NcSnoozeSuppressedSchema as K, resolveLocationMode as Kt, NcConditionsSchema as L, mayWriteToLocation as Lt, NC_TAXONOMY as M, isMediaOwnerType as Mt, NC_TEMPLATE_VARS as N, isScheduleActive as Nt, NC_CONDITION_CATALOG as O, hfModelUrl as Ot, NcAlarmConfigSchema as P, isSourceCap as Pt, OpsLogEntrySchema as Q, subKindsOf as Qt, NcRuleInputSchema as R, notificationRulesCapability as Rt, MAX_ARCHIVED_DEBUG_NOTES as S, object as Sn, embeddingEncoderCapability as St, MOTION_CLOSE_AFTER_MS as T, string as Tn, evictionPolicyOfLocation as Tt, NcScheduleSchema as U, plateGalleryCapability as Ut, NcRuleTargetSchema as V, pickClusterStepModels as Vt, NcSnoozeInputSchema as W, readDeviceStateFrom as Wt, NcTemplatePreviewSchema as X, sensorRaisedOf as Xt, NcTemplatePreviewInputSchema as Y, sceneMonitorCapability as Yt, NcTemplateVarDescriptorSchema as Z, storageOccupancyCapability as Zt, FIRST_LEVEL_MACRO_CLASSES as _, array as _n, audioModeOf as _t, BirthDecisionRecordSchema as a, canonicalHash as an, SCENE_DEFAULT_UNCOVERED_POLICY as at, LabelAttributionSchema as b, literal as bn, deriveRecordingMode as bt, CoverStateSchema as c, DeviceType as cn, TIMELAPSE_DENSE_FLOOR_SEC as ct, DEFAULT_TIMELAPSE_PREVIEW_TEXT as d, defineCustomActions as dn, TimelapseRuleSchema as dt, systemEventFilterApplies as en, RECORDING_EXPORT_MAX_READ_BYTES as et, DETECTION_MACRO_CLASSES as f, hydrateSchema as fn, TrackSourceSchema as ft, EVENT_OWNER_TYPES as g, _enum as gn, audioMetricsCapability as gt, EVENT_KIND_BY_CAP as h, sleep as hn, assertTimelapseCadences as ht, BaseDevice as i, errMsg as in, SCENE_DEFAULT_ANCHOR_THRESHOLD as it, NC_SNOOZE_MAX_MINUTES as j, isKnownTemplateVar as jt, NC_DEFAULT_SNOOZE_MINUTES as k, isDetectionMacroClass as kt, DEFAULT_EVENT_COLOR as l, createEvent as ln, TimelapseRuleInputSchema as lt, DeclaredDevices as m, nodePin as mn, alarmPanelCapability as mt, AlarmArmModeSchema as n, vectorDimFromBase64 as nn, RetrainStatusSchema as nt, CLUSTER_MODEL_SCOPED_STEPS as o, BaseAddon as on, SCENE_DIVERGED as ot, DETECTION_PIPELINE_CAP_NAME as p, isDeviceScopedCap as pn, addonWidgetsSourceCapability as pt, NcSystemEventKindSchema as q, resolvePoolMemoryPolicy as qt, ArchivedDebugNoteSchema as r, zoneAnalyticsCapability as rn, SCENE_CONFIRM_DEFAULT_TIMEOUT_MS as rt, COCO_TO_MACRO as s, CamProfileSchema as sn, SceneMonitorSchema as st, AUDIO_MACRO_LABELS as t, templateVarsFor as tn, RECORDING_SOURCE_CAMSTACK_ADDON as tt, DEFAULT_FIRST_SIGHTING_FRESHNESS_MS as u, customAction as un, TimelapseRulePatchSchema as ut, FULL_IMAGE_BBOX as v, boolean as vn, buildEventKindDescriptor as vt, MAX_BIRTH_LATENCY_PROXY_MS as w, record as wn, evaluateSensorEdge as wt, LockStateSchema as x, number as xn, describeSystemEventFamilyProblem as xt, FailureCounters as y, discriminatedUnion as yn, cosineSimilarity as yt, NcRulePatchSchema as z, occupancyScope as zt };