@camstack/addon-post-analysis 1.2.658 → 1.2.659

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.2.659] - 2026-11-01
11
+
12
+ ### Changed
13
+
14
+ - Notification rules fire once per appliance start/finish (running-state flip), not on every status refresh
15
+
10
16
  ## [1.2.658] - 2026-11-01
11
17
 
12
18
  ### Changed
@@ -11832,7 +11832,7 @@ function sleep(ms) {
11832
11832
  return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
11833
11833
  }
11834
11834
  //#endregion
11835
- //#region ../types/dist/composition-BBzVf2xd.mjs
11835
+ //#region ../types/dist/composition-BiKWlUCc.mjs
11836
11836
  /**
11837
11837
  * Deterministic SHA-256 hash of an arbitrary serialisable value. The
11838
11838
  * canonical form sorts object keys alphabetically at every depth so two
@@ -12925,7 +12925,15 @@ var HelperSpecSchema = discriminatedUnion("kind", [
12925
12925
  thresholdWatts: number().positive(),
12926
12926
  startDwellMs: number().int().nonnegative(),
12927
12927
  stopDwellMs: number().int().nonnegative(),
12928
- member: HelperMemberSchema
12928
+ member: HelperMemberSchema,
12929
+ /**
12930
+ * The plug that powers the appliance (`switch.on`). Optional: when set, the
12931
+ * composition carries a `power-source` feature, so the hub can cut and restore
12932
+ * that plug (power-source link of a NEW-target composition).
12933
+ */
12934
+ powerSwitch: HelperMemberSchema.optional(),
12935
+ /** How long a forced restart keeps the plug off; the cap's default when unset. */
12936
+ offSeconds: number().optional()
12929
12937
  }),
