@camstack/system 1.2.85 → 1.2.87

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  2. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  3. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  4. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  5. package/dist/builtins/alerts/alerts.addon.js +1 -1
  6. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  7. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  8. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  9. package/dist/builtins/console-logging/index.js +1 -1
  10. package/dist/builtins/console-logging/index.mjs +1 -1
  11. package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
  12. package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
  13. package/dist/builtins/device-manager/device-manager.addon.js +155 -18
  14. package/dist/builtins/device-manager/device-manager.addon.mjs +155 -18
  15. package/dist/builtins/device-manager/device-state-mirror.d.ts +51 -6
  16. package/dist/builtins/device-manager/runtime-state-persist-gate.d.ts +32 -0
  17. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  18. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  19. package/dist/builtins/hub-forwarder/index.js +1 -1
  20. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  21. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  22. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  23. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  24. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  25. package/dist/builtins/local-network/local-network.addon.js +1 -1
  26. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  27. package/dist/builtins/loki-logging/index.js +1 -1
  28. package/dist/builtins/loki-logging/index.mjs +1 -1
  29. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  30. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  31. package/dist/builtins/platform-probe/index.js +1 -1
  32. package/dist/builtins/platform-probe/index.mjs +1 -1
  33. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  34. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  35. package/dist/builtins/snapshot/index.js +1 -1
  36. package/dist/builtins/snapshot/index.mjs +1 -1
  37. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  38. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  39. package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +15 -0
  40. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +37 -1
  41. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +37 -1
  42. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  43. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  44. package/dist/builtins/system-config/system-config.addon.js +1 -1
  45. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  46. package/dist/builtins/winston-logging/index.js +1 -1
  47. package/dist/builtins/winston-logging/index.mjs +1 -1
  48. package/dist/{dist-DWuNENzg.mjs → dist-CuAaqtdt.mjs} +996 -109
  49. package/dist/{dist-DiScsb8j.js → dist-D4nuaPdd.js} +1001 -108
  50. package/dist/index.js +38 -20
  51. package/dist/index.mjs +38 -20
  52. package/dist/kernel/addon-installer.d.ts +7 -15
  53. package/dist/kernel/config-manager.d.ts +32 -0
  54. package/package.json +1 -1
@@ -2353,19 +2353,6 @@ function toNodeId(idOrRunnerId) {
2353
2353
  return head === void 0 || head.length === 0 ? idOrRunnerId : head;
2354
2354
  }
2355
2355
  /**
2356
- * Generic types for capability definitions.
2357
- *
2358
- * A capability is defined with Zod schemas for methods, events, and settings.
2359
- * TypeScript types are inferred via z.infer<> — zero duplication.
2360
- *
2361
- * Pattern:
2362
- * 1. Define Zod schemas for data, methods, settings
2363
- * 2. Export const capabilityDef = { ... } satisfies CapabilityDefinition
2364
- * 3. Export type IProvider = InferProvider<typeof capabilityDef>
2365
- * 4. Addon implements IProvider
2366
- * 5. Registry auto-mounts tRPC router from definition.methods
2367
- */
2368
- /**
2369
2356
  * Resolve the EFFECTIVE mount hint for a cap — the explicit `mount` when
2370
2357
  * present, else the scope/mode/deviceNative-derived default. Single source
2371
2358
  * of truth shared by the runtime builder and any codegen that needs the
@@ -7501,7 +7488,14 @@ var cameraStreamsCapability = {
7501
7488
  low: zod.z.string().optional()
7502
7489
  }),
7503
7490
  lastChangedAt: zod.z.number()
7504
- })
7491
+ }),
7492
+ /**
7493
+ * Runtime-state durability: **session** — a restored `slotStatuses: streaming` for a camera that has been dark for two hours is a lie the UI renders as truth.
7494
+ *
7495
+ * See `RuntimeStateDurability`. Enforced by
7496
+ * `scripts/check-runtime-state-durability.ts`.
7497
+ */
7498
+ durability: "session"
7505
7499
  };
7506
7500
  /** `z.void()` — input carries no data. */
7507
7501
  function isVoidInput(schema) {
@@ -8494,6 +8488,13 @@ var deviceDiscoveryCapability = {
8494
8488
  kind: "poll"
8495
8489
  },
8496
8490
  runtimeState: DeviceDiscoveryStatusSchema.extend({ lastFetchedAt: zod.z.number().int().nonnegative() }),
8491
+ /**
8492
+ * Runtime-state durability: **session** — 5.7 KB of scan output on the largest device, fully re-derivable by re-scanning.
8493
+ *
8494
+ * See `RuntimeStateDurability`. Enforced by
8495
+ * `scripts/check-runtime-state-durability.ts`.
8496
+ */
8497
+ durability: "session",
8497
8498
  methods: {
8498
8499
  /**
8499
8500
  * Snapshot of the current `discovered` list. Returns the
@@ -11094,7 +11095,23 @@ var NotificationActionSchema = zod.z.object({
11094
11095
  * else — see `notification-center/action-token.ts` for what that does and
11095
11096
  * does not buy.
11096
11097
  */
11097
- destructive: zod.z.boolean().optional()
11098
+ destructive: zod.z.boolean().optional(),
11099
+ /**
11100
+ * How the tap should REACH the url.
11101
+ *
11102
+ * `navigate` (absent, and every button authored before this field) opens it:
11103
+ * the phone leaves the notification and shows whatever the callback returns.
11104
+ * That is right for a button whose answer the operator wants to read.
11105
+ *
11106
+ * `background` fires it as a POST and stays put. It exists for the buttons
11107
+ * whose whole point is not to interrupt — "silence this for 30 minutes" is
11108
+ * an answer to the notification, and being thrown into a browser tab to
11109
+ * confirm it costs more attention than the notification did. A backend that
11110
+ * cannot do a background call renders it as an ordinary link (the adapters
11111
+ * fall back rather than dropping the button), so this is a preference, never
11112
+ * a requirement.
11113
+ */
11114
+ mode: zod.z.enum(["navigate", "background"]).optional()
11098
11115
  });
11099
11116
  /**
11100
11117
  * The canonical notification. `body` is the only hard field (Apprise model).
@@ -11962,7 +11979,17 @@ var alarmPanelCapability = {
11962
11979
  * full slice; renders an arm button per `availableModes` entry and
11963
11980
  * a PIN field iff `requiresCode === true`.
11964
11981
  */
11965
- runtimeState: AlarmPanelStatusSchema
11982
+ runtimeState: AlarmPanelStatusSchema,
11983
+ /**
11984
+ * Runtime-state durability: **restored** — armed state is the one thing a panel must not lose across a restart.
11985
+ *
11986
+ * See `RuntimeStateDurability`. Enforced by
11987
+ * `scripts/check-runtime-state-durability.ts`.
11988
+ */
11989
+ durability: "restored",
11990
+ /** Clock fields: written, but excluded from the compare that decides
11991
+ * whether persisting is worth a SQLite commit. */
11992
+ volatileStateFields: ["lastChangedAt"]
11966
11993
  };
11967
11994
  /**
11968
11995
  * Shared geometry vocabulary for on-frame shape caps — privacy-mask,
@@ -12141,6 +12168,9 @@ var NcSystemEventConditionSchema = zod.z.object({
12141
12168
  nodeIds: zod.z.array(zod.z.string().min(1)).min(1).optional(),
12142
12169
  packageNames: zod.z.array(zod.z.string().min(1)).min(1).optional()
12143
12170
  });
12171
+ /** Hard ceiling on a window (24h). A snooze that could not expire would be an
12172
+ * outage the operator asked for once and forgot. */
12173
+ var NC_SNOOZE_MAX_MINUTES = 1440;
12144
12174
  /** One weekly activation window. `startMinute > endMinute` crosses midnight. */