12930
12938
  object({
12931
12939
  kind: literal("statistic"),
@@ -47717,6 +47725,117 @@ function actuator(input) {
47717
47725
  };
47718
47726
  }
47719
47727
  new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
47728
+ var PowerSourceRefusalReasonSchema = _enum([
47729
+ "no-power-source",
47730
+ "switch-missing",
47731
+ "switch-offline",
47732
+ "switch-unknown",
47733
+ "restart-in-progress",
47734
+ "switch-call-failed"
47735
+ ]);
47736
+ var PowerSourceActionResultSchema = discriminatedUnion("accepted", [object({ accepted: literal(true) }), object({
47737
+ accepted: literal(false),
47738
+ reason: PowerSourceRefusalReasonSchema,
47739
+ /** One line for the operator, naming the switch. */
47740
+ message: string()
47741
+ })]);
47742
+ var PowerSourceInfoSchema = object({
47743
+ /** False when the device has no power source linked; the rest is then empty. */
47744
+ linked: boolean(),
47745
+ switchDeviceId: number().nullable(),
47746
+ switchName: string().nullable(),
47747
+ /** The switch's on/off state, or null when it is unknown. Never false for unknown (D393). */
47748
+ switchOn: boolean().nullable(),
47749
+ switchOnline: boolean().nullable(),
47750
+ restartInProgress: boolean(),
47751
+ offSeconds: number().int()
47752
+ });
47753
+ /** The composed slice: the switch state the link mirrors, plus the stored off time. */
47754
+ var PowerSourceStateSchema = object({
47755
+ /** Null while the switch has not reported: unknown is never `false` (D393). */
47756
+ switchOn: boolean().nullable(),
47757
+ offSeconds: number().int(),
47758
+ lastFetchedAt: number()
47759
+ });
47760
+ var POWER_SOURCE_DEVICE_TYPES = [
47761
+ DeviceType.Gateway,
47762
+ DeviceType.Hub,
47763
+ DeviceType.Camera,
47764
+ DeviceType.Sensor,
47765
+ DeviceType.MediaPlayer,
47766
+ DeviceType.Vacuum,
47767
+ DeviceType.Generic,
47768
+ DeviceType.Washer,
47769
+ DeviceType.Dryer,
47770
+ DeviceType.Dishwasher,
47771
+ DeviceType.PetFountain,
47772
+ DeviceType.Fan,
47773
+ DeviceType.Humidifier,
47774
+ DeviceType.Climate,
47775
+ DeviceType.WaterHeater
47776
+ ];
47777
+ var powerSourceCustomize = {
47778
+ version: 1,
47779
+ targets: [{
47780
+ id: "switch",
47781
+ cardinality: "scalar",
47782
+ vocabulary: {
47783
+ cap: "power-source",
47784
+ stateField: "switchOn"
47785
+ },
47786
+ deviceTypes: POWER_SOURCE_DEVICE_TYPES,
47787
+ apply: "add",
47788
+ path: "switchOn",
47789
+ sources: [{
47790
+ kind: "switch",
47791
+ transforms: [{ kind: "identity" }]
47792
+ }],
47793
+ companions: [{
47794
+ kind: "constant",
47795
+ path: "offSeconds",
47796
+ value: 10,
47797
+ when: "add"
47798
+ }, {
47799
+ kind: "clock",
47800
+ path: "lastFetchedAt",
47801
+ when: "always"
47802
+ }],
47803
+ sourceReport: { status: "assignment-status" }
47804
+ }]
47805
+ };
47806
+ var deviceInput$1 = object({ deviceId: number().int().nonnegative() });
47807
+ var powerSourceCapability = {
47808
+ name: "power-source",
47809
+ scope: "device",
47810
+ mode: "singleton",
47811
+ deviceTypes: POWER_SOURCE_DEVICE_TYPES,
47812
+ methods: {
47813
+ getStatus: systemMethod(deviceInput$1, PowerSourceInfoSchema, { auth: "admin" }),
47814
+ powerOn: systemMethod(deviceInput$1, PowerSourceActionResultSchema, {
47815
+ kind: "mutation",
47816
+ auth: "admin"
47817
+ }),
47818
+ powerOff: systemMethod(deviceInput$1, PowerSourceActionResultSchema, {
47819
+ kind: "mutation",
47820
+ auth: "admin"
47821
+ }),
47822
+ forceRestart: systemMethod(deviceInput$1, PowerSourceActionResultSchema, {
47823
+ kind: "mutation",
47824
+ auth: "admin"
47825
+ })
47826
+ },
47827
+ runtimeState: PowerSourceStateSchema,
47828
+ customize: powerSourceCustomize,
47829
+ /**
47830
+ * Runtime-state durability: **session** — mirrored from the linked switch on
47831
+ * its next report; a restored value would outlive the reading it names.
47832
+ *
47833
+ * See `RuntimeStateDurability`. Enforced by
47834
+ * `scripts/check-runtime-state-durability.ts`.
47835
+ */
47836
+ durability: "session",
47837
+ history: "none"
47838
+ };
47720
47839
  DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
47721
47840
  DeviceType.Camera;
47722
47841
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
@@ -53755,7 +53874,8 @@ var PALETTE_ENTRY_IDS = [
53755
53874
  "switch",
53756
53875
  "siren",
53757
53876
  "button",
53758
- "doorbell"
53877
+ "doorbell",
53878
+ "appliance-cycle"
53759
53879
  ];
53760
53880
  var AUDIO_ENTRY_ID = "audio";
53761
53881
  /** Six rungs, quiet → loud. The opaque end is the entry's hex. */
@@ -53826,7 +53946,8 @@ var CAMSTACK_HEX = {
53826
53946
  switch: "#7a812a",
53827
53947
  siren: "#ac5d7f",
53828
53948
  button: "#b276cd",
53829
- doorbell: "#0087ab"
53949
+ doorbell: "#0087ab",
53950
+ "appliance-cycle": "#2a8c8c"
53830
53951
  };
53831
53952
  var CAMSTACK_FALLBACK = [
53832
53953
  "#b34dc7",
@@ -53891,7 +54012,8 @@ var HIGH_CONTRAST_HEX = {
53891
54012
  switch: "#d05259",
53892
54013
  siren: "#cd67b3",
53893
54014
  button: "#c9746a",
53894
- doorbell: "#338eeb"
54015
+ doorbell: "#338eeb",
54016
+ "appliance-cycle": "#00848a"
53895
54017
  };
53896
54018
  var HIGH_CONTRAST_FALLBACK = [
53897
54019
  "#817f3b",
@@ -53956,7 +54078,8 @@ var OKABE_ITO_HEX = {
53956
54078
  switch: "#ad2c4e",
53957
54079
  siren: "#348e08",
53958
54080
  button: "#d27303",
53959
- doorbell: "#55770f"
54081
+ doorbell: "#55770f",
54082
+ "appliance-cycle": "#00737d"
53960
54083
  };
53961
54084
  var OKABE_ITO_FALLBACK = [
53962
54085
  "#9a3784",
@@ -54166,6 +54289,7 @@ sub("switch", "control", "control", "switch", "Switch");
54166
54289
  sub("siren", "control", "control", "siren", "Siren");
54167
54290
  sub("button", "control", "control", "button", "Button");
54168
54291
  sub("doorbell", "control", "control", "doorbell", "Doorbell");
54292
+ sub("appliance-cycle", "control", "control", "switch", "Appliance cycle");
54169
54293
  for (const l of AUDIO_MACRO_LABELS) {
54170
54294
  const kind = `audio-${l.id}`;
54171
54295
  if (entries.has(kind)) continue;
@@ -64596,7 +64720,8 @@ var CAP_TO_KIND = {
64596
64720
  cover: "cover",
64597
64721
  switch: "switch",
64598
64722
  button: "button",
64599
- doorbell: "doorbell"
64723
+ doorbell: "doorbell",
64724
+ "running-state": "appliance-cycle"
64600
64725
  };
64601
64726
  function buildDescriptor(capName, kind) {
64602
64727
  const t = EVENT_TAXONOMY[kind];
@@ -69052,19 +69177,19 @@ var RemoteSetConfigResultSchema = discriminatedUnion("status", [object({ status:
69052
69177
  reason: _enum(["unknown-template", "not-a-media-player"]),
69053
69178
  detail: string()
69054
69179
  })]);
69055
- var deviceInput$1 = object({ deviceId: number().int().nonnegative() });
69180
+ var deviceInput = object({ deviceId: number().int().nonnegative() });
69056
69181
  DeviceType.MediaPlayer;
69057
- method(deviceInput$1, RemoteConfigSchema, { auth: "admin" }), method(deviceInput$1.extend({ config: RemoteConfigSchema }), RemoteSetConfigResultSchema, {
69182
+ method(deviceInput, RemoteConfigSchema, { auth: "admin" }), method(deviceInput.extend({ config: RemoteConfigSchema }), RemoteSetConfigResultSchema, {
69058
69183
  kind: "mutation",
69059
69184
  auth: "admin"
69060
- }), method(deviceInput$1, RemoteCommandListSchema, { auth: "protected" }), method(deviceInput$1.extend({
69185
+ }), method(deviceInput, RemoteCommandListSchema, { auth: "protected" }), method(deviceInput.extend({
69061
69186
  role: RemoteRoleSchema,
69062
69187
  /** Sends in a row (volume steps). */
69063
69188
  repeat: number().int().min(1).max(50).default(1)
69064
69189
  }), RemoteSendResultSchema, {
69065
69190
  kind: "mutation",
69066
69191
  auth: "protected"
69067
- }), method(deviceInput$1.extend({
69192
+ }), method(deviceInput.extend({
69068
69193
  command: RemoteMediaCommandSchema,
69069
69194
  muted: boolean().optional(),
69070
69195
  source: string().optional(),
@@ -73509,117 +73634,6 @@ var lockControlCapability = {
73509
73634
  * whether persisting is worth a SQLite commit. */
73510
73635
  volatileStateFields: ["lastChangedAt"]
73511
73636
  };
73512
- var PowerSourceRefusalReasonSchema = _enum([
73513
- "no-power-source",
73514
- "switch-missing",
73515
- "switch-offline",
73516
- "switch-unknown",
73517
- "restart-in-progress",
73518
- "switch-call-failed"
73519
- ]);
73520
- var PowerSourceActionResultSchema = discriminatedUnion("accepted", [object({ accepted: literal(true) }), object({
73521
- accepted: literal(false),
73522
- reason: PowerSourceRefusalReasonSchema,
73523
- /** One line for the operator, naming the switch. */
73524
- message: string()
73525
- })]);
73526
- var PowerSourceInfoSchema = object({
73527
- /** False when the device has no power source linked; the rest is then empty. */
73528
- linked: boolean(),
73529
- switchDeviceId: number().nullable(),
73530
- switchName: string().nullable(),
73531
- /** The switch's on/off state, or null when it is unknown. Never false for unknown (D393). */
73532
- switchOn: boolean().nullable(),
73533
- switchOnline: boolean().nullable(),
73534
- restartInProgress: boolean(),
73535
- offSeconds: number().int()
73536
- });
73537
- /** The composed slice: the switch state the link mirrors, plus the stored off time. */
73538
- var PowerSourceStateSchema = object({
73539
- /** Null while the switch has not reported: unknown is never `false` (D393). */
73540
- switchOn: boolean().nullable(),
73541
- offSeconds: number().int(),
73542
- lastFetchedAt: number()
73543
- });
73544
- var POWER_SOURCE_DEVICE_TYPES = [
73545
- DeviceType.Gateway,
73546
- DeviceType.Hub,
73547
- DeviceType.Camera,
73548
- DeviceType.Sensor,
73549
- DeviceType.MediaPlayer,
73550
- DeviceType.Vacuum,
73551
- DeviceType.Generic,
73552
- DeviceType.Washer,
73553
- DeviceType.Dryer,
73554
- DeviceType.Dishwasher,
73555
- DeviceType.PetFountain,
73556
- DeviceType.Fan,
73557
- DeviceType.Humidifier,
73558
- DeviceType.Climate,
73559
- DeviceType.WaterHeater
73560
- ];
73561
- var powerSourceCustomize = {
73562
- version: 1,
73563
- targets: [{
73564
- id: "switch",
73565
- cardinality: "scalar",
73566
- vocabulary: {
73567
- cap: "power-source",
73568
- stateField: "switchOn"
73569
- },
73570
- deviceTypes: POWER_SOURCE_DEVICE_TYPES,
73571
- apply: "add",
73572
- path: "switchOn",
73573
- sources: [{
73574
- kind: "switch",
73575
- transforms: [{ kind: "identity" }]
73576
- }],
73577
- companions: [{
73578
- kind: "constant",
73579
- path: "offSeconds",
73580
- value: 10,
73581
- when: "add"
73582
- }, {
73583
- kind: "clock",
73584
- path: "lastFetchedAt",
73585
- when: "always"
73586
- }],
73587
- sourceReport: { status: "assignment-status" }
73588
- }]
73589
- };
73590
- var deviceInput = object({ deviceId: number().int().nonnegative() });
73591
- var powerSourceCapability = {
73592
- name: "power-source",
73593
- scope: "device",
73594
- mode: "singleton",
73595
- deviceTypes: POWER_SOURCE_DEVICE_TYPES,
73596
- methods: {
73597
- getStatus: systemMethod(deviceInput, PowerSourceInfoSchema, { auth: "admin" }),
73598
- powerOn: systemMethod(deviceInput, PowerSourceActionResultSchema, {
73599
- kind: "mutation",
73600
- auth: "admin"
73601
- }),
73602
- powerOff: systemMethod(deviceInput, PowerSourceActionResultSchema, {
73603
- kind: "mutation",
73604
- auth: "admin"
73605
- }),
73606
- forceRestart: systemMethod(deviceInput, PowerSourceActionResultSchema, {
73607
- kind: "mutation",
73608
- auth: "admin"
73609
- })
73610
- },
73611
- runtimeState: PowerSourceStateSchema,
73612
- customize: powerSourceCustomize,
73613
- /**
73614
- * Runtime-state durability: **session** — mirrored from the linked switch on
73615
- * its next report; a restored value would outlive the reading it names.
73616
- *
73617
- * See `RuntimeStateDurability`. Enforced by
73618
- * `scripts/check-runtime-state-durability.ts`.
73619
- */
73620
- durability: "session",
73621
- history: "none"
73622
- };
73623
73637
  /**
73624
73638
  * A monotonic total between resets (D944). Energy uses `power-meter.energy`
73625
73639
  * so dashboards keep one series; every other instantaneous reading lands here.
@@ -77221,6 +77235,10 @@ var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
77221
77235
  /** Generic Customize target for the running boolean (D936). */
77222
77236
  var runningCustomize = {
77223
77237
  version: 1,
77238
+ overridable: [{
77239
+ path: "running",
77240
+ by: "running"
77241
+ }],
77224
77242
  targets: [{
77225
77243
  id: "running",
77226
77244
  cardinality: "scalar",
@@ -77278,7 +77296,7 @@ var runningCustomize = {
77278
77296
  kind: "constant",
77279
77297
  path: "phase",
77280
77298
  value: null,
77281
- when: "always"
77299
+ when: "add"
77282
77300
  },
77283
77301
  {
77284
77302
  kind: "clock",
@@ -97392,7 +97410,8 @@ function isSystemDelivery(delivery) {
97392
97410
  * picker authors.
97393
97411
  *
97394
97412
  * Callers resolve the ids via `deviceManager.listDeviceIdsByCaps` (max 16
97395
- * names — `EVENTFUL_CAP_NAMES` is exactly 16) and must treat an unanswered
97413
+ * names per call — `EVENTFUL_CAP_NAMES` is longer than that, so ask through
97414
+ * {@link ruleDeviceCompatCapQueries}, which chunks it) and must treat an unanswered
97396
97415
  * read as "unknown", never as "no devices" (D315): this function only names
97397
97416
  * WHICH caps to ask for, not what to show while the answer is pending.
97398
97417
  */
@@ -97414,6 +97433,12 @@ function ruleDeviceCompatCapNames(kind) {
97414
97433
  * Named once, because a sensor rule's compatible set needs it (below).
97415
97434
  */
97416
97435
  var NC_CAMERA_SCOPE_CAP_NAME = "camera-streams";
97436
+ var MAX_CAPS_PER_QUERY = 16;
97437
+ function chunk(items, size) {
97438
+ const out = [];
97439
+ for (let i = 0; i < items.length; i += size) out.push(items.slice(i, i + size));
97440
+ return out;
97441
+ }
97417
97442
  /**
97418
97443
  * Every capability QUERY whose union is the set of devices a rule of this kind
97419
97444
  * may be SCOPED to (`conditions.devices`) — what the save-time guard and the
@@ -97421,7 +97446,7 @@ var NC_CAMERA_SCOPE_CAP_NAME = "camera-streams";
97421
97446
  * entry. `null` exactly where {@link ruleDeviceCompatCapNames} is `null`.
97422
97447
  *
97423
97448
  * Several queries rather than one list because `listDeviceIdsByCaps` takes at
97424
- * most 16 names and `EVENTFUL_CAP_NAMES` is already exactly 16.
97449
+ * most 16 names and `EVENTFUL_CAP_NAMES` is longer than that (chunked here).
97425
97450
  *
97426
97451
  * A `sensor` rule's set is the eventful devices PLUS every camera (fix round
97427
97452
  * 1, 2026-10-01): the engine matches a sensor rule scoped to a CAMERA — a
@@ -97432,7 +97457,8 @@ var NC_CAMERA_SCOPE_CAP_NAME = "camera-streams";
97432
97457
  function ruleDeviceCompatCapQueries(kind) {
97433
97458
  const primary = ruleDeviceCompatCapNames(kind);
97434
97459
  if (primary === null) return null;
97435
- return kind === "sensor" ? [primary, [NC_CAMERA_SCOPE_CAP_NAME]] : [primary];
97460
+ const chunks = chunk(primary, MAX_CAPS_PER_QUERY);
97461
+ return kind === "sensor" ? [...chunks, [NC_CAMERA_SCOPE_CAP_NAME]] : chunks;
97436
97462
  }
97437
97463
  /**
97438
97464
  * Which kind of rule is this?
@@ -98336,8 +98362,17 @@ function syncActiveAlarmProfileSettings(state, settings) {
98336
98362
  *
98337
98363
  * Pure, RN-safe: the viewer imports the support rule from here.
98338
98364
  */
98365
+ /**
98366
+ * Control caps that still have a raise and a clear an operator names: an
98367
+ * appliance cycle raises when it STARTS and clears when it FINISHES. Kept out
98368
+ * of `SOURCE_CAP_ACTIVE_FIELD` on purpose — that table also makes a device a
98369
+ * camera-sensor / recorder-trigger source, and a dishwasher is neither.
98370
+ */
98371
+ var CYCLE_RAISED_FIELD_BY_CAP = { "running-state": "running" };
98339
98372
  /** Event kind → the boolean field of its cap slice that means "raised". */
98340
98373
  var NC_SENSOR_RAISED_FIELD_BY_KIND = Object.freeze(Object.fromEntries(Object.entries(EVENT_KIND_BY_CAP).flatMap(([capName, descriptor]) => {
98374
+ const cycleField = CYCLE_RAISED_FIELD_BY_CAP[capName];
98375
+ if (cycleField !== void 0) return [[descriptor.kind, cycleField]];
98341
98376
  const field = SOURCE_CAP_ACTIVE_FIELD[capName];
98342
98377
  if (field === void 0 || descriptor.category !== "sensor") return [];
98343
98378
  return [[descriptor.kind, field]];
@@ -100077,6 +100112,7 @@ var EVENT_KIND_LABEL_KEYS = [
100077
100112
  "siren",
100078
100113
  "button",
100079
100114
  "doorbell",
100115
+ "appliance-cycle",
100080
100116
  "audio-speech",
100081
100117
  "audio-scream",
100082
100118
  "audio-crying",
@@ -100284,6 +100320,10 @@ var EVENT_KIND_LABELS = {
100284
100320
  en: "Doorbell",
100285
100321
  it: "Campanello"
100286
100322
  },
100323
+ "appliance-cycle": {
100324
+ en: "Appliance cycle",
100325
+ it: "Ciclo elettrodomestico"
100326
+ },
100287
100327
  "audio-speech": {
100288
100328
  en: "Speech",
100289
100329
  it: "Voce"
@@ -11863,7 +11863,7 @@ function sleep(ms) {
11863
11863
  return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
11864
11864
  }
11865
11865
  //#endregion
11866
- //#region ../types/dist/composition-BBzVf2xd.mjs
11866
+ //#region ../types/dist/composition-BiKWlUCc.mjs
11867
11867
  /**
11868
11868
  * Deterministic SHA-256 hash of an arbitrary serialisable value. The
11869
11869
  * canonical form sorts object keys alphabetically at every depth so two
@@ -12956,7 +12956,15 @@ var HelperSpecSchema = discriminatedUnion("kind", [
12956
12956
  thresholdWatts: number().positive(),
12957
12957
  startDwellMs: number().int().nonnegative(),
12958
12958
  stopDwellMs: number().int().nonnegative(),
12959
- member: HelperMemberSchema
12959
+ member: HelperMemberSchema,
12960
+ /**
12961
+ * The plug that powers the appliance (`switch.on`). Optional: when set, the
12962
+ * composition carries a `power-source` feature, so the hub can cut and restore
12963
+ * that plug (power-source link of a NEW-target composition).
12964
+ */
12965
+ powerSwitch: HelperMemberSchema.optional(),
12966
+ /** How long a forced restart keeps the plug off; the cap's default when unset. */
12967
+ offSeconds: number().optional()
12960
12968
  }),
12961
12969
  object({
12962
12970
  kind: literal("statistic"),
@@ -47748,6 +47756,117 @@ function actuator(input) {
47748
47756
  };
47749
47757
  }
47750
47758
  new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
47759
+ var PowerSourceRefusalReasonSchema = _enum([
47760
+ "no-power-source",
47761
+ "switch-missing",
47762
+ "switch-offline",
47763
+ "switch-unknown",
47764
+ "restart-in-progress",
47765
+ "switch-call-failed"
47766
+ ]);
47767
+ var PowerSourceActionResultSchema = discriminatedUnion("accepted", [object({ accepted: literal(true) }), object({
47768
+ accepted: literal(false),
47769
+ reason: PowerSourceRefusalReasonSchema,
47770
+ /** One line for the operator, naming the switch. */
47771
+ message: string()
47772
+ })]);
47773
+ var PowerSourceInfoSchema = object({
47774
+ /** False when the device has no power source linked; the rest is then empty. */
47775
+ linked: boolean(),
47776
+ switchDeviceId: number().nullable(),
47777
+ switchName: string().nullable(),
47778
+ /** The switch's on/off state, or null when it is unknown. Never false for unknown (D393). */
47779
+ switchOn: boolean().nullable(),
47780
+ switchOnline: boolean().nullable(),
47781
+ restartInProgress: boolean(),
47782
+ offSeconds: number().int()
47783
+ });
47784
+ /** The composed slice: the switch state the link mirrors, plus the stored off time. */
47785
+ var PowerSourceStateSchema = object({
47786
+ /** Null while the switch has not reported: unknown is never `false` (D393). */
47787
+ switchOn: boolean().nullable(),
47788
+ offSeconds: number().int(),
47789
+ lastFetchedAt: number()
47790
+ });
47791
+ var POWER_SOURCE_DEVICE_TYPES = [
47792
+ DeviceType.Gateway,
47793
+ DeviceType.Hub,
47794
+ DeviceType.Camera,
47795
+ DeviceType.Sensor,
47796
+ DeviceType.MediaPlayer,
47797
+ DeviceType.Vacuum,
47798
+ DeviceType.Generic,
47799
+ DeviceType.Washer,
47800
+ DeviceType.Dryer,
47801
+ DeviceType.Dishwasher,
47802
+ DeviceType.PetFountain,
47803
+ DeviceType.Fan,
47804
+ DeviceType.Humidifier,
47805
+ DeviceType.Climate,
47806
+ DeviceType.WaterHeater
47807
+ ];
47808
+ var powerSourceCustomize = {
47809
+ version: 1,
47810
+ targets: [{
47811
+ id: "switch",
47812
+ cardinality: "scalar",
47813
+ vocabulary: {
47814
+ cap: "power-source",
47815
+ stateField: "switchOn"
47816
+ },
47817
+ deviceTypes: POWER_SOURCE_DEVICE_TYPES,
47818
+ apply: "add",
47819
+ path: "switchOn",
47820
+ sources: [{
47821
+ kind: "switch",
47822
+ transforms: [{ kind: "identity" }]
47823
+ }],
47824
+ companions: [{
47825
+ kind: "constant",
47826
+ path: "offSeconds",
47827
+ value: 10,
47828
+ when: "add"
47829
+ }, {
47830
+ kind: "clock",
47831
+ path: "lastFetchedAt",
47832
+ when: "always"
47833
+ }],
47834
+ sourceReport: { status: "assignment-status" }
47835
+ }]
47836
+ };
47837
+ var deviceInput$1 = object({ deviceId: number().int().nonnegative() });
47838
+ var powerSourceCapability = {
47839
+ name: "power-source",
47840
+ scope: "device",
47841
+ mode: "singleton",
47842
+ deviceTypes: POWER_SOURCE_DEVICE_TYPES,
47843
+ methods: {
47844
+ getStatus: systemMethod(deviceInput$1, PowerSourceInfoSchema, { auth: "admin" }),
47845
+ powerOn: systemMethod(deviceInput$1, PowerSourceActionResultSchema, {
47846
+ kind: "mutation",
47847
+ auth: "admin"
47848
+ }),
47849
+ powerOff: systemMethod(deviceInput$1, PowerSourceActionResultSchema, {
47850
+ kind: "mutation",
47851
+ auth: "admin"
47852
+ }),
47853
+ forceRestart: systemMethod(deviceInput$1, PowerSourceActionResultSchema, {
47854
+ kind: "mutation",
47855
+ auth: "admin"
47856
+ })
47857
+ },
47858
+ runtimeState: PowerSourceStateSchema,
47859
+ customize: powerSourceCustomize,
47860
+ /**
47861
+ * Runtime-state durability: **session** — mirrored from the linked switch on
47862
+ * its next report; a restored value would outlive the reading it names.
47863
+ *
47864
+ * See `RuntimeStateDurability`. Enforced by
47865
+ * `scripts/check-runtime-state-durability.ts`.
47866
+ */
47867
+ durability: "session",
47868
+ history: "none"
47869
+ };
47751
47870
  DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
47752
47871
  DeviceType.Camera;
47753
47872
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
@@ -53786,7 +53905,8 @@ var PALETTE_ENTRY_IDS = [
53786
53905
  "switch",
53787
53906
  "siren",
53788
53907
  "button",
53789
- "doorbell"
53908
+ "doorbell",
53909
+ "appliance-cycle"
53790
53910
  ];
53791
53911
  var AUDIO_ENTRY_ID = "audio";
53792
53912
  /** Six rungs, quiet → loud. The opaque end is the entry's hex. */
@@ -53857,7 +53977,8 @@ var CAMSTACK_HEX = {
53857
53977
  switch: "#7a812a",
53858
53978
  siren: "#ac5d7f",
53859
53979
  button: "#b276cd",
53860
- doorbell: "#0087ab"
53980
+ doorbell: "#0087ab",
53981
+ "appliance-cycle": "#2a8c8c"
53861
53982
  };
53862
53983
  var CAMSTACK_FALLBACK = [
53863
53984
  "#b34dc7",
@@ -53922,7 +54043,8 @@ var HIGH_CONTRAST_HEX = {
53922
54043
  switch: "#d05259",
53923
54044
  siren: "#cd67b3",
53924
54045
  button: "#c9746a",
53925
- doorbell: "#338eeb"
54046
+ doorbell: "#338eeb",
54047
+ "appliance-cycle": "#00848a"
53926
54048
  };
53927
54049
  var HIGH_CONTRAST_FALLBACK = [
53928
54050
  "#817f3b",
@@ -53987,7 +54109,8 @@ var OKABE_ITO_HEX = {
53987
54109
  switch: "#ad2c4e",
53988
54110
  siren: "#348e08",
53989
54111
  button: "#d27303",
53990
- doorbell: "#55770f"
54112
+ doorbell: "#55770f",
54113
+ "appliance-cycle": "#00737d"
53991
54114
  };
53992
54115
  var OKABE_ITO_FALLBACK = [
53993
54116
  "#9a3784",
@@ -54197,6 +54320,7 @@ sub("switch", "control", "control", "switch", "Switch");
54197
54320
  sub("siren", "control", "control", "siren", "Siren");
54198
54321
  sub("button", "control", "control", "button", "Button");
54199
54322
  sub("doorbell", "control", "control", "doorbell", "Doorbell");
54323
+ sub("appliance-cycle", "control", "control", "switch", "Appliance cycle");
54200
54324
  for (const l of AUDIO_MACRO_LABELS) {
54201
54325
  const kind = `audio-${l.id}`;
54202
54326
  if (entries.has(kind)) continue;
@@ -64627,7 +64751,8 @@ var CAP_TO_KIND = {
64627
64751
  cover: "cover",
64628
64752
  switch: "switch",
64629
64753
  button: "button",
64630
- doorbell: "doorbell"
64754
+ doorbell: "doorbell",
64755
+ "running-state": "appliance-cycle"
64631
64756
  };
64632
64757
  function buildDescriptor(capName, kind) {
64633
64758
  const t = EVENT_TAXONOMY[kind];
@@ -69083,19 +69208,19 @@ var RemoteSetConfigResultSchema = discriminatedUnion("status", [object({ status:
69083
69208
  reason: _enum(["unknown-template", "not-a-media-player"]),
69084
69209
  detail: string()
69085
69210
  })]);
69086
- var deviceInput$1 = object({ deviceId: number().int().nonnegative() });
69211
+ var deviceInput = object({ deviceId: number().int().nonnegative() });
69087
69212
  DeviceType.MediaPlayer;
69088
- method(deviceInput$1, RemoteConfigSchema, { auth: "admin" }), method(deviceInput$1.extend({ config: RemoteConfigSchema }), RemoteSetConfigResultSchema, {
69213
+ method(deviceInput, RemoteConfigSchema, { auth: "admin" }), method(deviceInput.extend({ config: RemoteConfigSchema }), RemoteSetConfigResultSchema, {
69089
69214
  kind: "mutation",
69090
69215
  auth: "admin"
69091
- }), method(deviceInput$1, RemoteCommandListSchema, { auth: "protected" }), method(deviceInput$1.extend({
69216
+ }), method(deviceInput, RemoteCommandListSchema, { auth: "protected" }), method(deviceInput.extend({
69092
69217
  role: RemoteRoleSchema,
69093
69218
  /** Sends in a row (volume steps). */
69094
69219
  repeat: number().int().min(1).max(50).default(1)
69095
69220
  }), RemoteSendResultSchema, {
69096
69221
  kind: "mutation",
69097
69222
  auth: "protected"
69098
- }), method(deviceInput$1.extend({
69223
+ }), method(deviceInput.extend({
69099
69224
  command: RemoteMediaCommandSchema,
69100
69225
  muted: boolean().optional(),
69101
69226
  source: string().optional(),
@@ -73540,117 +73665,6 @@ var lockControlCapability = {
73540
73665
  * whether persisting is worth a SQLite commit. */
73541
73666
  volatileStateFields: ["lastChangedAt"]
73542
73667
  };
73543
- var PowerSourceRefusalReasonSchema = _enum([
73544
- "no-power-source",
73545
- "switch-missing",
73546
- "switch-offline",
73547
- "switch-unknown",
73548
- "restart-in-progress",
73549
- "switch-call-failed"
73550
- ]);
73551
- var PowerSourceActionResultSchema = discriminatedUnion("accepted", [object({ accepted: literal(true) }), object({
73552
- accepted: literal(false),
73553
- reason: PowerSourceRefusalReasonSchema,
73554
- /** One line for the operator, naming the switch. */
73555
- message: string()
73556
- })]);
73557
- var PowerSourceInfoSchema = object({
73558
- /** False when the device has no power source linked; the rest is then empty. */
73559
- linked: boolean(),
73560
- switchDeviceId: number().nullable(),
73561
- switchName: string().nullable(),
73562
- /** The switch's on/off state, or null when it is unknown. Never false for unknown (D393). */
73563
- switchOn: boolean().nullable(),
73564
- switchOnline: boolean().nullable(),
73565
- restartInProgress: boolean(),
73566
- offSeconds: number().int()
73567
- });
73568
- /** The composed slice: the switch state the link mirrors, plus the stored off time. */
73569
- var PowerSourceStateSchema = object({
73570
- /** Null while the switch has not reported: unknown is never `false` (D393). */
73571
- switchOn: boolean().nullable(),
73572
- offSeconds: number().int(),
73573
- lastFetchedAt: number()
73574
- });
73575
- var POWER_SOURCE_DEVICE_TYPES = [
73576
- DeviceType.Gateway,
73577
- DeviceType.Hub,
73578
- DeviceType.Camera,
73579
- DeviceType.Sensor,
73580
- DeviceType.MediaPlayer,
73581
- DeviceType.Vacuum,
73582
- DeviceType.Generic,
73583
- DeviceType.Washer,
73584
- DeviceType.Dryer,
73585
- DeviceType.Dishwasher,
73586
- DeviceType.PetFountain,
73587
- DeviceType.Fan,
73588
- DeviceType.Humidifier,
73589
- DeviceType.Climate,
73590
- DeviceType.WaterHeater
73591
- ];
73592
- var powerSourceCustomize = {
73593
- version: 1,
73594
- targets: [{
73595
- id: "switch",
73596
- cardinality: "scalar",
73597
- vocabulary: {
73598
- cap: "power-source",
73599
- stateField: "switchOn"
73600
- },
73601
- deviceTypes: POWER_SOURCE_DEVICE_TYPES,
73602
- apply: "add",
73603
- path: "switchOn",
73604
- sources: [{
73605
- kind: "switch",
73606
- transforms: [{ kind: "identity" }]
73607
- }],
73608
- companions: [{
73609
- kind: "constant",
73610
- path: "offSeconds",
73611
- value: 10,
73612
- when: "add"
73613
- }, {
73614
- kind: "clock",
73615
- path: "lastFetchedAt",
73616
- when: "always"
73617
- }],
73618
- sourceReport: { status: "assignment-status" }
73619
- }]
73620
- };
73621
- var deviceInput = object({ deviceId: number().int().nonnegative() });
73622
- var powerSourceCapability = {
73623
- name: "power-source",
73624
- scope: "device",
73625
- mode: "singleton",
73626
- deviceTypes: POWER_SOURCE_DEVICE_TYPES,
73627
- methods: {
73628
- getStatus: systemMethod(deviceInput, PowerSourceInfoSchema, { auth: "admin" }),
73629
- powerOn: systemMethod(deviceInput, PowerSourceActionResultSchema, {
73630
- kind: "mutation",
73631
- auth: "admin"
73632
- }),
73633
- powerOff: systemMethod(deviceInput, PowerSourceActionResultSchema, {
73634
- kind: "mutation",
73635
- auth: "admin"
73636
- }),
73637
- forceRestart: systemMethod(deviceInput, PowerSourceActionResultSchema, {
73638
- kind: "mutation",
73639
- auth: "admin"
73640
- })
73641
- },
73642
- runtimeState: PowerSourceStateSchema,
73643
- customize: powerSourceCustomize,
73644
- /**
73645
- * Runtime-state durability: **session** — mirrored from the linked switch on
73646
- * its next report; a restored value would outlive the reading it names.
73647
- *
73648
- * See `RuntimeStateDurability`. Enforced by
73649
- * `scripts/check-runtime-state-durability.ts`.
73650
- */
73651
- durability: "session",
73652
- history: "none"
73653
- };
73654
73668
  /**
73655
73669
  * A monotonic total between resets (D944). Energy uses `power-meter.energy`
73656
73670
  * so dashboards keep one series; every other instantaneous reading lands here.
@@ -77252,6 +77266,10 @@ var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
77252
77266
  /** Generic Customize target for the running boolean (D936). */
77253
77267
  var runningCustomize = {
77254
77268
  version: 1,
77269
+ overridable: [{
77270
+ path: "running",
77271
+ by: "running"
77272
+ }],
77255
77273
  targets: [{
77256
77274
  id: "running",
77257
77275
  cardinality: "scalar",
@@ -77309,7 +77327,7 @@ var runningCustomize = {
77309
77327
  kind: "constant",
77310
77328
  path: "phase",
77311
77329
  value: null,
77312
- when: "always"
77330
+ when: "add"
77313
77331
  },
77314
77332
  {
77315
77333
  kind: "clock",
@@ -97423,7 +97441,8 @@ function isSystemDelivery(delivery) {
97423
97441
  * picker authors.
97424
97442
  *
97425
97443
  * Callers resolve the ids via `deviceManager.listDeviceIdsByCaps` (max 16
97426
- * names — `EVENTFUL_CAP_NAMES` is exactly 16) and must treat an unanswered
97444
+ * names per call — `EVENTFUL_CAP_NAMES` is longer than that, so ask through
97445
+ * {@link ruleDeviceCompatCapQueries}, which chunks it) and must treat an unanswered
97427
97446
  * read as "unknown", never as "no devices" (D315): this function only names
97428
97447
  * WHICH caps to ask for, not what to show while the answer is pending.
97429
97448
  */
@@ -97445,6 +97464,12 @@ function ruleDeviceCompatCapNames(kind) {
97445
97464
  * Named once, because a sensor rule's compatible set needs it (below).
97446
97465
  */
97447
97466
  var NC_CAMERA_SCOPE_CAP_NAME = "camera-streams";
97467
+ var MAX_CAPS_PER_QUERY = 16;
97468
+ function chunk(items, size) {
97469
+ const out = [];
97470
+ for (let i = 0; i < items.length; i += size) out.push(items.slice(i, i + size));
97471
+ return out;
97472
+ }
97448
97473
  /**
97449
97474
  * Every capability QUERY whose union is the set of devices a rule of this kind
97450
97475
  * may be SCOPED to (`conditions.devices`) — what the save-time guard and the
@@ -97452,7 +97477,7 @@ var NC_CAMERA_SCOPE_CAP_NAME = "camera-streams";
97452
97477
  * entry. `null` exactly where {@link ruleDeviceCompatCapNames} is `null`.
97453
97478
  *
97454
97479
  * Several queries rather than one list because `listDeviceIdsByCaps` takes at
97455
- * most 16 names and `EVENTFUL_CAP_NAMES` is already exactly 16.
97480
+ * most 16 names and `EVENTFUL_CAP_NAMES` is longer than that (chunked here).
97456
97481
  *
97457
97482
  * A `sensor` rule's set is the eventful devices PLUS every camera (fix round
97458
97483
  * 1, 2026-10-01): the engine matches a sensor rule scoped to a CAMERA — a
@@ -97463,7 +97488,8 @@ var NC_CAMERA_SCOPE_CAP_NAME = "camera-streams";
97463
97488
  function ruleDeviceCompatCapQueries(kind) {
97464
97489
  const primary = ruleDeviceCompatCapNames(kind);
97465
97490
  if (primary === null) return null;
97466
- return kind === "sensor" ? [primary, [NC_CAMERA_SCOPE_CAP_NAME]] : [primary];
97491
+ const chunks = chunk(primary, MAX_CAPS_PER_QUERY);
97492
+ return kind === "sensor" ? [...chunks, [NC_CAMERA_SCOPE_CAP_NAME]] : chunks;
97467
97493
  }
97468
97494
  /**
97469
97495
  * Which kind of rule is this?
@@ -98367,8 +98393,17 @@ function syncActiveAlarmProfileSettings(state, settings) {
98367
98393
  *
98368
98394
  * Pure, RN-safe: the viewer imports the support rule from here.
98369
98395
  */
98396
+ /**
98397
+ * Control caps that still have a raise and a clear an operator names: an
98398
+ * appliance cycle raises when it STARTS and clears when it FINISHES. Kept out
98399
+ * of `SOURCE_CAP_ACTIVE_FIELD` on purpose — that table also makes a device a
98400
+ * camera-sensor / recorder-trigger source, and a dishwasher is neither.
98401
+ */
98402
+ var CYCLE_RAISED_FIELD_BY_CAP = { "running-state": "running" };
98370
98403
  /** Event kind → the boolean field of its cap slice that means "raised". */
98371
98404
  var NC_SENSOR_RAISED_FIELD_BY_KIND = Object.freeze(Object.fromEntries(Object.entries(EVENT_KIND_BY_CAP).flatMap(([capName, descriptor]) => {
98405
+ const cycleField = CYCLE_RAISED_FIELD_BY_CAP[capName];
98406
+ if (cycleField !== void 0) return [[descriptor.kind, cycleField]];
98372
98407
  const field = SOURCE_CAP_ACTIVE_FIELD[capName];
98373
98408
  if (field === void 0 || descriptor.category !== "sensor") return [];
98374
98409
  return [[descriptor.kind, field]];
@@ -100108,6 +100143,7 @@ var EVENT_KIND_LABEL_KEYS = [
100108
100143
  "siren",
100109
100144
  "button",
100110
100145
  "doorbell",
100146
+ "appliance-cycle",
100111
100147
  "audio-speech",
100112
100148
  "audio-scream",
100113
100149
  "audio-crying",
@@ -100315,6 +100351,10 @@ var EVENT_KIND_LABELS = {
100315
100351
  en: "Doorbell",
100316
100352
  it: "Campanello"
100317
100353
  },
100354
+ "appliance-cycle": {
100355
+ en: "Appliance cycle",
100356
+ it: "Ciclo elettrodomestico"
100357
+ },
100318
100358
  "audio-speech": {
100319
100359
  en: "Speech",
100320
100360
  it: "Voce"
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_clip_model_registry = require("../clip-model-registry-zi2g3vrD.js");
5
+ const require_clip_model_registry = require("../clip-model-registry-MIf9O34C.js");
6
6
  let node_fs = require("node:fs");
7
7
  node_fs = require_clip_model_registry.__toESM(node_fs);
8
8
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { Si as resolvePoolMemoryPolicy, _r as embeddingModelFailedError, a as CLIP_EMBEDDING_STEP_ID, br as embeddingRequirementsUnavailableError, ga as normalizeNodeId, gr as embeddingEncoderCapability, i as CLIP_TEXT_MODELS, l as resolveClusterModelPin, n as DEFAULT_CLIP_MODEL, r as CLIP_IMAGE_MODELS, ra as BaseAddon, rn as PoolMemoryWatchdog, si as parseProcStatus, t as BUILTIN_CLIP_MODELS, yr as embeddingRequirementsFailedError } from "../clip-model-registry-OHEqXA-p.mjs";
1
+ import { Si as resolvePoolMemoryPolicy, _r as embeddingModelFailedError, a as CLIP_EMBEDDING_STEP_ID, br as embeddingRequirementsUnavailableError, ga as normalizeNodeId, gr as embeddingEncoderCapability, i as CLIP_TEXT_MODELS, l as resolveClusterModelPin, n as DEFAULT_CLIP_MODEL, r as CLIP_IMAGE_MODELS, ra as BaseAddon, rn as PoolMemoryWatchdog, si as parseProcStatus, t as BUILTIN_CLIP_MODELS, yr as embeddingRequirementsFailedError } from "../clip-model-registry-BtzUYE5M.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import * as fs from "node:fs";
4
4
  import * as path$1 from "node:path";
@@ -18,7 +18,7 @@ var e = {
18
18
  },
19
19
  "@camstack/types": {
20
20
  name: "@camstack/types",
21
- version: "1.2.464",
21
+ version: "1.2.466",
22
22
  scope: ["default"],
23
23
  loaded: !1,
24
24
  from: "addon_pipeline_analytics_widgets",
@@ -36,7 +36,7 @@ async function r() {
36
36
  }
37
37
  },
38
38
  "@camstack/types": {
39
- version: "1.2.464",
39
+ version: "1.2.466",
40
40
  scope: "default",
41
41
  shareConfig: {
42
42
  singleton: !0,
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_clip_model_registry = require("../clip-model-registry-zi2g3vrD.js");
5
+ const require_clip_model_registry = require("../clip-model-registry-MIf9O34C.js");
6
6
  let node_fs = require("node:fs");
7
7
  node_fs = require_clip_model_registry.__toESM(node_fs, 1);
8
8
  let node_path = require("node:path");
@@ -70905,6 +70905,16 @@ var WORD_LEVEL_FIELD = {
70905
70905
  cover: "state",
70906
70906
  "lock-control": "state"
70907
70907
  };
70908
+ /**
70909
+ * Caps that carry a boolean level but are NOT source caps (`SOURCE_CAP_ACTIVE_FIELD`
70910
+ * would also make the device a recorder trigger): cap → boolean field. An
70911
+ * appliance cycle (`running-state`) flips `running`; its slice also carries
70912
+ * `lastFetchedAt`, which moves on every provider refresh, so only the FLIP —
70913
+ * either way — is an edge. The first sighting is a start only when the slice's
70914
+ * `since` clears the freshness floor, else it seeds (a machine that has been
70915
+ * running for an hour at boot did not just start).
70916
+ */
70917
+ var BOOLEAN_LEVEL_FIELD = { "running-state": "running" };
70908
70918
  /** The word a word-level cap rests in — its `false`, for the first-sighting rule. */
70909
70919
  var WORD_LEVEL_INACTIVE = {
70910
70920
  cover: "closed",
@@ -70959,6 +70969,8 @@ var SensorTransitionGate = class {
70959
70969
  if (slice["lastChangedAt"] === 0) return this.drop(deviceId, capName, "cold-slice");
70960
70970
  const wordField = WORD_LEVEL_FIELD[capName];
70961
70971
  if (wordField !== void 0) return this.observeWord(deviceId, capName, slice, wordField);
70972
+ const levelField = BOOLEAN_LEVEL_FIELD[capName];
70973
+ if (levelField !== void 0) return this.observeLevel(deviceId, capName, slice, levelField);
70962
70974
  const advanceField = ADVANCE_FIELD[capName];
70963
70975
  if (advanceField !== void 0) return this.observeAdvance(deviceId, capName, slice[advanceField]);
70964
70976
  if (!require_clip_model_registry.isSourceCap(capName)) return { changed: true };
@@ -70999,6 +71011,25 @@ var SensorTransitionGate = class {
70999
71011
  return out;
71000
71012
  }
71001
71013
  /**
71014
+ * A boolean level outside the source-cap table: a transition is the boolean
71015
+ * changing. Memory is written only when the slice CARRIED a boolean.
71016
+ */
71017
+ observeLevel(deviceId, capName, slice, field) {
71018
+ const raw = slice[field];
71019
+ if (typeof raw !== "boolean") return this.drop(deviceId, capName, "non-boolean-value");
71020
+ const key = `${deviceId}:${capName}`;
71021
+ const prior = this.lastValues.get(key);
71022
+ this.lastValues.set(key, raw);
71023
+ if (prior === void 0) {
71024
+ if (!raw) return this.drop(deviceId, capName, "baseline-seeded-inactive");
71025
+ const since = slice["since"];
71026
+ const floor = Math.max(this.startedAtMs, this.now() - this.freshnessMs);
71027
+ return typeof since === "number" && Number.isFinite(since) && since >= floor ? { changed: true } : this.drop(deviceId, capName, "baseline-seeded-stale-active");
71028
+ }
71029
+ if (prior === raw) return this.drop(deviceId, capName, "no-change");
71030
+ return { changed: true };
71031
+ }
71032
+ /**
71002
71033
  * A word-level cap: a transition is the word changing. The memory is
71003
71034
  * written only when the slice CARRIED a word, for the same reason as the
71004
71035
  * booleans — a malformed slice must not become a baseline.
@@ -1,4 +1,4 @@
1
- import { $ as MAX_TRACK_RELATIONS, $i as DEFAULT_FIRST_SIGHTING_FRESHNESS_MS, $n as bundledCamstack, $r as normalizeNcAction, $t as NcTemplateVarDescriptorSchema, A as DETECTION_MACRO_CLASSES, Aa as string, Ai as sceneMonitorCapability, An as TrackPuritySchema, Ar as isAlertEpisodeOpen, At as NcAlarmConfigSchema, B as EXPORT_DENSE_MAX_RANGES, Bi as sunTimes, Bn as alertEpisodeKind, Br as isLabelSupplyStepId, Bt as NcRuleSchema, C as COCO_TO_MACRO, Ca as literal, Ci as retrainRevisionConflictMessage, Cn as SetTrackRelationInputSchema, Cr as eventKindLabel, Ct as NC_GROUPING_MIN_SEC, D as DEFAULT_DETAIL_CROP_CONVENTION, Da as partialRecord, Di as ruleDeviceCompatCapQueries, Dn as TimelapseRulePatchSchema, Dr as gifDeriveSpeed, Dt as NC_SYSTEM_EVENT_KIND_GROUP_SPECS, E as CoverStateSchema, Ea as object, Ei as ruleBelongsToAlarm$1, En as TimelapseRuleInputSchema, Er as failureContributionCapability, Et as NC_STATE_SUMMARY_SECTION_IDS, F as EMBEDDING_REQUIREMENTS_FAILED, Fa as DeviceType, Fi as storageOccupancyCapability, Fn as activateAlarmProfile, Fr as isDetectionMacroClass, Ft as NcConditionDescriptorSchema, G as LabelAttributionSchema, Gi as systemEventSummaryScheduleOf, Gn as applySecureOnArmEdit, Gr as isSystemDelivery, Gt as NcSnoozeInputSchema, H as FULL_IMAGE_BBOX, Hi as systemEventDeliveryProblems, Hn as applyBlockingEdit, Hr as isRetiredClearKey, Ht as NcRuleUpdateInputSchema, I as EMBEDDING_REQUIREMENTS_UNAVAILABLE, Ia as errMsg, Ii as subKindsOf, In as addonWidgetsSourceCapability, Ir as isDrawableSubjectPath, It as NcConditionsSchema, J as LockStateSchema, Ji as templateVarsFor, Jn as audioMetricsCapability, Jr as kebabToCamel, Jt as NcStateSummarySectionIdSchema, K as ListTrackRelationsInputSchema, Ki as systemEventSummarySplitOf, Kn as armRemovalReconcile, Kr as isSystemEventSummaryRule, Kt as NcSnoozeSchema, L as EVENT_DENSITY_BATCH_MAX, La as EventCategory, Li as subjectPathSampleFromBox, Ln as alarmDeviceSecureOnArm, Lr as isEventKindLabelKey, Lt as NcRuleActionSchema, M as DeclaredDevices, Ma as tuple, Mi as sensorRaisedOf, Mn as TrackRelationSchema, Mr as isAppLinkBase, Mt as NcAlarmSensorsInputSchema, N as DetectionSourceSchema, Na as union, Ni as servedTemplateVars, Nn as TrackSideSchema, Nr as isAudioClassName, Nt as NcAlarmSensorsSchema, O as DEFAULT_EVENT_COLOR, Oa as record, Oi as ruleGroupingApplies, On as TimelapseRuleSchema, Or as gifFromMp4Args, Ot as NC_TAXONOMY, P as EMBEDDING_MODEL_FAILED, Pa as unknown, Pi as startMoverUnderClearance, Pn as TrackSourceSchema, Pr as isDefaultAlarmProfileId, Pt as NcAlarmSettingsPatchSchema, Q as MAX_TRACK_PURITIES, Qi as zoneAnalyticsCapability, Qn as buildViewerLink, Qr as ncMediaPolicyError, Qt as NcTemplatePreviewSchema, R as EVENT_KIND_BY_CAP, Ri as subjectPathSvgPoints, Rn as alarmPanelCapability, Rr as isEventOwnerType, Rt as NcRuleInputSchema, S as BucketAccumulator, Sa as discriminatedUnion, Sn as SetTrackPurityResultSchema, Sr as ensureAlarmProfiles, St as NC_GROUPING_MAX_SEC, T as ClearTrackRelationResultSchema, Ta as number, Ti as ruleAutoTriggersAlarm, Tn as TRACK_RELATIONS_DEFAULT_LIMIT, Tr as faceGalleryCapability, Tt as NC_SNOOZE_MAX_MINUTES, U as FailureCounters, Ui as systemEventFamilyProblems, Un as applyModeDelaysEdits, Ur as isRootSuppliableStepId, Ut as NcScheduleSchema, V as FIRST_LEVEL_MACRO_CLASSES, Vi as syncActiveAlarmProfileSettings, Vn as alertEpisodePayload, Vr as isMediaOwnerType, Vt as NcRuleTargetSchema, W as LABEL_SUPPLY_MACRO, Wi as systemEventFilterApplies, Wn as applyNonBlockingEdit, Wr as isScheduleActive, Wt as NcSharedSequenceSchema, X as MAX_BIRTH_DECISION_RECORDS, Xi as viewerLinkBaseOf, Xn as buildEventKindDescriptor, Xr as mayWriteToLocation, Xt as NcTaxonomySchema, Y as MAX_ARCHIVED_DEBUG_NOTES, Yi as vectorDimFromBase64, Yn as audioModeOf, Yr as linkedStepOf, Yt as NcSystemEventKindSchema, Z as MAX_BIRTH_LATENCY_PROXY_MS, Zi as withSystemEventClasses, Zn as buildSubjectPath, Zr as memoizePinnedFfmpeg, Zt as NcTemplatePreviewInputSchema, _ as AlarmArmModeSchema, _a as sleep$1, _i as resolveDeliveryParams, _n as SCENE_DEFAULT_UNCOVERED_POLICY, _t as NC_CONFIRM_DEFAULT_TIMEOUT_MS, a as CLIP_EMBEDDING_STEP_ID, aa as CamProfileSchema, ai as paletteResultSchema, an as RECORDING_SOURCE_CAMSTACK_ADDON, ar as coreBlockIdFromAddonId, at as NC_ALARM_DELAY_FIELDS, b as BaseDevice, ba as array, bi as resolveModeNotifyPolicy, bn as SceneMonitorSchema, bt as NC_DEFAULT_SNOOZE_MINUTES, c as readClusterModelPinStrict, ca as RECORD_QUERY_MAX, ci as pickFaceRescoreIntervalMinutes, cn as RetrainOriginSchema, cr as deleteAlarmProfile, ct as NC_ALARM_SYSTEM_EVENT_KINDS, d as APPEARANCE_BIN_COUNT, da as defineCustomActions, di as projectSubjectPath, dn as SCENE_CONFIRM_DEFAULT_MAX_IMAGE_PX, dr as deriveRecordingMode, dt as NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT, ea as canonicalHash, ei as normalizeNcCapTarget, en as OPS_LOG_DEFAULT_LIMIT, er as calendarEventLocalSpan, et as MOTION_CLOSE_AFTER_MS, f as APPEARANCE_BLOCKS, fa as defineRecordKinds, fi as readDeviceStateFrom, fn as SCENE_CONFIRM_DEFAULT_TIMEOUT_MS, fr as describeSystemEventDeliveryProblem, ft as NC_CLIP_POST_ROLL_DEFAULT_SEC, g as ActionTargetResolver, gi as resolveClipSearchMinScore, gn as SCENE_DEFAULT_QUIET_SECONDS, gt as NC_CONFIRM_DEFAULT_MAX_IMAGE_PX, h as AUDIO_MACRO_LABELS, ha as nodePin, hi as renameAlarmProfile, hn as SCENE_DEFAULT_OBSERVATION_SPACING_SEC, hr as deviceRemovalHookCapability, ht as NC_CONDITION_CATALOG, ia as CAP_ADVANCE_FIELDS, ii as paintHex, in as RECORDING_EXPORT_MAX_READ_BYTES, ir as consumableLowPercentOf, it as NC_ALARM_DEFAULT_TRIGGERED_DURATION_SEC, j as DETECTION_PIPELINE_CAP_NAME, ja as templateLiteral, ji as secureActuationFor, jn as TrackRelationKindSchema, jr as isAlertEpisodeSeverity, jt as NcAlarmPostTriggeredActionSchema, k as DEFAULT_TIMELAPSE_PREVIEW_TEXT, ka as strictObject, ki as ruleKindOf, kn as TrackPlacementSchema, kr as isAlarmControllableCap, kt as NC_TEMPLATE_VARS, l as resolveClusterModelPin, la as createEvent, li as pipelineAnalyticsCapability, ln as RetrainStatusSchema, lr as deriveDetailCropRect, lt as NC_ALARM_TRIGGERED_MAX_SEC, m as ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT, ma as isDeviceScopedCap, mi as readTimelapseGeneratedAt, mn as SCENE_DEFAULT_CHECK_INTERVAL_SEC, mr as deviceAttentionKind, mt as NC_CLIP_RETENTION_MAX_SEC, na as isSourceCap, ni as notificationRulesCapability, nn as PackageLlmVerdictSchema, nr as cloneAlarmSettings, nt as MotionTriggeredBySchema, o as CLUSTER_MODEL_OWNER_ADDON_ID, oa as InvalidRecordError, oi as parseAlertEpisodePayload, on as RebuildObjectEmbeddingsRefusalSchema, or as cosineSimilarity$1, ot as NC_ALARM_DELAY_MAX_SEC, p as APPEARANCE_RESOLVES_AMBIGUITY_DEFAULT, pa as hydrateSchema, pi as readMotionTriggeredBy, pn as SCENE_DEFAULT_ANCHOR_THRESHOLD, pr as describeSystemEventFamilyProblem, pt as NC_CLIP_PRE_ROLL_DEFAULT_SEC, q as ListTrackRelationsResultSchema, qi as templateCarriesSummary, qn as assertTimelapseCadences, qr as isVectorIndexDimConflict, qt as NcSnoozeSuppressedSchema, ra as BaseAddon, ri as occupancyScope, rr as consumableFormOf, rt as NC_ALARM_DEFAULT_PROFILE_ID, s as FACE_EMBEDDING_STEP_ID, sa as RECORD_MAX_DATA_BYTES, sn as RetrainDismissedSchema, sr as createAlarmProfile, st as NC_ALARM_NOTIFY_FIELDS, t as BUILTIN_CLIP_MODELS, ta as evaluateSensorEdge, ti as normalizeNcMediaPolicy, tn as OpsLogEntrySchema, tr as classifyRetrainReview, tt as MediaFileKindEnum, u as ACTION_TARGET_INVALIDATION_EVENTS, ua as customAction, ui as plateGalleryCapability, un as RetrainVerdictSubjectSchema, ur as derivePostTriggeredAction, ut as NC_AUDIO_CONFIRM_HITS_DEFAULT, v as ArchivedDebugNoteSchema, va as ZodObject, vi as resolveLocationMode, vn as SCENE_DIVERGED, vr as embeddingRefusalOf, vt as NC_CONSUMABLE_LOW_PERCENT_DEFAULT, w as ClearTrackRelationInputSchema, wa as looseObject, wi as rootSupplyServes, wn as TIMELAPSE_DENSE_FLOOR_SEC, wr as evictionPolicyOfLocation, wt as NC_SENSOR_TRANSITION_KINDS, x as BirthDecisionRecordSchema, xa as boolean, xi as resolveNcMediaImage, xn as SetTrackPurityInputSchema, xr as encodeVectorBase64, xt as NC_GROUPING_DEFAULT_SEC, y as BIRTH_DECISION_DEFAULT_LIMIT, ya as _enum, yi as resolveModeDelays, yn as SCENE_RESET_RECAPTURES, yt as NC_CONSUMABLE_SYSTEM_EVENT_KINDS, z as EVENT_OWNER_TYPES, zi as summarizeReview, zn as alertEpisodeId, zr as isKnownTemplateVar, zt as NcRulePatchSchema } from "../clip-model-registry-OHEqXA-p.mjs";
1
+ import { $ as MAX_TRACK_RELATIONS, $i as DEFAULT_FIRST_SIGHTING_FRESHNESS_MS, $n as bundledCamstack, $r as normalizeNcAction, $t as NcTemplateVarDescriptorSchema, A as DETECTION_MACRO_CLASSES, Aa as string, Ai as sceneMonitorCapability, An as TrackPuritySchema, Ar as isAlertEpisodeOpen, At as NcAlarmConfigSchema, B as EXPORT_DENSE_MAX_RANGES, Bi as sunTimes, Bn as alertEpisodeKind, Br as isLabelSupplyStepId, Bt as NcRuleSchema, C as COCO_TO_MACRO, Ca as literal, Ci as retrainRevisionConflictMessage, Cn as SetTrackRelationInputSchema, Cr as eventKindLabel, Ct as NC_GROUPING_MIN_SEC, D as DEFAULT_DETAIL_CROP_CONVENTION, Da as partialRecord, Di as ruleDeviceCompatCapQueries, Dn as TimelapseRulePatchSchema, Dr as gifDeriveSpeed, Dt as NC_SYSTEM_EVENT_KIND_GROUP_SPECS, E as CoverStateSchema, Ea as object, Ei as ruleBelongsToAlarm$1, En as TimelapseRuleInputSchema, Er as failureContributionCapability, Et as NC_STATE_SUMMARY_SECTION_IDS, F as EMBEDDING_REQUIREMENTS_FAILED, Fa as DeviceType, Fi as storageOccupancyCapability, Fn as activateAlarmProfile, Fr as isDetectionMacroClass, Ft as NcConditionDescriptorSchema, G as LabelAttributionSchema, Gi as systemEventSummaryScheduleOf, Gn as applySecureOnArmEdit, Gr as isSystemDelivery, Gt as NcSnoozeInputSchema, H as FULL_IMAGE_BBOX, Hi as systemEventDeliveryProblems, Hn as applyBlockingEdit, Hr as isRetiredClearKey, Ht as NcRuleUpdateInputSchema, I as EMBEDDING_REQUIREMENTS_UNAVAILABLE, Ia as errMsg, Ii as subKindsOf, In as addonWidgetsSourceCapability, Ir as isDrawableSubjectPath, It as NcConditionsSchema, J as LockStateSchema, Ji as templateVarsFor, Jn as audioMetricsCapability, Jr as kebabToCamel, Jt as NcStateSummarySectionIdSchema, K as ListTrackRelationsInputSchema, Ki as systemEventSummarySplitOf, Kn as armRemovalReconcile, Kr as isSystemEventSummaryRule, Kt as NcSnoozeSchema, L as EVENT_DENSITY_BATCH_MAX, La as EventCategory, Li as subjectPathSampleFromBox, Ln as alarmDeviceSecureOnArm, Lr as isEventKindLabelKey, Lt as NcRuleActionSchema, M as DeclaredDevices, Ma as tuple, Mi as sensorRaisedOf, Mn as TrackRelationSchema, Mr as isAppLinkBase, Mt as NcAlarmSensorsInputSchema, N as DetectionSourceSchema, Na as union, Ni as servedTemplateVars, Nn as TrackSideSchema, Nr as isAudioClassName, Nt as NcAlarmSensorsSchema, O as DEFAULT_EVENT_COLOR, Oa as record, Oi as ruleGroupingApplies, On as TimelapseRuleSchema, Or as gifFromMp4Args, Ot as NC_TAXONOMY, P as EMBEDDING_MODEL_FAILED, Pa as unknown, Pi as startMoverUnderClearance, Pn as TrackSourceSchema, Pr as isDefaultAlarmProfileId, Pt as NcAlarmSettingsPatchSchema, Q as MAX_TRACK_PURITIES, Qi as zoneAnalyticsCapability, Qn as buildViewerLink, Qr as ncMediaPolicyError, Qt as NcTemplatePreviewSchema, R as EVENT_KIND_BY_CAP, Ri as subjectPathSvgPoints, Rn as alarmPanelCapability, Rr as isEventOwnerType, Rt as NcRuleInputSchema, S as BucketAccumulator, Sa as discriminatedUnion, Sn as SetTrackPurityResultSchema, Sr as ensureAlarmProfiles, St as NC_GROUPING_MAX_SEC, T as ClearTrackRelationResultSchema, Ta as number, Ti as ruleAutoTriggersAlarm, Tn as TRACK_RELATIONS_DEFAULT_LIMIT, Tr as faceGalleryCapability, Tt as NC_SNOOZE_MAX_MINUTES, U as FailureCounters, Ui as systemEventFamilyProblems, Un as applyModeDelaysEdits, Ur as isRootSuppliableStepId, Ut as NcScheduleSchema, V as FIRST_LEVEL_MACRO_CLASSES, Vi as syncActiveAlarmProfileSettings, Vn as alertEpisodePayload, Vr as isMediaOwnerType, Vt as NcRuleTargetSchema, W as LABEL_SUPPLY_MACRO, Wi as systemEventFilterApplies, Wn as applyNonBlockingEdit, Wr as isScheduleActive, Wt as NcSharedSequenceSchema, X as MAX_BIRTH_DECISION_RECORDS, Xi as viewerLinkBaseOf, Xn as buildEventKindDescriptor, Xr as mayWriteToLocation, Xt as NcTaxonomySchema, Y as MAX_ARCHIVED_DEBUG_NOTES, Yi as vectorDimFromBase64, Yn as audioModeOf, Yr as linkedStepOf, Yt as NcSystemEventKindSchema, Z as MAX_BIRTH_LATENCY_PROXY_MS, Zi as withSystemEventClasses, Zn as buildSubjectPath, Zr as memoizePinnedFfmpeg, Zt as NcTemplatePreviewInputSchema, _ as AlarmArmModeSchema, _a as sleep$1, _i as resolveDeliveryParams, _n as SCENE_DEFAULT_UNCOVERED_POLICY, _t as NC_CONFIRM_DEFAULT_TIMEOUT_MS, a as CLIP_EMBEDDING_STEP_ID, aa as CamProfileSchema, ai as paletteResultSchema, an as RECORDING_SOURCE_CAMSTACK_ADDON, ar as coreBlockIdFromAddonId, at as NC_ALARM_DELAY_FIELDS, b as BaseDevice, ba as array, bi as resolveModeNotifyPolicy, bn as SceneMonitorSchema, bt as NC_DEFAULT_SNOOZE_MINUTES, c as readClusterModelPinStrict, ca as RECORD_QUERY_MAX, ci as pickFaceRescoreIntervalMinutes, cn as RetrainOriginSchema, cr as deleteAlarmProfile, ct as NC_ALARM_SYSTEM_EVENT_KINDS, d as APPEARANCE_BIN_COUNT, da as defineCustomActions, di as projectSubjectPath, dn as SCENE_CONFIRM_DEFAULT_MAX_IMAGE_PX, dr as deriveRecordingMode, dt as NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT, ea as canonicalHash, ei as normalizeNcCapTarget, en as OPS_LOG_DEFAULT_LIMIT, er as calendarEventLocalSpan, et as MOTION_CLOSE_AFTER_MS, f as APPEARANCE_BLOCKS, fa as defineRecordKinds, fi as readDeviceStateFrom, fn as SCENE_CONFIRM_DEFAULT_TIMEOUT_MS, fr as describeSystemEventDeliveryProblem, ft as NC_CLIP_POST_ROLL_DEFAULT_SEC, g as ActionTargetResolver, gi as resolveClipSearchMinScore, gn as SCENE_DEFAULT_QUIET_SECONDS, gt as NC_CONFIRM_DEFAULT_MAX_IMAGE_PX, h as AUDIO_MACRO_LABELS, ha as nodePin, hi as renameAlarmProfile, hn as SCENE_DEFAULT_OBSERVATION_SPACING_SEC, hr as deviceRemovalHookCapability, ht as NC_CONDITION_CATALOG, ia as CAP_ADVANCE_FIELDS, ii as paintHex, in as RECORDING_EXPORT_MAX_READ_BYTES, ir as consumableLowPercentOf, it as NC_ALARM_DEFAULT_TRIGGERED_DURATION_SEC, j as DETECTION_PIPELINE_CAP_NAME, ja as templateLiteral, ji as secureActuationFor, jn as TrackRelationKindSchema, jr as isAlertEpisodeSeverity, jt as NcAlarmPostTriggeredActionSchema, k as DEFAULT_TIMELAPSE_PREVIEW_TEXT, ka as strictObject, ki as ruleKindOf, kn as TrackPlacementSchema, kr as isAlarmControllableCap, kt as NC_TEMPLATE_VARS, l as resolveClusterModelPin, la as createEvent, li as pipelineAnalyticsCapability, ln as RetrainStatusSchema, lr as deriveDetailCropRect, lt as NC_ALARM_TRIGGERED_MAX_SEC, m as ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT, ma as isDeviceScopedCap, mi as readTimelapseGeneratedAt, mn as SCENE_DEFAULT_CHECK_INTERVAL_SEC, mr as deviceAttentionKind, mt as NC_CLIP_RETENTION_MAX_SEC, na as isSourceCap, ni as notificationRulesCapability, nn as PackageLlmVerdictSchema, nr as cloneAlarmSettings, nt as MotionTriggeredBySchema, o as CLUSTER_MODEL_OWNER_ADDON_ID, oa as InvalidRecordError, oi as parseAlertEpisodePayload, on as RebuildObjectEmbeddingsRefusalSchema, or as cosineSimilarity$1, ot as NC_ALARM_DELAY_MAX_SEC, p as APPEARANCE_RESOLVES_AMBIGUITY_DEFAULT, pa as hydrateSchema, pi as readMotionTriggeredBy, pn as SCENE_DEFAULT_ANCHOR_THRESHOLD, pr as describeSystemEventFamilyProblem, pt as NC_CLIP_PRE_ROLL_DEFAULT_SEC, q as ListTrackRelationsResultSchema, qi as templateCarriesSummary, qn as assertTimelapseCadences, qr as isVectorIndexDimConflict, qt as NcSnoozeSuppressedSchema, ra as BaseAddon, ri as occupancyScope, rr as consumableFormOf, rt as NC_ALARM_DEFAULT_PROFILE_ID, s as FACE_EMBEDDING_STEP_ID, sa as RECORD_MAX_DATA_BYTES, sn as RetrainDismissedSchema, sr as createAlarmProfile, st as NC_ALARM_NOTIFY_FIELDS, t as BUILTIN_CLIP_MODELS, ta as evaluateSensorEdge, ti as normalizeNcMediaPolicy, tn as OpsLogEntrySchema, tr as classifyRetrainReview, tt as MediaFileKindEnum, u as ACTION_TARGET_INVALIDATION_EVENTS, ua as customAction, ui as plateGalleryCapability, un as RetrainVerdictSubjectSchema, ur as derivePostTriggeredAction, ut as NC_AUDIO_CONFIRM_HITS_DEFAULT, v as ArchivedDebugNoteSchema, va as ZodObject, vi as resolveLocationMode, vn as SCENE_DIVERGED, vr as embeddingRefusalOf, vt as NC_CONSUMABLE_LOW_PERCENT_DEFAULT, w as ClearTrackRelationInputSchema, wa as looseObject, wi as rootSupplyServes, wn as TIMELAPSE_DENSE_FLOOR_SEC, wr as evictionPolicyOfLocation, wt as NC_SENSOR_TRANSITION_KINDS, x as BirthDecisionRecordSchema, xa as boolean, xi as resolveNcMediaImage, xn as SetTrackPurityInputSchema, xr as encodeVectorBase64, xt as NC_GROUPING_DEFAULT_SEC, y as BIRTH_DECISION_DEFAULT_LIMIT, ya as _enum, yi as resolveModeDelays, yn as SCENE_RESET_RECAPTURES, yt as NC_CONSUMABLE_SYSTEM_EVENT_KINDS, z as EVENT_OWNER_TYPES, zi as summarizeReview, zn as alertEpisodeId, zr as isKnownTemplateVar, zt as NcRulePatchSchema } from "../clip-model-registry-BtzUYE5M.mjs";
2
2
  import { t as __exportAll } from "../embedding-encoder/index.mjs";
3
3
  import * as fs$1 from "node:fs";
4
4
  import { createWriteStream, promises } from "node:fs";
@@ -70810,6 +70810,16 @@ var WORD_LEVEL_FIELD = {
70810
70810
  cover: "state",
70811
70811
  "lock-control": "state"
70812
70812
  };
70813
+ /**
70814
+ * Caps that carry a boolean level but are NOT source caps (`SOURCE_CAP_ACTIVE_FIELD`
70815
+ * would also make the device a recorder trigger): cap → boolean field. An
70816
+ * appliance cycle (`running-state`) flips `running`; its slice also carries
70817
+ * `lastFetchedAt`, which moves on every provider refresh, so only the FLIP —
70818
+ * either way — is an edge. The first sighting is a start only when the slice's
70819
+ * `since` clears the freshness floor, else it seeds (a machine that has been
70820
+ * running for an hour at boot did not just start).
70821
+ */
70822
+ var BOOLEAN_LEVEL_FIELD = { "running-state": "running" };
70813
70823
  /** The word a word-level cap rests in — its `false`, for the first-sighting rule. */
70814
70824
  var WORD_LEVEL_INACTIVE = {
70815
70825
  cover: "closed",
@@ -70864,6 +70874,8 @@ var SensorTransitionGate = class {
70864
70874
  if (slice["lastChangedAt"] === 0) return this.drop(deviceId, capName, "cold-slice");
70865
70875
  const wordField = WORD_LEVEL_FIELD[capName];
70866
70876
  if (wordField !== void 0) return this.observeWord(deviceId, capName, slice, wordField);
70877
+ const levelField = BOOLEAN_LEVEL_FIELD[capName];
70878
+ if (levelField !== void 0) return this.observeLevel(deviceId, capName, slice, levelField);
70867
70879
  const advanceField = ADVANCE_FIELD[capName];
70868
70880
  if (advanceField !== void 0) return this.observeAdvance(deviceId, capName, slice[advanceField]);
70869
70881
  if (!isSourceCap(capName)) return { changed: true };
@@ -70904,6 +70916,25 @@ var SensorTransitionGate = class {
70904
70916
  return out;
70905
70917
  }
70906
70918
  /**
70919
+ * A boolean level outside the source-cap table: a transition is the boolean
70920
+ * changing. Memory is written only when the slice CARRIED a boolean.
70921
+ */
70922
+ observeLevel(deviceId, capName, slice, field) {
70923
+ const raw = slice[field];
70924
+ if (typeof raw !== "boolean") return this.drop(deviceId, capName, "non-boolean-value");
70925
+ const key = `${deviceId}:${capName}`;
70926
+ const prior = this.lastValues.get(key);
70927
+ this.lastValues.set(key, raw);
70928
+ if (prior === void 0) {
70929
+ if (!raw) return this.drop(deviceId, capName, "baseline-seeded-inactive");
70930
+ const since = slice["since"];
70931
+ const floor = Math.max(this.startedAtMs, this.now() - this.freshnessMs);
70932
+ return typeof since === "number" && Number.isFinite(since) && since >= floor ? { changed: true } : this.drop(deviceId, capName, "baseline-seeded-stale-active");
70933
+ }
70934
+ if (prior === raw) return this.drop(deviceId, capName, "no-change");
70935
+ return { changed: true };
70936
+ }
70937
+ /**
70907
70938
  * A word-level cap: a transition is the word changing. The memory is
70908
70939
  * written only when the slice CARRIED a word, for the same reason as the
70909
70940
  * booleans — a malformed slice must not become a baseline.
@@ -30,7 +30,7 @@ async function d(e) {
30
30
  }
31
31
  }
32
32
  async function f() {
33
- return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-BBL7vKoc.mjs")).catch((e) => {
33
+ return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-C4XD7qn7.mjs")).catch((e) => {
34
34
  throw l = void 0, e;
35
35
  }), l;
36
36
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-post-analysis",
3
- "version": "1.2.658",
3
+ "version": "1.2.659",
4
4
  "description": "Post-Analysis bundle — enrichment, embedding-encoder, pipeline-analytics. Multi-entry npm package shipping addons that consume pipeline output.",
5
5
  "keywords": [
6
6
  "camstack",
@@ -138,7 +138,7 @@
138
138
  }
139
139
  ],
140
140
  "requires": {
141
- "server": ">=1.2.723"
141
+ "server": ">=1.2.726"
142
142
  }
143
143
  },
144
144
  "scripts": {