12145
12175
  var NcScheduleWindowSchema = zod.z.object({
12146
12176
  /** Days of week the window STARTS on (0 = Sunday … 6 = Saturday). */
@@ -12530,15 +12560,15 @@ var NcConditionsSchema = zod.z.object({
12530
12560
  * (an `immediate` rule naming an `audio-*` class, one notification per
12531
12561
  * classified sample) stays exactly as it was for rules that already use it.
12532
12562
  *
12533
- * NOT in {@link NC_CONDITION_CATALOG} yet, and that is the sequencing rule
12534
- * rather than an oversight: the viewer mirrors the descriptor enums BY HAND
12535
- * (`camstack/src/data/notification-center.ts`, guarded by
12536
- * `scripts/check-viewer-condition-mirror.ts`) and its rule editor STRIPS the
12563
+ * In {@link NC_CONDITION_CATALOG} since P2, and the ORDER it got there is the
12564
+ * rule rather than an accident: the viewer mirrors the descriptor enums BY
12565
+ * HAND (`camstack/src/data/notification-center.ts`, guarded by
12566
+ * `scripts/check-viewer-condition-mirror.ts`) and its rule editor strips the
12537
12567
  * condition fields it does not know when a rule is saved from the phone.
12538
12568
  * Publishing an editor for a condition the app cannot round-trip is how an
12539
- * operator loses a rule's conditions by opening it — so the descriptor, the
12540
- * admin widget and the viewer mirror land together (P2 + P3), and only then
12541
- * does an audio rule become authorable.
12569
+ * operator loses a rule's conditions by opening it — so the viewer mirror
12570
+ * (P3, shipped) went FIRST, and the descriptor an editor renders from
12571
+ * follows here.
12542
12572
  */
12543
12573
  audio: NcAudioConditionSchema.optional()
12544
12574
  });
@@ -12774,6 +12804,30 @@ var NcRuleInputSchema = zod.z.object({
12774
12804
  */
12775
12805
  snoozeAllowGlobal: zod.z.boolean().optional(),
12776
12806
  /**
12807
+ * The snooze durations THIS rule's notification offers as buttons, in
12808
+ * minutes.
12809
+ *
12810
+ * Three states, and all three are distinct — which is exactly why this is
12811
+ * `.optional()` and never `.default()`. A Zod default does not run on the
12812
+ * addon cap path (three production failures in one day), so a schema default
12813
+ * would collapse the first two:
12814
+ *
12815
+ * | value | meaning |
12816
+ * | --- | --- |
12817
+ * | absent | the operator never said ⇒ {@link NC_DEFAULT_SNOOZE_MINUTES} |
12818
+ * | `[]` | **no snooze buttons on this rule** — the explicit override |
12819
+ * | a list | these choices, de-duplicated and sorted, at most four |
12820
+ *
12821
+ * `.max(4)` because the notifier's own action budget is small (ntfy allows
12822
+ * three buttons in total) and a rule that spent it all on snooze choices
12823
+ * would push its own tap-through actions off the notification.
12824
+ *
12825
+ * An empty list is NOT an alarm exemption: a rule the alarm is about, or
12826
+ * that arms the panel, is exempt automatically and cannot be silenced by a
12827
+ * window from anywhere (D133).
12828
+ */
12829
+ snoozeOptions: zod.z.array(zod.z.number().int().min(1).max(NC_SNOOZE_MAX_MINUTES)).max(4).optional(),
12830
+ /**
12777
12831
  * Devices this rule ACTUATES — arm the alarm, open a gate, turn on a light.
12778
12832
  *
12779
12833
  * This is what makes the rule set the alarm's trigger set without the alarm
@@ -12873,6 +12927,7 @@ var NcConditionDescriptorSchema = zod.z.object({
12873
12927
  "device",
12874
12928
  "package",
12875
12929
  "occupancy",
12930
+ "audio",
12876
12931
  "system"
12877
12932
  ]),
12878
12933
  label: zod.z.string(),
@@ -12891,6 +12946,7 @@ var NcConditionDescriptorSchema = zod.z.object({
12891
12946
  "crossingSelect",
12892
12947
  "polygonDraw",
12893
12948
  "occupancy",
12949
+ "audio",
12894
12950
  "deviceState",
12895
12951
  "systemEvent"
12896
12952
  ]),
@@ -13042,7 +13098,20 @@ var NcSnoozeInputSchema = zod.z.object({
13042
13098
  ruleId: zod.z.string().optional(),
13043
13099
  /** Required when `scope: 'device'`. */
13044
13100
  deviceId: zod.z.number().int().optional(),
13045
- durationMinutes: zod.z.number().int().min(1).max(1440),
13101
+ /**
13102
+ * Narrow the window to these subject classes — "the cat, not the person".
13103
+ *
13104
+ * ORTHOGONAL to `scope`, deliberately, and absent means EVERY class: that is
13105
+ * what every window authored before this field meant, so no persisted row
13106
+ * changes meaning and no client has to learn anything to keep working.
13107
+ *
13108
+ * It is what makes the window's real key `(deviceId, classes[])` and lets it
13109
+ * cross rules (D133): the operator points at a camera and a kind of thing,
13110
+ * not at whichever of their four rules happened to produce the notification
13111
+ * they are dismissing.
13112
+ */
13113
+ classes: zod.z.array(zod.z.string().min(1)).min(1).optional(),
13114
+ durationMinutes: zod.z.number().int().min(1).max(NC_SNOOZE_MAX_MINUTES),
13046
13115
  /**
13047
13116
  * Silence this for EVERY recipient, not just the caller. Permission is
13048
13117
  * checked server-side (the rule's `snoozeAllowGlobal`, or admin for the
@@ -13067,6 +13136,10 @@ var NcSnoozeSchema = zod.z.object({
13067
13136
  scope: NcSnoozeScopeSchema,
13068
13137
  ruleId: zod.z.string().optional(),
13069
13138
  deviceId: zod.z.number().int().optional(),
13139
+ /** Subject classes this window covers. ABSENT = every class — see
13140
+ * {@link NcSnoozeInputSchema.shape.classes}. Lives in the JSON blob and has
13141
+ * no SQLite column: nothing queries a window by class. */
13142
+ classes: zod.z.array(zod.z.string().min(1)).min(1).optional(),
13070
13143
  startedAt: zod.z.number(),
13071
13144
  /** Exclusive: at exactly this instant the snooze is over. Expiry is a
13072
13145
  * COMPARISON, not a job — no sweeper can leave the operator silenced. */
@@ -15829,7 +15902,14 @@ var zonesCapability = {
15829
15902
  * handle. Slice shape is `{ zones: Zone[] }` so future extensions
15830
15903
  * (e.g. zone groupings) can sit alongside the polygon list.
15831
15904
  */
15832
- runtimeState: zod.z.object({ zones: zod.z.array(ZoneSchema).readonly() })
15905
+ runtimeState: zod.z.object({ zones: zod.z.array(ZoneSchema).readonly() }),
15906
+ /**
15907
+ * Runtime-state durability: **restored** — written only on operator mutation, so a camera that never had one has nothing to re-derive from. This is the slice `zone-mirror-hydration.ts` exists to paper over.
15908
+ *
15909
+ * See `RuntimeStateDurability`. Enforced by
15910
+ * `scripts/check-runtime-state-durability.ts`.
15911
+ */
15912
+ durability: "restored"
15833
15913
  };
15834
15914
  /**
15835
15915
  * A bounding box in NORMALIZED [0,1] frame coordinates for `getNativeCrop`. The
@@ -19823,7 +19903,17 @@ var airQualitySensorCapability = {
19823
19903
  schema: AirQualitySensorStatusSchema,
19824
19904
  kind: "push"
19825
19905
  },
19826
- runtimeState: AirQualitySensorStatusSchema
19906
+ runtimeState: AirQualitySensorStatusSchema,
19907
+ /**
19908
+ * Runtime-state durability: **restored** — as `numeric-sensor`.
19909
+ *
19910
+ * See `RuntimeStateDurability`. Enforced by
19911
+ * `scripts/check-runtime-state-durability.ts`.
19912
+ */
19913
+ durability: "restored",
19914
+ /** Clock fields: written, but excluded from the compare that decides
19915
+ * whether persisting is worth a SQLite commit. */
19916
+ volatileStateFields: ["lastFetchedAt"]
19827
19917
  };
19828
19918
  /**
19829
19919
  * Ambient illuminance reading in lux. Drives Home Assistant `sensor`
@@ -19855,7 +19945,17 @@ var ambientLightSensorCapability = {
19855
19945
  schema: AmbientLightSensorStatusSchema,
19856
19946
  kind: "push"
19857
19947
  },
19858
- runtimeState: AmbientLightSensorStatusSchema
19948
+ runtimeState: AmbientLightSensorStatusSchema,
19949
+ /**
19950
+ * Runtime-state durability: **restored** — as `numeric-sensor`.
19951
+ *
19952
+ * See `RuntimeStateDurability`. Enforced by
19953
+ * `scripts/check-runtime-state-durability.ts`.
19954
+ */
19955
+ durability: "restored",
19956
+ /** Clock fields: written, but excluded from the compare that decides
19957
+ * whether persisting is worth a SQLite commit. */
19958
+ volatileStateFields: ["lastFetchedAt"]
19859
19959
  };
19860
19960
  /**
19861
19961
  * Per-class audio metrics aggregated over a sliding window.
@@ -19982,7 +20082,14 @@ var audioMetricsCapability = {
19982
20082
  }), AudioMetricsHistorySchema)
19983
20083
  },
19984
20084
  /** Reactive runtime-state mirror — live `device.state.audioMetrics.value`. */
19985
- runtimeState: AudioMetricsSnapshotSchema
20085
+ runtimeState: AudioMetricsSnapshotSchema,
20086
+ /**
20087
+ * Runtime-state durability: **session** — 1 Hz per camera at the mirror and ~63 % of the fleet's whole runtime-state write rate. `avgDbfs` is a rolling 60 s mean that genuinely moves every second, so no equality fix reclaims it — and a two-hour-old dB reading rendered as current is worse than no reading.
20088
+ *
20089
+ * See `RuntimeStateDurability`. Enforced by
20090
+ * `scripts/check-runtime-state-durability.ts`.
20091
+ */
20092
+ durability: "session"
19986
20093
  };
19987
20094
  /**
19988
20095
  * Automation-control cap. Models HA `automation.*` entities on
@@ -20044,7 +20151,14 @@ var automationControlCapability = {
20044
20151
  * reads `enabled` (toggle) + `isRunning` (spinner) + `lastError`
20045
20152
  * (badge) directly.
20046
20153
  */
20047
- runtimeState: AutomationControlStatusSchema
20154
+ runtimeState: AutomationControlStatusSchema,
20155
+ /**
20156
+ * Runtime-state durability: **session** — the authority for an automation being enabled is the automation store; a restored `isRunning` would be a lie. D62: one authority per switch.
20157
+ *
20158
+ * See `RuntimeStateDurability`. Enforced by
20159
+ * `scripts/check-runtime-state-durability.ts`.
20160
+ */
20161
+ durability: "session"
20048
20162
  };
20049
20163
  /**
20050
20164
  * Battery status snapshot. Emitted by providers whose device is
@@ -20150,7 +20264,17 @@ onStatusChanged: { data: zod.z.object({
20150
20264
  * via `device.runtimeState.getCapState('battery')` regardless of
20151
20265
  * the underlying driver.
20152
20266
  */
20153
- runtimeState: BatteryStatusSchema
20267
+ runtimeState: BatteryStatusSchema,
20268
+ /**
20269
+ * Runtime-state durability: **restored** — a sleeping battery camera may not report for hours; the restored percentage is the only thing the UI and the sleep gate have. Zero churn once `lastUpdated` is excluded — 526 writes, 0 value changes, in 25 minutes.
20270
+ *
20271
+ * See `RuntimeStateDurability`. Enforced by
20272
+ * `scripts/check-runtime-state-durability.ts`.
20273
+ */
20274
+ durability: "restored",
20275
+ /** Clock fields: written, but excluded from the compare that decides
20276
+ * whether persisting is worth a SQLite commit. */
20277
+ volatileStateFields: ["lastUpdated"]
20154
20278
  };
20155
20279
  /**
20156
20280
  * Generic boolean sensor — last-resort fallback when no domain-
@@ -20179,7 +20303,17 @@ var binaryCapability = {
20179
20303
  schema: BinaryStatusSchema,
20180
20304
  kind: "push"
20181
20305
  },
20182
- runtimeState: BinaryStatusSchema
20306
+ runtimeState: BinaryStatusSchema,
20307
+ /**
20308
+ * Runtime-state durability: **restored** — transition-driven sensor state; the restored value gives the boot comparison.
20309
+ *
20310
+ * See `RuntimeStateDurability`. Enforced by
20311
+ * `scripts/check-runtime-state-durability.ts`.
20312
+ */
20313
+ durability: "restored",
20314
+ /** Clock fields: written, but excluded from the compare that decides
20315
+ * whether persisting is worth a SQLite commit. */
20316
+ volatileStateFields: ["lastChangedAt"]
20183
20317
  };
20184
20318
  /**
20185
20319
  * Dimmable-light brightness control. Co-exists with `switch` on the
@@ -20232,7 +20366,14 @@ onBrightnessChanged: { data: zod.z.object({
20232
20366
  * by the kernel. Read via `device.state.brightness.value` so UI
20233
20367
  * sliders surface the current level without polling the provider.
20234
20368
  */
20235
- runtimeState: BrightnessStatusSchema
20369
+ runtimeState: BrightnessStatusSchema,
20370
+ /**
20371
+ * Runtime-state durability: **session** — live lamp state, re-published by the provider on connect.
20372
+ *
20373
+ * See `RuntimeStateDurability`. Enforced by
20374
+ * `scripts/check-runtime-state-durability.ts`.
20375
+ */
20376
+ durability: "session"
20236
20377
  };
20237
20378
  /**
20238
20379
  * button — device-scoped capability for HA `button.*` / `input_button.*`
@@ -20361,7 +20502,17 @@ var carbonMonoxideCapability = {
20361
20502
  schema: CarbonMonoxideStatusSchema,
20362
20503
  kind: "push"
20363
20504
  },
20364
- runtimeState: CarbonMonoxideStatusSchema
20505
+ runtimeState: CarbonMonoxideStatusSchema,
20506
+ /**
20507
+ * Runtime-state durability: **restored** — as `smoke`.
20508
+ *
20509
+ * See `RuntimeStateDurability`. Enforced by
20510
+ * `scripts/check-runtime-state-durability.ts`.
20511
+ */
20512
+ durability: "restored",
20513
+ /** Clock fields: written, but excluded from the compare that decides
20514
+ * whether persisting is worth a SQLite commit. */
20515
+ volatileStateFields: ["lastChangedAt"]
20365
20516
  };
20366
20517
  /**
20367
20518
  * HVAC / climate control cap. Models the full surface of a HA
@@ -20521,7 +20672,14 @@ var climateControlCapability = {
20521
20672
  * the full slice via `device.state.climate-control.value` and refresh
20522
20673
  * on every push without re-querying the provider.
20523
20674
  */
20524
- runtimeState: ClimateControlStatusSchema
20675
+ runtimeState: ClimateControlStatusSchema,
20676
+ /**
20677
+ * Runtime-state durability: **session** — as `brightness`; `currentTemp` moves continuously and is re-published on connect.
20678
+ *
20679
+ * See `RuntimeStateDurability`. Enforced by
20680
+ * `scripts/check-runtime-state-durability.ts`.
20681
+ */
20682
+ durability: "session"
20525
20683
  };
20526
20684
  /**
20527
20685
  * Color-light cap. Coexists with `switch` (on/off) and `brightness`
@@ -20631,7 +20789,14 @@ onColorChanged: { data: zod.z.object({
20631
20789
  * kernel. Read via `device.state.color.value` so UI pickers surface
20632
20790
  * the current chromaticity without polling the provider.
20633
20791
  */
20634
- runtimeState: ColorStatusSchema
20792
+ runtimeState: ColorStatusSchema,
20793
+ /**
20794
+ * Runtime-state durability: **session** — as `brightness`.
20795
+ *
20796
+ * See `RuntimeStateDurability`. Enforced by
20797
+ * `scripts/check-runtime-state-durability.ts`.
20798
+ */
20799
+ durability: "session"
20635
20800
  };
20636
20801
  var ConnectionTestOutcomeSchema = zod.z.discriminatedUnion("outcome", [
20637
20802
  zod.z.object({
@@ -20697,7 +20862,17 @@ var connectivityCapability = {
20697
20862
  schema: ConnectivityStatusSchema,
20698
20863
  kind: "push"
20699
20864
  },
20700
- runtimeState: ConnectivityStatusSchema
20865
+ runtimeState: ConnectivityStatusSchema,
20866
+ /**
20867
+ * Runtime-state durability: **restored** — same shape and same argument as `device-status`, for links rather than devices.
20868
+ *
20869
+ * See `RuntimeStateDurability`. Enforced by
20870
+ * `scripts/check-runtime-state-durability.ts`.
20871
+ */
20872
+ durability: "restored",
20873
+ /** Clock fields: written, but excluded from the compare that decides
20874
+ * whether persisting is worth a SQLite commit. */
20875
+ volatileStateFields: ["lastChangedAt"]
20701
20876
  };
20702
20877
  /**
20703
20878
  * Generic device-consumables capability — surfaces a device's
@@ -20779,7 +20954,14 @@ reset: method(zod.z.object({
20779
20954
  }
20780
20955
  }
20781
20956
  },
20782
- runtimeState: ConsumablesStatusSchema.extend({ lastFetchedAt: zod.z.number() })
20957
+ runtimeState: ConsumablesStatusSchema.extend({ lastFetchedAt: zod.z.number() }),
20958
+ /**
20959
+ * Runtime-state durability: **session** — the authority is the appliance; the provider re-reads the whole item array on connect.
20960
+ *
20961
+ * See `RuntimeStateDurability`. Enforced by
20962
+ * `scripts/check-runtime-state-durability.ts`.
20963
+ */
20964
+ durability: "session"
20783
20965
  };
20784
20966
  /**
20785
20967
  * Door / window / opening / garage / valve contact sensor. Boolean
@@ -20810,7 +20992,17 @@ var contactCapability = {
20810
20992
  schema: ContactStatusSchema,
20811
20993
  kind: "push"
20812
20994
  },
20813
- runtimeState: ContactStatusSchema
20995
+ runtimeState: ContactStatusSchema,
20996
+ /**
20997
+ * Runtime-state durability: **restored** — a door left open across a restart must still read open.
20998
+ *
20999
+ * See `RuntimeStateDurability`. Enforced by
21000
+ * `scripts/check-runtime-state-durability.ts`.
21001
+ */
21002
+ durability: "restored",
21003
+ /** Clock fields: written, but excluded from the compare that decides
21004
+ * whether persisting is worth a SQLite commit. */
21005
+ volatileStateFields: ["lastChangedAt"]
20814
21006
  };
20815
21007
  /**
20816
21008
  * Unified user-settable input cap. Models HA's `number` /
@@ -20940,7 +21132,14 @@ var controlCapability = {
20940
21132
  * dropdown / text field / date picker) read the slice's discriminant
20941
21133
  * and value directly without polling the provider.
20942
21134
  */
20943
- runtimeState: ControlStatusSchema
21135
+ runtimeState: ControlStatusSchema,
21136
+ /**
21137
+ * Runtime-state durability: **session** — a generic control mirrors an external entity that re-publishes on connect; the options array is re-derived with it.
21138
+ *
21139
+ * See `RuntimeStateDurability`. Enforced by
21140
+ * `scripts/check-runtime-state-durability.ts`.
21141
+ */
21142
+ durability: "session"
20944
21143
  };
20945
21144
  /**
20946
21145
  * Window covering / blinds / garage door / valve cap. Models HA
@@ -21023,7 +21222,17 @@ var coverCapability = {
21023
21222
  * Runtime-state slice — mirrored by the kernel. UI controls watch
21024
21223
  * the slice for live position changes during a move.
21025
21224
  */
21026
- runtimeState: CoverStatusSchema
21225
+ runtimeState: CoverStatusSchema,
21226
+ /**
21227
+ * Runtime-state durability: **restored** — position survives a restart on the device; the mirror should agree at boot rather than read blank.
21228
+ *
21229
+ * See `RuntimeStateDurability`. Enforced by
21230
+ * `scripts/check-runtime-state-durability.ts`.
21231
+ */
21232
+ durability: "restored",
21233
+ /** Clock fields: written, but excluded from the compare that decides
21234
+ * whether persisting is worth a SQLite commit. */
21235
+ volatileStateFields: ["lastChangedAt"]
21027
21236
  };
21028
21237
  /**
21029
21238
  * Vendor-neutral day/night (IR-cut) control — the per-camera config cap
@@ -21117,7 +21326,17 @@ var dayNightCapability = {
21117
21326
  schema: DayNightStatusSchema,
21118
21327
  kind: "poll"
21119
21328
  },
21120
- runtimeState: DayNightStatusSchema
21329
+ runtimeState: DayNightStatusSchema,
21330
+ /**
21331
+ * Runtime-state durability: **restored** — operator-set IR-cut behaviour; mutation-driven.
21332
+ *
21333
+ * See `RuntimeStateDurability`. Enforced by
21334
+ * `scripts/check-runtime-state-durability.ts`.
21335
+ */
21336
+ durability: "restored",
21337
+ /** Clock fields: written, but excluded from the compare that decides
21338
+ * whether persisting is worth a SQLite commit. */
21339
+ volatileStateFields: ["lastFetchedAt"]
21121
21340
  };
21122
21341
  /**
21123
21342
  * Generic device-level status snapshot. Auto-registered by `BaseDevice`
@@ -21164,7 +21383,17 @@ onStatusChanged: { data: zod.z.object({
21164
21383
  schema: DeviceStatusSchema,
21165
21384
  kind: "push"
21166
21385
  },
21167
- runtimeState: DeviceStatusSchema
21386
+ runtimeState: DeviceStatusSchema,
21387
+ /**
21388
+ * Runtime-state durability: **restored** — the previous observation is what makes the first reading after a restart a COMPARISON instead of a phantom transition (D130). 32 real flips across 16 devices in 25 min — the busiest slice in the cold half.
21389
+ *
21390
+ * See `RuntimeStateDurability`. Enforced by
21391
+ * `scripts/check-runtime-state-durability.ts`.
21392
+ */
21393
+ durability: "restored",
21394
+ /** Clock fields: written, but excluded from the compare that decides
21395
+ * whether persisting is worth a SQLite commit. */
21396
+ volatileStateFields: ["lastChangedAt"]
21168
21397
  };
21169
21398
  /**
21170
21399
  * Doorbell button cap. Two kinds of providers coexist behind this cap
@@ -21226,7 +21455,14 @@ onPressed: { data: DoorbellPressEventSchema } },
21226
21455
  * `device.state.doorbell.value`. UIs can show "last ring 5m ago"
21227
21456
  * without subscribing.
21228
21457
  */
21229
- runtimeState: DoorbellStatusSchema
21458
+ runtimeState: DoorbellStatusSchema,
21459
+ /**
21460
+ * Runtime-state durability: **restored** — a monotonic accumulator: the slice IS the record. `lastPressedAt` is content here, not a clock, so it is deliberately NOT volatile.
21461
+ *
21462
+ * See `RuntimeStateDurability`. Enforced by
21463
+ * `scripts/check-runtime-state-durability.ts`.
21464
+ */
21465
+ durability: "restored"
21230
21466
  };
21231
21467
  /**
21232
21468
  * Enum-state sensor — a string value picked from a finite option set.
@@ -21266,7 +21502,17 @@ var enumSensorCapability = {
21266
21502
  schema: EnumSensorStatusSchema,
21267
21503
  kind: "push"
21268
21504
  },
21269
- runtimeState: EnumSensorStatusSchema
21505
+ runtimeState: EnumSensorStatusSchema,
21506
+ /**
21507
+ * Runtime-state durability: **restored** — as `numeric-sensor`; 80 devices.
21508
+ *
21509
+ * See `RuntimeStateDurability`. Enforced by
21510
+ * `scripts/check-runtime-state-durability.ts`.
21511
+ */
21512
+ durability: "restored",
21513
+ /** Clock fields: written, but excluded from the compare that decides
21514
+ * whether persisting is worth a SQLite commit. */
21515
+ volatileStateFields: ["lastFetchedAt"]
21270
21516
  };
21271
21517
  /**
21272
21518
  * Generic stateless event emitter. Installed on a `DeviceType.EventEmitter`
@@ -21302,7 +21548,14 @@ var eventEmitterCapability = {
21302
21548
  schema: EventEmitterStatusSchema,
21303
21549
  kind: "push"
21304
21550
  },
21305
- runtimeState: EventEmitterStatusSchema
21551
+ runtimeState: EventEmitterStatusSchema,
21552
+ /**
21553
+ * Runtime-state durability: **session** — `eventCountSinceStart` names its own scope.
21554
+ *
21555
+ * See `RuntimeStateDurability`. Enforced by
21556
+ * `scripts/check-runtime-state-durability.ts`.
21557
+ */
21558
+ durability: "session"
21306
21559
  };
21307
21560
  var EventItemSchema = zod.z.object({
21308
21561
  id: zod.z.string(),
@@ -21619,7 +21872,14 @@ var fanControlCapability = {
21619
21872
  * Runtime-state slice — mirrored by the kernel. UI fan speed
21620
21873
  * sliders read `percentage` for live updates.
21621
21874
  */
21622
- runtimeState: FanControlStatusSchema
21875
+ runtimeState: FanControlStatusSchema,
21876
+ /**
21877
+ * Runtime-state durability: **session** — as `brightness`.
21878
+ *
21879
+ * See `RuntimeStateDurability`. Enforced by
21880
+ * `scripts/check-runtime-state-durability.ts`.
21881
+ */
21882
+ durability: "session"
21623
21883
  };
21624
21884
  /**
21625
21885
  * Per-device feature/identity probe slice. Holds the runtime-resolved
@@ -21695,7 +21955,14 @@ onProbeChanged: { data: zod.z.object({
21695
21955
  schema: FeatureProbeStatusSchema,
21696
21956
  kind: "push"
21697
21957
  },
21698
- runtimeState: FeatureProbeStatusSchema
21958
+ runtimeState: FeatureProbeStatusSchema,
21959
+ /**
21960
+ * Runtime-state durability: **session** — per-session by definition — `lastProbedAt` means "this worker completed a probe THIS session", which is why the mirror seed already blanks it. Persisting it only creates something to blank.
21961
+ *
21962
+ * See `RuntimeStateDurability`. Enforced by
21963
+ * `scripts/check-runtime-state-durability.ts`.
21964
+ */
21965
+ durability: "session"
21699
21966
  };
21700
21967
  /**
21701
21968
  * Water leak / moisture sensor. Boolean "is liquid currently
@@ -21722,7 +21989,17 @@ var floodCapability = {
21722
21989
  schema: FloodStatusSchema,
21723
21990
  kind: "push"
21724
21991
  },
21725
- runtimeState: FloodStatusSchema
21992
+ runtimeState: FloodStatusSchema,
21993
+ /**
21994
+ * Runtime-state durability: **restored** — as `smoke`.
21995
+ *
21996
+ * See `RuntimeStateDurability`. Enforced by
21997
+ * `scripts/check-runtime-state-durability.ts`.
21998
+ */
21999
+ durability: "restored",
22000
+ /** Clock fields: written, but excluded from the compare that decides
22001
+ * whether persisting is worth a SQLite commit. */
22002
+ volatileStateFields: ["lastChangedAt"]
21726
22003
  };
21727
22004
  /**
21728
22005
  * Combustible-gas (LPG / methane / hydrogen) alarm sensor. Drives
@@ -21745,7 +22022,17 @@ var gasCapability = {
21745
22022
  schema: GasStatusSchema,
21746
22023
  kind: "push"
21747
22024
  },
21748
- runtimeState: GasStatusSchema
22025
+ runtimeState: GasStatusSchema,
22026
+ /**
22027
+ * Runtime-state durability: **restored** — as `smoke`.
22028
+ *
22029
+ * See `RuntimeStateDurability`. Enforced by
22030
+ * `scripts/check-runtime-state-durability.ts`.
22031
+ */
22032
+ durability: "restored",
22033
+ /** Clock fields: written, but excluded from the compare that decides
22034
+ * whether persisting is worth a SQLite commit. */
22035
+ volatileStateFields: ["lastChangedAt"]
21749
22036
  };
21750
22037
  /**
21751
22038
  * Humidifier / dehumidifier cap. Models HA `humidifier.*` entities —
@@ -21821,7 +22108,14 @@ var humidifierCapability = {
21821
22108
  * Runtime-state slice — mirrored by the kernel. UI controls watch the
21822
22109
  * slice for live humidity / mode changes.
21823
22110
  */
21824
- runtimeState: HumidifierStatusSchema
22111
+ runtimeState: HumidifierStatusSchema,
22112
+ /**
22113
+ * Runtime-state durability: **session** — as `climate-control`.
22114
+ *
22115
+ * See `RuntimeStateDurability`. Enforced by
22116
+ * `scripts/check-runtime-state-durability.ts`.
22117
+ */
22118
+ durability: "session"
21825
22119
  };
21826
22120
  /**
21827
22121
  * Single-metric humidity reading. Drives Home Assistant `sensor`
@@ -21857,7 +22151,17 @@ var humiditySensorCapability = {
21857
22151
  schema: HumiditySensorStatusSchema,
21858
22152
  kind: "push"
21859
22153
  },
21860
- runtimeState: HumiditySensorStatusSchema
22154
+ runtimeState: HumiditySensorStatusSchema,
22155
+ /**
22156
+ * Runtime-state durability: **restored** — as `numeric-sensor` (67 of 75 writes were the clock alone).
22157
+ *
22158
+ * See `RuntimeStateDurability`. Enforced by
22159
+ * `scripts/check-runtime-state-durability.ts`.
22160
+ */
22161
+ durability: "restored",
22162
+ /** Clock fields: written, but excluded from the compare that decides
22163
+ * whether persisting is worth a SQLite commit. */
22164
+ volatileStateFields: ["lastFetchedAt"]
21861
22165
  };
21862
22166
  /**
21863
22167
  * Image display cap. Models a single still image exposed by an integration —
@@ -21895,7 +22199,14 @@ var imageCapability = {
21895
22199
  * Runtime-state slice — mirrored by the kernel. The UI reads `url`
21896
22200
  * directly and renders the still image.
21897
22201
  */
21898
- runtimeState: ImageStatusSchema
22202
+ runtimeState: ImageStatusSchema,
22203
+ /**
22204
+ * Runtime-state durability: **session** — a snapshot URL is a session-scoped handle; a restored one points at nothing.
22205
+ *
22206
+ * See `RuntimeStateDurability`. Enforced by
22207
+ * `scripts/check-runtime-state-durability.ts`.
22208
+ */
22209
+ durability: "session"
21899
22210
  };
21900
22211
  /**
21901
22212
  * Vendor-neutral image / picture-adjustment cap — the per-camera config
@@ -22044,7 +22355,17 @@ var imageSettingsCapability = {
22044
22355
  schema: ImageSettingsStatusSchema,
22045
22356
  kind: "poll"
22046
22357
  },
22047
- runtimeState: ImageSettingsStatusSchema
22358
+ runtimeState: ImageSettingsStatusSchema,
22359
+ /**
22360
+ * Runtime-state durability: **restored** — operator-set camera imaging; mutation-driven.
22361
+ *
22362
+ * See `RuntimeStateDurability`. Enforced by
22363
+ * `scripts/check-runtime-state-durability.ts`.
22364
+ */
22365
+ durability: "restored",
22366
+ /** Clock fields: written, but excluded from the compare that decides
22367
+ * whether persisting is worth a SQLite commit. */
22368
+ volatileStateFields: ["lastFetchedAt"]
22048
22369
  };
22049
22370
  /**
22050
22371
  * integrations — system-scoped singleton capability for integration
@@ -22453,7 +22774,14 @@ var lawnMowerControlCapability = {
22453
22774
  * Runtime-state slice — mirrored by the kernel. UI controls watch the
22454
22775
  * slice for live activity + battery changes.
22455
22776
  */
22456
- runtimeState: LawnMowerControlStatusSchema
22777
+ runtimeState: LawnMowerControlStatusSchema,
22778
+ /**
22779
+ * Runtime-state durability: **session** — as `vacuum-control`.
22780
+ *
22781
+ * See `RuntimeStateDurability`. Enforced by
22782
+ * `scripts/check-runtime-state-durability.ts`.
22783
+ */
22784
+ durability: "session"
22457
22785
  };
22458
22786
  /**
22459
22787
  * local-network — hub-only singleton.
@@ -22756,7 +23084,17 @@ var lockControlCapability = {
22756
23084
  * read `state` and disable themselves during `locking`/`unlocking`
22757
23085
  * transitions.
22758
23086
  */
22759
- runtimeState: LockControlStatusSchema
23087
+ runtimeState: LockControlStatusSchema,
23088
+ /**
23089
+ * Runtime-state durability: **restored** — a lock left locked must still read locked.
23090
+ *
23091
+ * See `RuntimeStateDurability`. Enforced by
23092
+ * `scripts/check-runtime-state-durability.ts`.
23093
+ */
23094
+ durability: "restored",
23095
+ /** Clock fields: written, but excluded from the compare that decides
23096
+ * whether persisting is worth a SQLite commit. */
23097
+ volatileStateFields: ["lastChangedAt"]
22760
23098
  };
22761
23099
  /**
22762
23100
  * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
@@ -22918,7 +23256,14 @@ var mediaPlayerCapability = {
22918
23256
  * full slice for live now-playing, volume, and progress updates
22919
23257
  * without polling.
22920
23258
  */
22921
- runtimeState: MediaPlayerStatusSchema
23259
+ runtimeState: MediaPlayerStatusSchema,
23260
+ /**
23261
+ * Runtime-state durability: **session** — a restored transport position describes a playback that stopped when the hub did.
23262
+ *
23263
+ * See `RuntimeStateDurability`. Enforced by
23264
+ * `scripts/check-runtime-state-durability.ts`.
23265
+ */
23266
+ durability: "session"
22922
23267
  };
22923
23268
  /**
22924
23269
  * mesh-network — collection cap for mesh-VPN providers.
@@ -23243,7 +23588,14 @@ onMotionChanged: { data: MotionOnMotionChangedDataSchema } },
23243
23588
  * `device.state.motion.value`. Reads never invoke the provider, so
23244
23589
  * UIs and other addons can poll the cached state safely.
23245
23590
  */
23246
- runtimeState: MotionStatusSchema
23591
+ runtimeState: MotionStatusSchema,
23592
+ /**
23593
+ * Runtime-state durability: **session** — self-clearing by construction (`autoClearAfterMs`); a restored `detected: true` is a frozen event, and the next frame re-publishes the real one.
23594
+ *
23595
+ * See `RuntimeStateDurability`. Enforced by
23596
+ * `scripts/check-runtime-state-durability.ts`.
23597
+ */
23598
+ durability: "session"
23247
23599
  };
23248
23600
  /**
23249
23601
  * Motion-trigger toggle for accessory devices.
@@ -23308,7 +23660,14 @@ var motionTriggerCapability = {
23308
23660
  schema: MotionTriggerStatusSchema,
23309
23661
  kind: "command-driven"
23310
23662
  },
23311
- runtimeState: MotionTriggerRuntimeStateSchema
23663
+ runtimeState: MotionTriggerRuntimeStateSchema,
23664
+ /**
23665
+ * Runtime-state durability: **session** — the authority for motion-trigger enablement is the provider's own config; the slice is a mirror of it, re-published on connect.
23666
+ *
23667
+ * See `RuntimeStateDurability`. Enforced by
23668
+ * `scripts/check-runtime-state-durability.ts`.
23669
+ */
23670
+ durability: "session"
23312
23671
  };
23313
23672
  /**
23314
23673
  * Motion-zones share the same MaskShape vocabulary as privacy-mask — the
@@ -23375,7 +23734,17 @@ var motionZonesCapability = {
23375
23734
  schema: MotionZoneStatusSchema,
23376
23735
  kind: "poll"
23377
23736
  },
23378
- runtimeState: MotionZoneStatusSchema
23737
+ runtimeState: MotionZoneStatusSchema,
23738
+ /**
23739
+ * Runtime-state durability: **restored** — the 14 KB polygon list is the single largest slice on the fleet and has not changed since the operator drew it. Highest value per byte in the table.
23740
+ *
23741
+ * See `RuntimeStateDurability`. Enforced by
23742
+ * `scripts/check-runtime-state-durability.ts`.
23743
+ */
23744
+ durability: "restored",
23745
+ /** Clock fields: written, but excluded from the compare that decides
23746
+ * whether persisting is worth a SQLite commit. */
23747
+ volatileStateFields: ["lastFetchedAt"]
23379
23748
  };
23380
23749
  /**
23381
23750
  * On-camera AI object detection cap. Surfaces per-device the classes
@@ -23449,7 +23818,17 @@ var nativeObjectDetectionCapability = {
23449
23818
  schema: NativeObjectDetectionStatusSchema,
23450
23819
  kind: "push"
23451
23820
  },
23452
- runtimeState: NativeObjectDetectionRuntimeStateSchema
23821
+ runtimeState: NativeObjectDetectionRuntimeStateSchema,
23822
+ /**
23823
+ * Runtime-state durability: **restored** — `enabled` is an operator toggle on a camera whose refresh is a no-op and whose staleMs is Infinity. There is no hardware value to re-read — losing it loses the setting.
23824
+ *
23825
+ * See `RuntimeStateDurability`. Enforced by
23826
+ * `scripts/check-runtime-state-durability.ts`.
23827
+ */
23828
+ durability: "restored",
23829
+ /** Clock fields: written, but excluded from the compare that decides
23830
+ * whether persisting is worth a SQLite commit. */
23831
+ volatileStateFields: ["lastFetchedAt"]
23453
23832
  };
23454
23833
  /**
23455
23834
  * network-quality — system-scoped singleton capability tracking RTT,
@@ -23836,7 +24215,14 @@ onSent: { data: zod.z.object({
23836
24215
  * form reads `supports` to gate optional fields; history pane reads
23837
24216
  * `lastSentAt` / `lastError` / `queueDepth`.
23838
24217
  */
23839
- runtimeState: NotifierStatusSchema
24218
+ runtimeState: NotifierStatusSchema,
24219
+ /**
24220
+ * Runtime-state durability: **session** — live queue depth and last-send state; a restored queue depth describes a queue that no longer exists.
24221
+ *
24222
+ * See `RuntimeStateDurability`. Enforced by
24223
+ * `scripts/check-runtime-state-durability.ts`.
24224
+ */
24225
+ durability: "session"
23840
24226
  };
23841
24227
  /**
23842
24228
  * Generic numeric sensor — last-resort fallback when no typed numeric
@@ -23879,7 +24265,17 @@ var numericSensorCapability = {
23879
24265
  schema: NumericSensorStatusSchema,
23880
24266
  kind: "push"
23881
24267
  },
23882
- runtimeState: NumericSensorStatusSchema
24268
+ runtimeState: NumericSensorStatusSchema,
24269
+ /**
24270
+ * Runtime-state durability: **restored** — polled value, low churn once the clock is excluded (251 of 669 writes were the clock alone); restoring it removes the cold window before the first poll.
24271
+ *
24272
+ * See `RuntimeStateDurability`. Enforced by
24273
+ * `scripts/check-runtime-state-durability.ts`.
24274
+ */
24275
+ durability: "restored",
24276
+ /** Clock fields: written, but excluded from the compare that decides
24277
+ * whether persisting is worth a SQLite commit. */
24278
+ volatileStateFields: ["lastFetchedAt"]
23883
24279
  };
23884
24280
  /**
23885
24281
  * Generic on-screen-display (video overlay) cap. Each camera exposes
@@ -24358,7 +24754,14 @@ var petFeederCapability = {
24358
24754
  * the full slice via `device.state.petFeeder.value` and refresh on
24359
24755
  * every poll without re-querying the provider.
24360
24756
  */
24361
- runtimeState: PetFeederStatusSchema
24757
+ runtimeState: PetFeederStatusSchema,
24758
+ /**
24759
+ * Runtime-state durability: **session** — live appliance state re-published on connect.
24760
+ *
24761
+ * See `RuntimeStateDurability`. Enforced by
24762
+ * `scripts/check-runtime-state-durability.ts`.
24763
+ */
24764
+ durability: "session"
24362
24765
  };
24363
24766
  var VehicleSchema = zod.z.object({
24364
24767
  id: zod.z.string(),
@@ -24715,7 +25118,17 @@ var powerMeterCapability = {
24715
25118
  schema: PowerMeterStatusSchema,
24716
25119
  kind: "push"
24717
25120
  },
24718
- runtimeState: PowerMeterStatusSchema
25121
+ runtimeState: PowerMeterStatusSchema,
25122
+ /**
25123
+ * Runtime-state durability: **restored** — as `numeric-sensor`; `kwhTotal` is an accumulator whose restored value is the baseline.
25124
+ *
25125
+ * See `RuntimeStateDurability`. Enforced by
25126
+ * `scripts/check-runtime-state-durability.ts`.
25127
+ */
25128
+ durability: "restored",
25129
+ /** Clock fields: written, but excluded from the compare that decides
25130
+ * whether persisting is worth a SQLite commit. */
25131
+ volatileStateFields: ["lastFetchedAt"]
24719
25132
  };
24720
25133
  /**
24721
25134
  * Presence cap. Models HA `person.*` and `device_tracker.*` entities
@@ -24772,7 +25185,17 @@ var presenceCapability = {
24772
25185
  * the map pin is rendered (use `DeviceFeature.PresenceGps` for the
24773
25186
  * pre-fetch fast-path check).
24774
25187
  */
24775
- runtimeState: PresenceStatusSchema
25188
+ runtimeState: PresenceStatusSchema,
25189
+ /**
25190
+ * Runtime-state durability: **restored** — occupancy-relevant: the restored state is what an occupancy rule compares the first post-restart observation against.
25191
+ *
25192
+ * See `RuntimeStateDurability`. Enforced by
25193
+ * `scripts/check-runtime-state-durability.ts`.
25194
+ */
25195
+ durability: "restored",
25196
+ /** Clock fields: written, but excluded from the compare that decides
25197
+ * whether persisting is worth a SQLite commit. */
25198
+ volatileStateFields: ["lastChangedAt"]
24776
25199
  };
24777
25200
  /**
24778
25201
  * Atmospheric pressure reading in hectopascals. Drives Home Assistant
@@ -24808,7 +25231,17 @@ var pressureSensorCapability = {
24808
25231
  schema: PressureSensorStatusSchema,
24809
25232
  kind: "push"
24810
25233
  },
24811
- runtimeState: PressureSensorStatusSchema
25234
+ runtimeState: PressureSensorStatusSchema,
25235
+ /**
25236
+ * Runtime-state durability: **restored** — as `numeric-sensor`.
25237
+ *
25238
+ * See `RuntimeStateDurability`. Enforced by
25239
+ * `scripts/check-runtime-state-durability.ts`.
25240
+ */
25241
+ durability: "restored",
25242
+ /** Clock fields: written, but excluded from the compare that decides
25243
+ * whether persisting is worth a SQLite commit. */
25244
+ volatileStateFields: ["lastFetchedAt"]
24812
25245
  };
24813
25246
  /**
24814
25247
  * PRIVACY — what the camera deliberately does not capture. Two planes:
@@ -24938,7 +25371,17 @@ var privacyMaskCapability = {
24938
25371
  schema: PrivacyMaskStatusSchema,
24939
25372
  kind: "poll"
24940
25373
  },
24941
- runtimeState: PrivacyMaskStatusSchema
25374
+ runtimeState: PrivacyMaskStatusSchema,
25375
+ /**
25376
+ * Runtime-state durability: **restored** — operator-drawn regions, zero real churn — 22 writes in 25 minutes, every one of them the clock.
25377
+ *
25378
+ * See `RuntimeStateDurability`. Enforced by
25379
+ * `scripts/check-runtime-state-durability.ts`.
25380
+ */
25381
+ durability: "restored",
25382
+ /** Clock fields: written, but excluded from the compare that decides
25383
+ * whether persisting is worth a SQLite commit. */
25384
+ volatileStateFields: ["lastFetchedAt"]
24942
25385
  };
24943
25386
  var PtzPresetSchema = zod.z.object({
24944
25387
  id: zod.z.string(),
@@ -25181,7 +25624,14 @@ var ptzAutotrackCapability = {
25181
25624
  * fetch / cache / fallback logic out of the four cap methods —
25182
25625
  * they become trampolines over `runtimeState`.
25183
25626
  */
25184
- runtimeState: PtzAutotrackRuntimeStateSchema
25627
+ runtimeState: PtzAutotrackRuntimeStateSchema,
25628
+ /**
25629
+ * Runtime-state durability: **session** — mirrors the camera's own autotrack config, re-read on connect.
25630
+ *
25631
+ * See `RuntimeStateDurability`. Enforced by
25632
+ * `scripts/check-runtime-state-durability.ts`.
25633
+ */
25634
+ durability: "session"
25185
25635
  };
25186
25636
  /**
25187
25637
  * reboot — device-scoped capability for "soft" device reboots (firmware
@@ -25651,13 +26101,24 @@ var recordingCapability = {
25651
26101
  /** Playback-speed multiplier for the render (1 = realtime). */
25652
26102
  var ExportSpeedSchema = zod.z.number().min(.25).max(32);
25653
26103
  /**
25654
- * One dense interval, in SECONDS FROM THE EXPORT'S OWN `fromMs`.
26104
+ * One dense interval, in WALL-CLOCK SECONDS FROM THE EXPORT'S OWN `fromMs`.
26105
+ *
26106
+ * **Wall clock, not ffmpeg's `t`** — and the recorder translates. A caller
26107
+ * derives these bounds from things that happened at a TIME (a track's
26108
+ * `firstSeen`), while `t` runs over the source playlist: the concatenation of
26109
+ * every segment present for the range, with each recording GAP removed. The
26110
+ * two agree only on a window that recorded without one interruption, and only
26111
+ * the render side knows the segments, so the translation lives there
26112
+ * (`export-dense-map.ts`, addon-pipeline).
26113
+ *
26114
+ * It was not always so. These seconds were fed to `between(t,…)` verbatim, and
26115
+ * on a 10 h window holding 29,393 s of footage every range landed late by the
26116
+ * gap accumulated before it — up to 6,607 s, well past EOF. Nothing matched,
26117
+ * the video was a uniform timelapse, and the log line reported the five ranges
26118
+ * that had been ASKED for (2026-08-13, export `57d14363`, camera 615).
25655
26119
  *
25656
- * Relative and not absolute epoch on purpose: the renderer's frame-select
25657
- * expression sees ffmpeg's `t`, which starts at 0 for the export's source
25658
- * playlist. Handing it absolute epochs would make every call site responsible
25659
- * for the same subtraction, and the one that forgot would emit a filter that
25660
- * selects nothing — silently, as a uniform timelapse.
26120
+ * Relative and not absolute epoch, because an absolute epoch would make every
26121
+ * call site responsible for the same subtraction.
25661
26122
  */
25662
26123
  var ExportDenseRangeSchema = zod.z.object({
25663
26124
  fromSec: zod.z.number().nonnegative(),
@@ -25978,7 +26439,14 @@ var sceneMonitorCapability = {
25978
26439
  schema: SceneMonitorStatusSchema,
25979
26440
  kind: "push"
25980
26441
  },
25981
- runtimeState: SceneMonitorStatusSchema
26442
+ runtimeState: SceneMonitorStatusSchema,
26443
+ /**
26444
+ * Runtime-state durability: **session** — re-derived from the current scene on the next evaluation.
26445
+ *
26446
+ * See `RuntimeStateDurability`. Enforced by
26447
+ * `scripts/check-runtime-state-durability.ts`.
26448
+ */
26449
+ durability: "session"
25982
26450
  };
25983
26451
  /**
25984
26452
  * Per-stage gating mode applied to the zones a rule references.
@@ -26122,7 +26590,14 @@ var scriptRunnerCapability = {
26122
26590
  * `isRunning` to render a spinner during execution and surfaces
26123
26591
  * `lastError` / `lastRunSuccess` in the recent-runs panel.
26124
26592
  */
26125
- runtimeState: ScriptRunnerStatusSchema
26593
+ runtimeState: ScriptRunnerStatusSchema,
26594
+ /**
26595
+ * Runtime-state durability: **session** — a restored `isRunning: true` describes a process that died with the previous hub.
26596
+ *
26597
+ * See `RuntimeStateDurability`. Enforced by
26598
+ * `scripts/check-runtime-state-durability.ts`.
26599
+ */
26600
+ durability: "session"
26126
26601
  };
26127
26602
  /**
26128
26603
  * Smoke alarm sensor — boolean "is smoke currently detected" with
@@ -26149,7 +26624,17 @@ var smokeCapability = {
26149
26624
  schema: SmokeStatusSchema,
26150
26625
  kind: "push"
26151
26626
  },
26152
- runtimeState: SmokeStatusSchema
26627
+ runtimeState: SmokeStatusSchema,
26628
+ /**
26629
+ * Runtime-state durability: **restored** — a safety sensor must not read "clear" merely because the hub restarted.
26630
+ *
26631
+ * See `RuntimeStateDurability`. Enforced by
26632
+ * `scripts/check-runtime-state-durability.ts`.
26633
+ */
26634
+ durability: "restored",
26635
+ /** Clock fields: written, but excluded from the compare that decides
26636
+ * whether persisting is worth a SQLite commit. */
26637
+ volatileStateFields: ["lastChangedAt"]
26153
26638
  };
26154
26639
  /**
26155
26640
  * One publishable camera stream as its OWNING PROVIDER describes it — the same
@@ -26335,7 +26820,17 @@ var streamParamsCapability = {
26335
26820
  schema: StreamParamsStatusSchema,
26336
26821
  kind: "poll"
26337
26822
  },
26338
- runtimeState: StreamParamsStatusSchema
26823
+ runtimeState: StreamParamsStatusSchema,
26824
+ /**
26825
+ * Runtime-state durability: **restored** — operator-set encoder profile; mutation-driven.
26826
+ *
26827
+ * See `RuntimeStateDurability`. Enforced by
26828
+ * `scripts/check-runtime-state-durability.ts`.
26829
+ */
26830
+ durability: "restored",
26831
+ /** Clock fields: written, but excluded from the compare that decides
26832
+ * whether persisting is worth a SQLite commit. */
26833
+ volatileStateFields: ["lastFetchedAt"]
26339
26834
  };
26340
26835
  /**
26341
26836
  * The three well-known stream profiles in render order. Exported so the
@@ -26638,6 +27133,16 @@ var switchCapability = {
26638
27133
  * not need to re-query the provider after a setState mutation.
26639
27134
  */
26640
27135
  runtimeState: SwitchStatusSchema,
27136
+ /**
27137
+ * Runtime-state durability: **restored** — device state an operator reads as authoritative; 55 devices, transition-driven.
27138
+ *
27139
+ * See `RuntimeStateDurability`. Enforced by
27140
+ * `scripts/check-runtime-state-durability.ts`.
27141
+ */
27142
+ durability: "restored",
27143
+ /** Clock fields: written, but excluded from the compare that decides
27144
+ * whether persisting is worth a SQLite commit. */
27145
+ volatileStateFields: ["lastChangedAt"],
26641
27146
  settings: { bindings: [{
26642
27147
  kind: "scalar",
26643
27148
  statusPath: "on",
@@ -26732,7 +27237,17 @@ var tamperCapability = {
26732
27237
  schema: TamperStatusSchema,
26733
27238
  kind: "push"
26734
27239
  },
26735
- runtimeState: TamperStatusSchema
27240
+ runtimeState: TamperStatusSchema,
27241
+ /**
27242
+ * Runtime-state durability: **restored** — as `smoke`.
27243
+ *
27244
+ * See `RuntimeStateDurability`. Enforced by
27245
+ * `scripts/check-runtime-state-durability.ts`.
27246
+ */
27247
+ durability: "restored",
27248
+ /** Clock fields: written, but excluded from the compare that decides
27249
+ * whether persisting is worth a SQLite commit. */
27250
+ volatileStateFields: ["lastChangedAt"]
26736
27251
  };
26737
27252
  /**
26738
27253
  * Single-metric temperature reading. Drives Home Assistant `sensor`
@@ -26777,7 +27292,17 @@ var temperatureSensorCapability = {
26777
27292
  schema: TemperatureSensorStatusSchema,
26778
27293
  kind: "push"
26779
27294
  },
26780
- runtimeState: TemperatureSensorStatusSchema
27295
+ runtimeState: TemperatureSensorStatusSchema,
27296
+ /**
27297
+ * Runtime-state durability: **restored** — as `numeric-sensor` (69 of 125 writes were the clock alone).
27298
+ *
27299
+ * See `RuntimeStateDurability`. Enforced by
27300
+ * `scripts/check-runtime-state-durability.ts`.
27301
+ */
27302
+ durability: "restored",
27303
+ /** Clock fields: written, but excluded from the compare that decides
27304
+ * whether persisting is worth a SQLite commit. */
27305
+ volatileStateFields: ["lastFetchedAt"]
26781
27306
  };
26782
27307
  /**
26783
27308
  * toast — system-scoped singleton capability that streams toast
@@ -26853,7 +27378,14 @@ var updateCapability = {
26853
27378
  schema: UpdateStatusSchema,
26854
27379
  kind: "poll"
26855
27380
  },
26856
- runtimeState: UpdateStatusSchema
27381
+ runtimeState: UpdateStatusSchema,
27382
+ /**
27383
+ * Runtime-state durability: **session** — a restored `inProgress: true` describes an update that is no longer running; versions are re-probed at boot.
27384
+ *
27385
+ * See `RuntimeStateDurability`. Enforced by
27386
+ * `scripts/check-runtime-state-durability.ts`.
27387
+ */
27388
+ durability: "session"
26857
27389
  };
26858
27390
  var UserSummarySchema = zod.z.object({
26859
27391
  id: zod.z.string(),
@@ -27229,7 +27761,14 @@ var vacuumControlCapability = {
27229
27761
  * Runtime-state slice — mirrored by the kernel. UI controls watch the
27230
27762
  * slice for live state + battery + fan-speed changes.
27231
27763
  */
27232
- runtimeState: VacuumControlStatusSchema
27764
+ runtimeState: VacuumControlStatusSchema,
27765
+ /**
27766
+ * Runtime-state durability: **session** — as `media-player` — a restored `state: cleaning` is a robot that is not cleaning.
27767
+ *
27768
+ * See `RuntimeStateDurability`. Enforced by
27769
+ * `scripts/check-runtime-state-durability.ts`.
27770
+ */
27771
+ durability: "session"
27233
27772
  };
27234
27773
  /**
27235
27774
  * Pipe / water / gas valve cap. Models HA `valve.*` entities — anything
@@ -27299,7 +27838,14 @@ var valveCapability = {
27299
27838
  * Runtime-state slice — mirrored by the kernel. UI controls watch the
27300
27839
  * slice for live position changes during a move.
27301
27840
  */
27302
- runtimeState: ValveStatusSchema
27841
+ runtimeState: ValveStatusSchema,
27842
+ /**
27843
+ * Runtime-state durability: **session** — as `brightness`.
27844
+ *
27845
+ * See `RuntimeStateDurability`. Enforced by
27846
+ * `scripts/check-runtime-state-durability.ts`.
27847
+ */
27848
+ durability: "session"
27303
27849
  };
27304
27850
  /**
27305
27851
  * Vibration / shake / impact sensor. Drives Home Assistant
@@ -27321,7 +27867,17 @@ var vibrationCapability = {
27321
27867
  schema: VibrationStatusSchema,
27322
27868
  kind: "push"
27323
27869
  },
27324
- runtimeState: VibrationStatusSchema
27870
+ runtimeState: VibrationStatusSchema,
27871
+ /**
27872
+ * Runtime-state durability: **restored** — as `smoke`.
27873
+ *
27874
+ * See `RuntimeStateDurability`. Enforced by
27875
+ * `scripts/check-runtime-state-durability.ts`.
27876
+ */
27877
+ durability: "restored",
27878
+ /** Clock fields: written, but excluded from the compare that decides
27879
+ * whether persisting is worth a SQLite commit. */
27880
+ volatileStateFields: ["lastChangedAt"]
27325
27881
  };
27326
27882
  /**
27327
27883
  * Water heater / boiler cap. Models HA `water_heater.*` entities — a
@@ -27395,7 +27951,14 @@ var waterHeaterCapability = {
27395
27951
  * Runtime-state slice — mirrored by the kernel. UI controls watch the
27396
27952
  * slice for live temperature / mode / away changes.
27397
27953
  */
27398
- runtimeState: WaterHeaterStatusSchema
27954
+ runtimeState: WaterHeaterStatusSchema,
27955
+ /**
27956
+ * Runtime-state durability: **session** — as `climate-control`.
27957
+ *
27958
+ * See `RuntimeStateDurability`. Enforced by
27959
+ * `scripts/check-runtime-state-durability.ts`.
27960
+ */
27961
+ durability: "session"
27399
27962
  };
27400
27963
  /**
27401
27964
  * Weather provider cap. Models HA `weather.*` entities — a read-only
@@ -27454,7 +28017,14 @@ var weatherCapability = {
27454
28017
  * Runtime-state slice — mirrored by the kernel. The UI reads the
27455
28018
  * current conditions directly from the slice on each weather push.
27456
28019
  */
27457
- runtimeState: WeatherStatusSchema
28020
+ runtimeState: WeatherStatusSchema,
28021
+ /**
28022
+ * Runtime-state durability: **session** — a forecast is stale the moment the hub is down; the provider re-fetches on connect.
28023
+ *
28024
+ * See `RuntimeStateDurability`. Enforced by
28025
+ * `scripts/check-runtime-state-durability.ts`.
28026
+ */
28027
+ durability: "session"
27458
28028
  };
27459
28029
  /**
27460
28030
  * Per-zone occupancy aggregation produced by the analytics frame
@@ -27616,7 +28186,14 @@ var zoneAnalyticsCapability = {
27616
28186
  * automatically; the explicit `getCurrentSnapshot` cap method is
27617
28187
  * still useful for one-off polls without a subscription.
27618
28188
  */
27619
- runtimeState: CameraOccupancySnapshotSchema
28189
+ runtimeState: CameraOccupancySnapshotSchema,
28190
+ /**
28191
+ * Runtime-state durability: **session** — per-frame analytics; with `audio-metrics` it is ~90 % of the offered write rate. Re-derived on the next frame.
28192
+ *
28193
+ * See `RuntimeStateDurability`. Enforced by
28194
+ * `scripts/check-runtime-state-durability.ts`.
28195
+ */
28196
+ durability: "session"
27620
28197
  };
27621
28198
  /**
27622
28199
  * Stages a {@link ZoneRule} can apply to. Discriminator on the rules
@@ -27694,7 +28271,14 @@ var zoneRulesCapability = {
27694
28271
  motion: zod.z.array(ZoneRuleSchema).readonly(),
27695
28272
  detection: zod.z.array(ZoneRuleSchema).readonly(),
27696
28273
  package: zod.z.array(ZoneRuleSchema).readonly()
27697
- })
28274
+ }),
28275
+ /**
28276
+ * Runtime-state durability: **restored** — operator intent, mutation-only, same argument as `zones`.
28277
+ *
28278
+ * See `RuntimeStateDurability`. Enforced by
28279
+ * `scripts/check-runtime-state-durability.ts`.
28280
+ */
28281
+ durability: "restored"
27698
28282
  };
27699
28283
  /**
27700
28284
  * Runtime defaults -- used by ConfigManager.get() for backward compatibility
@@ -33911,6 +34495,279 @@ Object.freeze({
33911
34495
  "network-access": "ingress",
33912
34496
  "smtp-provider": "email"
33913
34497
  });
34498
+ /**
34499
+ * Per-cap runtime-state policy, projected from every `*.cap.ts` that declares
34500
+ * `runtimeState`. 62 caps: 33 `restored`, 29 `session`.
34501
+ *
34502
+ * A cap absent from this map has no runtime-state slice at all. A cap PRESENT
34503
+ * with `durability: 'session'` has one and has decided not to keep it.
34504
+ */
34505
+ var RUNTIME_STATE_POLICY = {
34506
+ "air-quality-sensor": {
34507
+ durability: "restored",
34508
+ volatileFields: ["lastFetchedAt"]
34509
+ },
34510
+ "alarm-panel": {
34511
+ durability: "restored",
34512
+ volatileFields: ["lastChangedAt"]
34513
+ },
34514
+ "ambient-light-sensor": {
34515
+ durability: "restored",
34516
+ volatileFields: ["lastFetchedAt"]
34517
+ },
34518
+ "audio-metrics": {
34519
+ durability: "session",
34520
+ volatileFields: []
34521
+ },
34522
+ "automation-control": {
34523
+ durability: "session",
34524
+ volatileFields: []
34525
+ },
34526
+ "battery": {
34527
+ durability: "restored",
34528
+ volatileFields: ["lastUpdated"]
34529
+ },
34530
+ "binary": {
34531
+ durability: "restored",
34532
+ volatileFields: ["lastChangedAt"]
34533
+ },
34534
+ "brightness": {
34535
+ durability: "session",
34536
+ volatileFields: []
34537
+ },
34538
+ "camera-streams": {
34539
+ durability: "session",
34540
+ volatileFields: []
34541
+ },
34542
+ "carbon-monoxide": {
34543
+ durability: "restored",
34544
+ volatileFields: ["lastChangedAt"]
34545
+ },
34546
+ "climate-control": {
34547
+ durability: "session",
34548
+ volatileFields: []
34549
+ },
34550
+ "color": {
34551
+ durability: "session",
34552
+ volatileFields: []
34553
+ },
34554
+ "connectivity": {
34555
+ durability: "restored",
34556
+ volatileFields: ["lastChangedAt"]
34557
+ },
34558
+ "consumables": {
34559
+ durability: "session",
34560
+ volatileFields: []
34561
+ },
34562
+ "contact": {
34563
+ durability: "restored",
34564
+ volatileFields: ["lastChangedAt"]
34565
+ },
34566
+ "control": {
34567
+ durability: "session",
34568
+ volatileFields: []
34569
+ },
34570
+ "cover": {
34571
+ durability: "restored",
34572
+ volatileFields: ["lastChangedAt"]
34573
+ },
34574
+ "day-night": {
34575
+ durability: "restored",
34576
+ volatileFields: ["lastFetchedAt"]
34577
+ },
34578
+ "device-discovery": {
34579
+ durability: "session",
34580
+ volatileFields: []
34581
+ },
34582
+ "device-status": {
34583
+ durability: "restored",
34584
+ volatileFields: ["lastChangedAt"]
34585
+ },
34586
+ "doorbell": {
34587
+ durability: "restored",
34588
+ volatileFields: []
34589
+ },
34590
+ "enum-sensor": {
34591
+ durability: "restored",
34592
+ volatileFields: ["lastFetchedAt"]
34593
+ },
34594
+ "event-emitter": {
34595
+ durability: "session",
34596
+ volatileFields: []
34597
+ },
34598
+ "fan-control": {
34599
+ durability: "session",
34600
+ volatileFields: []
34601
+ },
34602
+ "feature-probe": {
34603
+ durability: "session",
34604
+ volatileFields: []
34605
+ },
34606
+ "flood": {
34607
+ durability: "restored",
34608
+ volatileFields: ["lastChangedAt"]
34609
+ },
34610
+ "gas": {
34611
+ durability: "restored",
34612
+ volatileFields: ["lastChangedAt"]
34613
+ },
34614
+ "humidifier": {
34615
+ durability: "session",
34616
+ volatileFields: []
34617
+ },
34618
+ "humidity-sensor": {
34619
+ durability: "restored",
34620
+ volatileFields: ["lastFetchedAt"]
34621
+ },
34622
+ "image": {
34623
+ durability: "session",
34624
+ volatileFields: []
34625
+ },
34626
+ "image-settings": {
34627
+ durability: "restored",
34628
+ volatileFields: ["lastFetchedAt"]
34629
+ },
34630
+ "lawn-mower-control": {
34631
+ durability: "session",
34632
+ volatileFields: []
34633
+ },
34634
+ "lock-control": {
34635
+ durability: "restored",
34636
+ volatileFields: ["lastChangedAt"]
34637
+ },
34638
+ "media-player": {
34639
+ durability: "session",
34640
+ volatileFields: []
34641
+ },
34642
+ "motion": {
34643
+ durability: "session",
34644
+ volatileFields: []
34645
+ },
34646
+ "motion-trigger": {
34647
+ durability: "session",
34648
+ volatileFields: []
34649
+ },
34650
+ "motion-zones": {
34651
+ durability: "restored",
34652
+ volatileFields: ["lastFetchedAt"]
34653
+ },
34654
+ "native-object-detection": {
34655
+ durability: "restored",
34656
+ volatileFields: ["lastFetchedAt"]
34657
+ },
34658
+ "notifier": {
34659
+ durability: "session",
34660
+ volatileFields: []
34661
+ },
34662
+ "numeric-sensor": {
34663
+ durability: "restored",
34664
+ volatileFields: ["lastFetchedAt"]
34665
+ },
34666
+ "pet-feeder": {
34667
+ durability: "session",
34668
+ volatileFields: []
34669
+ },
34670
+ "power-meter": {
34671
+ durability: "restored",
34672
+ volatileFields: ["lastFetchedAt"]
34673
+ },
34674
+ "presence": {
34675
+ durability: "restored",
34676
+ volatileFields: ["lastChangedAt"]
34677
+ },
34678
+ "pressure-sensor": {
34679
+ durability: "restored",
34680
+ volatileFields: ["lastFetchedAt"]
34681
+ },
34682
+ "privacy-mask": {
34683
+ durability: "restored",
34684
+ volatileFields: ["lastFetchedAt"]
34685
+ },
34686
+ "ptz-autotrack": {
34687
+ durability: "session",
34688
+ volatileFields: []
34689
+ },
34690
+ "scene-monitor": {
34691
+ durability: "session",
34692
+ volatileFields: []
34693
+ },
34694
+ "script-runner": {
34695
+ durability: "session",
34696
+ volatileFields: []
34697
+ },
34698
+ "smoke": {
34699
+ durability: "restored",
34700
+ volatileFields: ["lastChangedAt"]
34701
+ },
34702
+ "stream-params": {
34703
+ durability: "restored",
34704
+ volatileFields: ["lastFetchedAt"]
34705
+ },
34706
+ "switch": {
34707
+ durability: "restored",
34708
+ volatileFields: ["lastChangedAt"]
34709
+ },
34710
+ "tamper": {
34711
+ durability: "restored",
34712
+ volatileFields: ["lastChangedAt"]
34713
+ },
34714
+ "temperature-sensor": {
34715
+ durability: "restored",
34716
+ volatileFields: ["lastFetchedAt"]
34717
+ },
34718
+ "update": {
34719
+ durability: "session",
34720
+ volatileFields: []
34721
+ },
34722
+ "vacuum-control": {
34723
+ durability: "session",
34724
+ volatileFields: []
34725
+ },
34726
+ "valve": {
34727
+ durability: "session",
34728
+ volatileFields: []
34729
+ },
34730
+ "vibration": {
34731
+ durability: "restored",
34732
+ volatileFields: ["lastChangedAt"]
34733
+ },
34734
+ "water-heater": {
34735
+ durability: "session",
34736
+ volatileFields: []
34737
+ },
34738
+ "weather": {
34739
+ durability: "session",
34740
+ volatileFields: []
34741
+ },
34742
+ "zone-analytics": {
34743
+ durability: "session",
34744
+ volatileFields: []
34745
+ },
34746
+ "zone-rules": {
34747
+ durability: "restored",
34748
+ volatileFields: []
34749
+ },
34750
+ "zones": {
34751
+ durability: "restored",
34752
+ volatileFields: []
34753
+ }
34754
+ };
34755
+ /**
34756
+ * The policy for `capName`. An UNKNOWN cap resolves to `'session'` — an
34757
+ * addon-private slice the codegen has never seen is not persisted until its
34758
+ * capability says so, which is the safe direction: the cost of a lost session
34759
+ * value is a cold window, the cost of an unasked-for persist is a commit per
34760
+ * second on the fleet's busiest write path.
34761
+ */
34762
+ function runtimeStatePolicyFor(capName) {
34763
+ return RUNTIME_STATE_POLICY[capName] ?? SESSION_ONLY_POLICY;
34764
+ }
34765
+ /** Shared fallback instance — see {@link runtimeStatePolicyFor}. */
34766
+ var SESSION_ONLY_POLICY = {
34767
+ durability: "session",
34768
+ volatileFields: []
34769
+ };
34770
+ new Map(AUDIO_MACRO_LABELS.flatMap((macro) => macro.icon === void 0 ? [] : [[macro.id, macro.icon]]));
33914
34771
  new Set(["devices", "classes"]);
33915
34772
  /**
33916
34773
  * TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
@@ -34188,25 +35045,32 @@ zod.z.object({
34188
35045
  var NativeLeaseAdmissionSchema = zod.z.enum(["all", "inferred"]);
34189
35046
  zod.z.object({
34190
35047
  /**
34191
- * How long a retained native frame is served before it counts as a miss.
35048
+ * How many delivered frames the worker HOLDS at once, waiting for each one's
35049
+ * detection result.
35050
+ *
35051
+ * This replaced a TTL on 2026-08-13, and the replacement is the whole point:
35052
+ * a time window was never related to the event the pixels were waiting for.
35053
+ * A held frame now lives from delivery until the runner has its `FrameResult`
35054
+ * — at which moment the runner cuts the subject tiles it actually wanted and
35055
+ * releases the frame. The bound exists only so a runner that stops answering
35056
+ * cannot pin RAM: above it the OLDEST held frame is dropped and counted.
34192
35057
  *
34193
- * Must cover the FULL late-crop horizon: detection inference + the
34194
- * cross-process inference-result hop to hub post-analysis + tracking + the
34195
- * tRPC crop round-trip back. Below ~500 ms the busiest cameras' subject crops
34196
- * outrun it and fall back to the ≤640 detection frame; above ~3 s the resident
34197
- * RAM per busy camera grows linearly with no measured hit-rate gain.
35058
+ * Sizing: the steady state is `inferenceLatency × deliveredFps`, measured at
35059
+ * 40-160 ms × ≤25 fps = 1-4 frames. The default leaves headroom for a hiccup
35060
+ * without ever approaching the old resident set (43 frames × 24.9 MB at 4K).
35061
+ * Raising it does not buy hit rate it buys tolerance for a slow runner, and
35062
+ * `holdOverflow` on the metrics line is what says you need it.
34198
35063
  */
34199
- ttlMs: zod.z.number().int().min(250).max(1e4),
35064
+ holdFrames: zod.z.number().int().min(1).max(64),
34200
35065
  /**
34201
35066
  * Hard per-decode-worker RAM ceiling for retained native frames, in MB.
34202
35067
  *
34203
- * Intended as a SAFETY ceiling with the TTL as the effective cap — but check
34204
- * which one is actually binding before reasoning from that. At the shipped
34205
- * 1024 MB and a 2 800 ms TTL, a 4K camera hits the CEILING first (~43 frames
34206
- * at ~24 MB each) and the TTL never gets to expire anything; `leaseMb` /
34207
- * `leaseFrames` on the metrics line say which. When the ceiling binds, a
34208
- * change that admits fewer frames buys retention WINDOW at constant RAM
34209
- * rather than giving RAM back — lower this knob if RAM is what you wanted.
35068
+ * Since 2026-08-13 this is a SAFETY ceiling and nothing else: `holdFrames`
35069
+ * is what decides how much is held, and the ceiling is the number above which
35070
+ * something is wrong. Before that it was the effective cap at 1024 MB with
35071
+ * a 2 800 ms TTL a 4K camera sat pinned at `leaseMb:1020, leaseFrames:43`
35072
+ * with the TTL expiring nothing, which is exactly the confusion the hold
35073
+ * removes. `leaseMb` / `leaseFrames` still say what is resident.
34210
35074
  * `0` DISABLES the lease entirely and falls the worker back to the tiny
34211
35075
  * leak-prone GPU surface ring (~85% crop miss; that is what the lease exists
34212
35076
  * to replace).
@@ -34232,22 +35096,45 @@ zod.z.object({
34232
35096
  * there is the signal that some caller names frames outside the inference set
34233
35097
  * and that this must go back to `all`.
34234
35098
  */
34235
- admission: NativeLeaseAdmissionSchema
35099
+ admission: NativeLeaseAdmissionSchema,
35100
+ /**
35101
+ * RAM ceiling per decode worker, in MB, for the SUBJECT TILES — the
35102
+ * compressed native crops the worker cuts at the moment a frame's detection
35103
+ * result arrives, and keeps long after the frame itself is freed.
35104
+ *
35105
+ * This is the knob that replaced the old retention window, and it buys about
35106
+ * three orders of magnitude more of it: a tile is one subject at native
35107
+ * resolution, JPEG-encoded (~60-120 KB on a 4K person), against ~24.9 MB for
35108
+ * the frame it was cut from. A frame on which nothing was detected costs
35109
+ * nothing at all, which is the real change — the old lease paid per FRAME and
35110
+ * was interrogated per SUBJECT.
35111
+ *
35112
+ * `0` DISABLES tiles, leaving only the hold window and the ≤640 RAM
35113
+ * fallback — i.e. the pre-2026-08-13 miss profile. Set it there only to
35114
+ * reproduce that.
35115
+ */
35116
+ tileBudgetMb: zod.z.number().int().min(0).max(1024)
34236
35117
  });
34237
35118
  /**
34238
- * The values in force when the operator has set nothing — byte-for-byte the
34239
- * constants the decode worker shipped with as env-var defaults, so making these
34240
- * settings changed no behaviour on the day it landed.
35119
+ * The values in force when the operator has set nothing.
35120
+ *
35121
+ * `budgetMb` stays at 1024 on the day the hold landed, deliberately: it stopped
35122
+ * being the retention window and became the OOM ceiling, and lowering a ceiling
35123
+ * in the same change that redefines it would make a regression and a retune
35124
+ * indistinguishable. Cut it once `tileHits` / `holdOverflow` have been read on
35125
+ * live traffic.
34241
35126
  */
34242
35127
  var DEFAULT_NATIVE_LEASE_SETTINGS = {
34243
- ttlMs: 1200,
35128
+ holdFrames: 8,
34244
35129
  budgetMb: 1024,
34245
35130
  activityMs: 15e3,
35131
+ tileBudgetMb: 64,
34246
35132
  admission: "inferred"
34247
35133
  };
34248
- DEFAULT_NATIVE_LEASE_SETTINGS.ttlMs;
35134
+ DEFAULT_NATIVE_LEASE_SETTINGS.holdFrames;
34249
35135
  DEFAULT_NATIVE_LEASE_SETTINGS.budgetMb;
34250
35136
  DEFAULT_NATIVE_LEASE_SETTINGS.activityMs;
35137
+ DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb;
34251
35138
  DEFAULT_NATIVE_LEASE_SETTINGS.admission;
34252
35139
  /**
34253
35140
  * The addon id as the REGISTRY, the wire and the durable stores spell it.
@@ -34909,6 +35796,12 @@ Object.defineProperty(exports, "resolveCapMount", {
34909
35796
  return resolveCapMount;
34910
35797
  }
34911
35798
  });
35799
+ Object.defineProperty(exports, "runtimeStatePolicyFor", {
35800
+ enumerable: true,
35801
+ get: function() {
35802
+ return runtimeStatePolicyFor;
35803
+ }
35804
+ });
34912
35805
  Object.defineProperty(exports, "scopeKey", {
34913
35806
  enumerable: true,
34914
35807
  get: function() {