@camstack/addon-mqtt-broker 1.2.22 → 1.2.24

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.
@@ -7595,7 +7595,7 @@ var RecordingBandSchema = object({
7595
7595
  postBufferSec: number().min(0).optional()
7596
7596
  });
7597
7597
  ({
7598
- preBufferSec: 10,
7598
+ preBufferSec: 15,
7599
7599
  postBufferSec: 30
7600
7600
  }).postBufferSec * 1e3;
7601
7601
  /**
@@ -13602,128 +13602,103 @@ var COCO_TO_MACRO = {
13602
13602
  var AUDIO_MACRO_LABELS = [
13603
13603
  {
13604
13604
  id: "speech",
13605
- name: "Speech",
13606
- icon: "🗣️"
13605
+ name: "Speech"
13607
13606
  },
13608
13607
  {
13609
13608
  id: "scream",
13610
- name: "Scream / Shout",
13611
- icon: "😱"
13609
+ name: "Scream / Shout"
13612
13610
  },
13613
13611
  {
13614
13612
  id: "crying",
13615
- name: "Crying / Baby",
13616
- icon: "😢"
13613
+ name: "Crying / Baby"
13617
13614
  },
13618
13615
  {
13619
13616
  id: "laughter",
13620
- name: "Laughter",
13621
- icon: "😂"
13617
+ name: "Laughter"
13622
13618
  },
13623
13619
  {
13624
13620
  id: "music",
13625
- name: "Music",
13626
- icon: "🎵"
13621
+ name: "Music"
13627
13622
  },
13628
13623
  {
13629
13624
  id: "dog",
13630
- name: "Dog",
13631
- icon: "🐕"
13625
+ name: "Dog"
13632
13626
  },
13633
13627
  {
13634
13628
  id: "cat",
13635
- name: "Cat",
13636
- icon: "🐈"
13629
+ name: "Cat"
13637
13630
  },
13638
13631
  {
13639
13632
  id: "bird",
13640
- name: "Bird",
13641
- icon: "🐦"
13633
+ name: "Bird"
13642
13634
  },
13643
13635
  {
13644
13636
  id: "animal",
13645
- name: "Animal (other)",
13646
- icon: "🐾"
13637
+ name: "Animal (other)"
13647
13638
  },
13648
13639
  {
13649
13640
  id: "alarm",
13650
- name: "Alarm / Siren",
13651
- icon: "🚨"
13641
+ name: "Alarm / Siren"
13652
13642
  },
13653
13643
  {
13654
13644
  id: "doorbell",
13655
- name: "Doorbell / Knock",
13656
- icon: "🔔"
13645
+ name: "Doorbell / Knock"
13657
13646
  },
13658
13647
  {
13659
13648
  id: "glass_breaking",
13660
- name: "Glass Breaking",
13661
- icon: "💥"
13649
+ name: "Glass Breaking"
13662
13650
  },
13663
13651
  {
13664
13652
  id: "gunshot",
13665
- name: "Gunshot / Explosion",
13666
- icon: "💣"
13653
+ name: "Gunshot / Explosion"
13667
13654
  },
13668
13655
  {
13669
13656
  id: "vehicle",
13670
- name: "Vehicle",
13671
- icon: "🚗"
13657
+ name: "Vehicle"
13672
13658
  },
13673
13659
  {
13674
13660
  id: "siren",
13675
- name: "Emergency Siren",
13676
- icon: "🚑"
13661
+ name: "Emergency Siren"
13677
13662
  },
13678
13663
  {
13679
13664
  id: "fire",
13680
- name: "Fire / Smoke",
13681
- icon: "🔥"
13665
+ name: "Fire / Smoke"
13682
13666
  },
13683
13667
  {
13684
13668
  id: "water",
13685
- name: "Water",
13686
- icon: "💧"
13669
+ name: "Water"
13687
13670
  },
13688
13671
  {
13689
13672
  id: "wind",
13690
- name: "Wind / Weather",
13691
- icon: "🌬️"
13673
+ name: "Wind / Weather"
13692
13674
  },
13693
13675
  {
13694
13676
  id: "door",
13695
- name: "Door",
13696
- icon: "🚪"
13677
+ name: "Door"
13697
13678
  },
13698
13679
  {
13699
13680
  id: "footsteps",
13700
- name: "Footsteps",
13701
- icon: "👣"
13681
+ name: "Footsteps"
13702
13682
  },
13703
13683
  {
13704
13684
  id: "crowd",
13705
- name: "Crowd / Chatter",
13706
- icon: "👥"
13685
+ name: "Crowd / Chatter"
13707
13686
  },
13708
13687
  {
13709
13688
  id: "telephone",
13710
- name: "Telephone",
13711
- icon: "📞"
13689
+ name: "Telephone"
13712
13690
  },
13713
13691
  {
13714
13692
  id: "engine",
13715
- name: "Engine / Motor",
13716
- icon: "⚙️"
13693
+ name: "Engine / Motor"
13717
13694
  },
13718
13695
  {
13719
13696
  id: "tools",
13720
- name: "Tools / Construction",
13721
- icon: "🔨"
13697
+ name: "Tools / Construction"
13722
13698
  },
13723
13699
  {
13724
13700
  id: "silence",
13725
- name: "Silence",
13726
- icon: "🤫"
13701
+ name: "Silence"
13727
13702
  }
13728
13703
  ];
13729
13704
  var YAMNET_TO_MACRO = {
@@ -16187,7 +16162,7 @@ var TrackEnvelopeSchema = object({
16187
16162
  * `snapshots[]` references — megabytes across a page of tracks. `slim`
16188
16163
  * keeps every scalar the list surfaces actually render (ids, class(es),
16189
16164
  * label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
16190
- * zonesVisited, bestEventId, envelope, hasFace, hasRider) and returns `positions` /
16165
+ * zonesVisited, bestEventId, envelope, hasFace, hasEmbeddedFace, hasRider) and returns `positions` /
16191
16166
  * `snapshots` as EMPTY arrays — detail views re-fetch the full row via
16192
16167
  * `getTrack`. Mirrors the event-store `projection` convention
16193
16168
  * (`getObjectEvents` et al.).
@@ -16482,6 +16457,35 @@ var TrackSchema = object({
16482
16457
  */
16483
16458
  hasFace: boolean().optional(),
16484
16459
  /**
16460
+ * This track has a face row IN THE GALLERY: a crop **and** an embedding — a
16461
+ * face an operator could ASSIGN to an identity.
16462
+ *
16463
+ * The STRICT twin of {@link hasFace}, and the pair only earns its keep
16464
+ * because the two disagree. `hasFace` is stamped at the TOP of the face
16465
+ * branch, before every gate, and means no more than "a face detector produced
16466
+ * a face detail". This one is stamped at the single moment the gallery row
16467
+ * LANDS — after `FaceRecognizer.onTrackEnd` successfully persists it, i.e.
16468
+ * past the embedding-magnitude verdict, the `minFacePx` detection gate, the
16469
+ * candidate gate, the imageless-track drop (no crop was ever captured) and
16470
+ * the crop-store drop. Everything between the detector and that insert can
16471
+ * legitimately refuse the face, so a flag written any earlier promises the
16472
+ * operator something to assign and delivers nothing.
16473
+ *
16474
+ * **Independent of recognition.** A face collected but never auto-matched is
16475
+ * still assignable — it is in fact the face an operator most wants to reach —
16476
+ * so this is NOT gated on `recognizedIdentityId`. Recognition lands in
16477
+ * `subLabel`; this says only that the raw material exists.
16478
+ *
16479
+ * **Set once, never cleared.** A track that produced a gallery row produced
16480
+ * one; deleting the row later is the gallery's business, not this flag's.
16481
+ *
16482
+ * **Absent ≠ false**, the same rule as {@link hasFace}: every row written
16483
+ * before the column omits it, and so does every server that predates the
16484
+ * field. A consumer must test `=== true` and render nothing otherwise —
16485
+ * never infer "no assignable face".
16486
+ */
16487
+ hasEmbeddedFace: boolean().optional(),
16488
+ /**
16485
16489
  * This subject CONTAINS a folded rider — a person the rider-pairing step
16486
16490
  * ([D34](../decisions/adr-0034.md)) removed from the frame BEFORE the tracker,
16487
16491
  * so the passage is tracked once and as a VEHICLE.
@@ -17831,6 +17835,32 @@ var DetailResultSchema = object({
17831
17835
  /** FRAME-space bbox (already mapped back from crop space). */
17832
17836
  bbox: NativeCropBboxSchema.optional(),
17833
17837
  embedding: string().optional(),
17838
+ /**
17839
+ * L2 magnitude of the RAW pre-normalization embedding. Additive and optional
17840
+ * so an older runner that does not send it degrades to "unmeasurable", which
17841
+ * the consuming gate treats as accept — never as reject.
17842
+ */
17843
+ embeddingMagnitude: number().optional(),
17844
+ /**
17845
+ * Model that produced `embedding` — the SAME contract `labelModelId` has for
17846
+ * `label`, and for the same reason: the producing node is the only side that
17847
+ * knows which model actually ran, and re-deriving it downstream is exactly
17848
+ * the inference this model exists to forbid.
17849
+ *
17850
+ * Additive and optional, so a runner that predates it degrades to
17851
+ * "unmeasurable" rather than to a wrong answer — the consumer falls back to
17852
+ * its previous assumption instead of refusing.
17853
+ *
17854
+ * Its absence was not cosmetic. `FaceRecognizer` needs the probe's model id
17855
+ * to use `face-matcher`'s same-model gate (`sample.modelId !== probe.modelId`);
17856
+ * with nothing on the wire it took the id from the GALLERY, so the gate
17857
+ * compared the gallery against itself and could never fire. That turned the
17858
+ * one guard protecting the face feature space into a tautology, and it is
17859
+ * why swapping `face-embedding`'s model would NOT have stranded the enrolled
17860
+ * gallery as the catalog comment predicts — it would have scored the new
17861
+ * model's vectors against the old model's samples in one cosine space.
17862
+ */
17863
+ embeddingModelId: string().optional(),
17834
17864
  label: string().optional(),
17835
17865
  /**
17836
17866
  * The tier `label` occupies, copied VERBATIM from the producing step's
@@ -19241,6 +19271,7 @@ DeviceType.Camera, method(object({
19241
19271
  isBattery: boolean(),
19242
19272
  reason: _enum([
19243
19273
  "disabled",
19274
+ "offline",
19244
19275
  "sleeping",
19245
19276
  "unreachable",
19246
19277
  "waking"
@@ -19286,9 +19317,17 @@ targets: array(object({
19286
19317
  sleeping: boolean(),
19287
19318
  /** Current device state rendered over the cached frame. State images
19288
19319
  * remain authoritative even when their photographic background is
19289
- * old; null means the link must carry a current camera frame. */
19320
+ * old; null means the link must carry a current camera frame.
19321
+ *
19322
+ * **This is the ONLY source a surface may derive an inactive tile
19323
+ * from.** A client that reads a device's `online`/`disabled` flags and
19324
+ * draws its own verdict will disagree with the pixels it is painting
19325
+ * — the frame comes from here, and so must the sentence over it
19326
+ * (D190). Pair with `ageMs` for the age of the photograph behind the
19327
+ * state. */
19290
19328
  stateReason: _enum([
19291
19329
  "disabled",
19330
+ "offline",
19292
19331
  "sleeping",
19293
19332
  "unreachable",
19294
19333
  "waking"
@@ -24319,9 +24358,21 @@ var RecordingLocationUsageSchema = object({
24319
24358
  * previously rendered as two identical "disks" with a nonsensical used
24320
24359
  * split — hydrate attribution across aliases is arbitrary by nature. */
24321
24360
  locationIds: array(string()).optional(),
24322
- /** Bytes of recordings stored on this PHYSICAL volume (all aliases). */
24361
+ /**
24362
+ * Filesystem root of the physical volume this row accounts — the only
24363
+ * operator-legible identity when a location has no `displayName` yet, and
24364
+ * what a "which disk is full" alert has to name. OPTIONAL for the same
24365
+ * train-skew reason as `oldestMs`: a recorder that predates the field omits
24366
+ * it, and this schema must keep validating that older provider's payload.
24367
+ */
24368
+ root: string().optional(),
24369
+ /** Bytes of recordings stored on this PHYSICAL volume (all aliases). This is
24370
+ * the footage's SHARE of the volume, not how full the volume is — the disk
24371
+ * also holds everything that is not recordings. Volume fill is
24372
+ * `(totalBytes - availableBytes) / totalBytes`. */
24323
24373
  usedBytes: number(),
24324
- /** Free bytes on the location's volume; null when capacity is unknown (remote). */
24374
+ /** Free bytes on the location's volume; null when capacity is unknown
24375
+ * (remote/unstattable — the recorder logs the statfs failure with the root). */
24325
24376
  availableBytes: number().nullable(),
24326
24377
  /** Total bytes of the location's volume; null when unknown. */
24327
24378
  totalBytes: number().nullable()
@@ -24333,7 +24384,15 @@ var RecordingStorageUsageSchema = object({
24333
24384
  nodeId: string(),
24334
24385
  totalUsedBytes: number(),
24335
24386
  devices: array(RecordingDeviceUsageSchema),
24336
- locations: array(RecordingLocationUsageSchema)
24387
+ /**
24388
+ * Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
24389
+ * of the payload without it: the hub serves this method through a BAKED
24390
+ * router, so a hub whose framework train predates a change to this array
24391
+ * strips it out of an answer a newer recorder happily produced. A UI that
24392
+ * dereferences it unconditionally crashes the whole Storage page over a
24393
+ * missing disk bar.
24394
+ */
24395
+ locations: array(RecordingLocationUsageSchema).optional()
24337
24396
  });
24338
24397
  /**
24339
24398
  * The OPERATOR-ARMED half of multi-location recordings (D116).
@@ -33449,8 +33508,13 @@ Object.freeze({
33449
33508
  "network-access": "ingress",
33450
33509
  "smtp-provider": "email"
33451
33510
  });
33452
- new Map(AUDIO_MACRO_LABELS.flatMap((macro) => macro.icon === void 0 ? [] : [[macro.id, macro.icon]]));
33511
+ /** Schema defaults an untouched sub-field must author exactly these. */
33512
+ var NC_AUDIO_DEFAULTS = {
33513
+ hitPercent: 60,
33514
+ samplingSeconds: 10
33515
+ };
33453
33516
  new Set(["devices", "classes"]);
33517
+ NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
33454
33518
  /**
33455
33519
  * TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
33456
33520
  *
@@ -33682,6 +33746,39 @@ TimelapseRuleInputSchema.extend({
33682
33746
  createdAt: number(),
33683
33747
  updatedAt: number()
33684
33748
  });
33749
+ Object.freeze(Object.fromEntries([{
33750
+ stepId: "face-embedding",
33751
+ label: "Face recognition model",
33752
+ defaultModelId: "arcface-r100",
33753
+ indexName: "the enrolled face gallery",
33754
+ options: [
33755
+ {
33756
+ id: "arcface-r100",
33757
+ label: "ArcFace (ResNet34)"
33758
+ },
33759
+ {
33760
+ id: "auraface-r100",
33761
+ label: "AuraFace R100"
33762
+ },
33763
+ {
33764
+ id: "inception-resnet-v1",
33765
+ label: "Inception ResNet V1"
33766
+ }
33767
+ ]
33768
+ }, {
33769
+ stepId: "clip-embedding",
33770
+ label: "Semantic search model",
33771
+ defaultModelId: "mobileclip-s1",
33772
+ indexName: "the object semantic-search index",
33773
+ options: [{
33774
+ id: "mobileclip-s1",
33775
+ label: "MobileCLIP S1"
33776
+ }, {
33777
+ id: "mobileclip-s2",
33778
+ label: "MobileCLIP S2"
33779
+ }]
33780
+ }].map((s) => [s.stepId, s.defaultModelId])));
33781
+ string().min(1);
33685
33782
  object({
33686
33783
  /**
33687
33784
  * Fraction of the box's own size added on EACH side before cutting.
@@ -33702,10 +33799,21 @@ object({
33702
33799
  */
33703
33800
  square: boolean()
33704
33801
  });
33705
- ({
33802
+ /**
33803
+ * The convention in force when nobody has configured one — byte-for-byte the
33804
+ * behaviour of the pre-unification LIVE path (`DETAIL_CROP_PADDING_RATIO`).
33805
+ */
33806
+ var DEFAULT_DETAIL_CROP_CONVENTION = {
33706
33807
  paddingRatio: .15,
33707
33808
  square: false
33708
- }).paddingRatio;
33809
+ };
33810
+ Object.freeze({
33811
+ x: 0,
33812
+ y: 0,
33813
+ w: 1,
33814
+ h: 1
33815
+ });
33816
+ DEFAULT_DETAIL_CROP_CONVENTION.paddingRatio;
33709
33817
  /**
33710
33818
  * WHICH delivered frames the decode worker retains a native copy of.
33711
33819
  *
@@ -7590,7 +7590,7 @@ var RecordingBandSchema = object({
7590
7590
  postBufferSec: number().min(0).optional()
7591
7591
  });
7592
7592
  ({
7593
- preBufferSec: 10,
7593
+ preBufferSec: 15,
7594
7594
  postBufferSec: 30
7595
7595
  }).postBufferSec * 1e3;
7596
7596
  /**
@@ -13597,128 +13597,103 @@ var COCO_TO_MACRO = {
13597
13597
  var AUDIO_MACRO_LABELS = [
13598
13598
  {
13599
13599
  id: "speech",
13600
- name: "Speech",
13601
- icon: "🗣️"
13600
+ name: "Speech"
13602
13601
  },
13603
13602
  {
13604
13603
  id: "scream",
13605
- name: "Scream / Shout",
13606
- icon: "😱"
13604
+ name: "Scream / Shout"
13607
13605
  },
13608
13606
  {
13609
13607
  id: "crying",
13610
- name: "Crying / Baby",
13611
- icon: "😢"
13608
+ name: "Crying / Baby"
13612
13609
  },
13613
13610
  {
13614
13611
  id: "laughter",
13615
- name: "Laughter",
13616
- icon: "😂"
13612
+ name: "Laughter"
13617
13613
  },
13618
13614
  {
13619
13615
  id: "music",
13620
- name: "Music",
13621
- icon: "🎵"
13616
+ name: "Music"
13622
13617
  },
13623
13618
  {
13624
13619
  id: "dog",
13625
- name: "Dog",
13626
- icon: "🐕"
13620
+ name: "Dog"
13627
13621
  },
13628
13622
  {
13629
13623
  id: "cat",
13630
- name: "Cat",
13631
- icon: "🐈"
13624
+ name: "Cat"
13632
13625
  },
13633
13626
  {
13634
13627
  id: "bird",
13635
- name: "Bird",
13636
- icon: "🐦"
13628
+ name: "Bird"
13637
13629
  },
13638
13630
  {
13639
13631
  id: "animal",
13640
- name: "Animal (other)",
13641
- icon: "🐾"
13632
+ name: "Animal (other)"
13642
13633
  },
13643
13634
  {
13644
13635
  id: "alarm",
13645
- name: "Alarm / Siren",
13646
- icon: "🚨"
13636
+ name: "Alarm / Siren"
13647
13637
  },
13648
13638
  {
13649
13639
  id: "doorbell",
13650
- name: "Doorbell / Knock",
13651
- icon: "🔔"
13640
+ name: "Doorbell / Knock"
13652
13641
  },
13653
13642
  {
13654
13643
  id: "glass_breaking",
13655
- name: "Glass Breaking",
13656
- icon: "💥"
13644
+ name: "Glass Breaking"
13657
13645
  },
13658
13646
  {
13659
13647
  id: "gunshot",
13660
- name: "Gunshot / Explosion",
13661
- icon: "💣"
13648
+ name: "Gunshot / Explosion"
13662
13649
  },
13663
13650
  {
13664
13651
  id: "vehicle",
13665
- name: "Vehicle",
13666
- icon: "🚗"
13652
+ name: "Vehicle"
13667
13653
  },
13668
13654
  {
13669
13655
  id: "siren",
13670
- name: "Emergency Siren",
13671
- icon: "🚑"
13656
+ name: "Emergency Siren"
13672
13657
  },
13673
13658
  {
13674
13659
  id: "fire",
13675
- name: "Fire / Smoke",
13676
- icon: "🔥"
13660
+ name: "Fire / Smoke"
13677
13661
  },
13678
13662
  {
13679
13663
  id: "water",
13680
- name: "Water",
13681
- icon: "💧"
13664
+ name: "Water"
13682
13665
  },
13683
13666
  {
13684
13667
  id: "wind",
13685
- name: "Wind / Weather",
13686
- icon: "🌬️"
13668
+ name: "Wind / Weather"
13687
13669
  },
13688
13670
  {
13689
13671
  id: "door",
13690
- name: "Door",
13691
- icon: "🚪"
13672
+ name: "Door"
13692
13673
  },
13693
13674
  {
13694
13675
  id: "footsteps",
13695
- name: "Footsteps",
13696
- icon: "👣"
13676
+ name: "Footsteps"
13697
13677
  },
13698
13678
  {
13699
13679
  id: "crowd",
13700
- name: "Crowd / Chatter",
13701
- icon: "👥"
13680
+ name: "Crowd / Chatter"
13702
13681
  },
13703
13682
  {
13704
13683
  id: "telephone",
13705
- name: "Telephone",
13706
- icon: "📞"
13684
+ name: "Telephone"
13707
13685
  },
13708
13686
  {
13709
13687
  id: "engine",
13710
- name: "Engine / Motor",
13711
- icon: "⚙️"
13688
+ name: "Engine / Motor"
13712
13689
  },
13713
13690
  {
13714
13691
  id: "tools",
13715
- name: "Tools / Construction",
13716
- icon: "🔨"
13692
+ name: "Tools / Construction"
13717
13693
  },
13718
13694
  {
13719
13695
  id: "silence",
13720
- name: "Silence",
13721
- icon: "🤫"
13696
+ name: "Silence"
13722
13697
  }
13723
13698
  ];
13724
13699
  var YAMNET_TO_MACRO = {
@@ -16182,7 +16157,7 @@ var TrackEnvelopeSchema = object({
16182
16157
  * `snapshots[]` references — megabytes across a page of tracks. `slim`
16183
16158
  * keeps every scalar the list surfaces actually render (ids, class(es),
16184
16159
  * label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
16185
- * zonesVisited, bestEventId, envelope, hasFace, hasRider) and returns `positions` /
16160
+ * zonesVisited, bestEventId, envelope, hasFace, hasEmbeddedFace, hasRider) and returns `positions` /
16186
16161
  * `snapshots` as EMPTY arrays — detail views re-fetch the full row via
16187
16162
  * `getTrack`. Mirrors the event-store `projection` convention
16188
16163
  * (`getObjectEvents` et al.).
@@ -16477,6 +16452,35 @@ var TrackSchema = object({
16477
16452
  */
16478
16453
  hasFace: boolean().optional(),
16479
16454
  /**
16455
+ * This track has a face row IN THE GALLERY: a crop **and** an embedding — a
16456
+ * face an operator could ASSIGN to an identity.
16457
+ *
16458
+ * The STRICT twin of {@link hasFace}, and the pair only earns its keep
16459
+ * because the two disagree. `hasFace` is stamped at the TOP of the face
16460
+ * branch, before every gate, and means no more than "a face detector produced
16461
+ * a face detail". This one is stamped at the single moment the gallery row
16462
+ * LANDS — after `FaceRecognizer.onTrackEnd` successfully persists it, i.e.
16463
+ * past the embedding-magnitude verdict, the `minFacePx` detection gate, the
16464
+ * candidate gate, the imageless-track drop (no crop was ever captured) and
16465
+ * the crop-store drop. Everything between the detector and that insert can
16466
+ * legitimately refuse the face, so a flag written any earlier promises the
16467
+ * operator something to assign and delivers nothing.
16468
+ *
16469
+ * **Independent of recognition.** A face collected but never auto-matched is
16470
+ * still assignable — it is in fact the face an operator most wants to reach —
16471
+ * so this is NOT gated on `recognizedIdentityId`. Recognition lands in
16472
+ * `subLabel`; this says only that the raw material exists.
16473
+ *
16474
+ * **Set once, never cleared.** A track that produced a gallery row produced
16475
+ * one; deleting the row later is the gallery's business, not this flag's.
16476
+ *
16477
+ * **Absent ≠ false**, the same rule as {@link hasFace}: every row written
16478
+ * before the column omits it, and so does every server that predates the
16479
+ * field. A consumer must test `=== true` and render nothing otherwise —
16480
+ * never infer "no assignable face".
16481
+ */
16482
+ hasEmbeddedFace: boolean().optional(),
16483
+ /**
16480
16484
  * This subject CONTAINS a folded rider — a person the rider-pairing step
16481
16485
  * ([D34](../decisions/adr-0034.md)) removed from the frame BEFORE the tracker,
16482
16486
  * so the passage is tracked once and as a VEHICLE.
@@ -17826,6 +17830,32 @@ var DetailResultSchema = object({
17826
17830
  /** FRAME-space bbox (already mapped back from crop space). */
17827
17831
  bbox: NativeCropBboxSchema.optional(),
17828
17832
  embedding: string().optional(),
17833
+ /**
17834
+ * L2 magnitude of the RAW pre-normalization embedding. Additive and optional
17835
+ * so an older runner that does not send it degrades to "unmeasurable", which
17836
+ * the consuming gate treats as accept — never as reject.
17837
+ */
17838
+ embeddingMagnitude: number().optional(),
17839
+ /**
17840
+ * Model that produced `embedding` — the SAME contract `labelModelId` has for
17841
+ * `label`, and for the same reason: the producing node is the only side that
17842
+ * knows which model actually ran, and re-deriving it downstream is exactly
17843
+ * the inference this model exists to forbid.
17844
+ *
17845
+ * Additive and optional, so a runner that predates it degrades to
17846
+ * "unmeasurable" rather than to a wrong answer — the consumer falls back to
17847
+ * its previous assumption instead of refusing.
17848
+ *
17849
+ * Its absence was not cosmetic. `FaceRecognizer` needs the probe's model id
17850
+ * to use `face-matcher`'s same-model gate (`sample.modelId !== probe.modelId`);
17851
+ * with nothing on the wire it took the id from the GALLERY, so the gate
17852
+ * compared the gallery against itself and could never fire. That turned the
17853
+ * one guard protecting the face feature space into a tautology, and it is
17854
+ * why swapping `face-embedding`'s model would NOT have stranded the enrolled
17855
+ * gallery as the catalog comment predicts — it would have scored the new
17856
+ * model's vectors against the old model's samples in one cosine space.
17857
+ */
17858
+ embeddingModelId: string().optional(),
17829
17859
  label: string().optional(),
17830
17860
  /**
17831
17861
  * The tier `label` occupies, copied VERBATIM from the producing step's
@@ -19236,6 +19266,7 @@ DeviceType.Camera, method(object({
19236
19266
  isBattery: boolean(),
19237
19267
  reason: _enum([
19238
19268
  "disabled",
19269
+ "offline",
19239
19270
  "sleeping",
19240
19271
  "unreachable",
19241
19272
  "waking"
@@ -19281,9 +19312,17 @@ targets: array(object({
19281
19312
  sleeping: boolean(),
19282
19313
  /** Current device state rendered over the cached frame. State images
19283
19314
  * remain authoritative even when their photographic background is
19284
- * old; null means the link must carry a current camera frame. */
19315
+ * old; null means the link must carry a current camera frame.
19316
+ *
19317
+ * **This is the ONLY source a surface may derive an inactive tile
19318
+ * from.** A client that reads a device's `online`/`disabled` flags and
19319
+ * draws its own verdict will disagree with the pixels it is painting
19320
+ * — the frame comes from here, and so must the sentence over it
19321
+ * (D190). Pair with `ageMs` for the age of the photograph behind the
19322
+ * state. */
19285
19323
  stateReason: _enum([
19286
19324
  "disabled",
19325
+ "offline",
19287
19326
  "sleeping",
19288
19327
  "unreachable",
19289
19328
  "waking"
@@ -24314,9 +24353,21 @@ var RecordingLocationUsageSchema = object({
24314
24353
  * previously rendered as two identical "disks" with a nonsensical used
24315
24354
  * split — hydrate attribution across aliases is arbitrary by nature. */
24316
24355
  locationIds: array(string()).optional(),
24317
- /** Bytes of recordings stored on this PHYSICAL volume (all aliases). */
24356
+ /**
24357
+ * Filesystem root of the physical volume this row accounts — the only
24358
+ * operator-legible identity when a location has no `displayName` yet, and
24359
+ * what a "which disk is full" alert has to name. OPTIONAL for the same
24360
+ * train-skew reason as `oldestMs`: a recorder that predates the field omits
24361
+ * it, and this schema must keep validating that older provider's payload.
24362
+ */
24363
+ root: string().optional(),
24364
+ /** Bytes of recordings stored on this PHYSICAL volume (all aliases). This is
24365
+ * the footage's SHARE of the volume, not how full the volume is — the disk
24366
+ * also holds everything that is not recordings. Volume fill is
24367
+ * `(totalBytes - availableBytes) / totalBytes`. */
24318
24368
  usedBytes: number(),
24319
- /** Free bytes on the location's volume; null when capacity is unknown (remote). */
24369
+ /** Free bytes on the location's volume; null when capacity is unknown
24370
+ * (remote/unstattable — the recorder logs the statfs failure with the root). */
24320
24371
  availableBytes: number().nullable(),
24321
24372
  /** Total bytes of the location's volume; null when unknown. */
24322
24373
  totalBytes: number().nullable()
@@ -24328,7 +24379,15 @@ var RecordingStorageUsageSchema = object({
24328
24379
  nodeId: string(),
24329
24380
  totalUsedBytes: number(),
24330
24381
  devices: array(RecordingDeviceUsageSchema),
24331
- locations: array(RecordingLocationUsageSchema)
24382
+ /**
24383
+ * Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
24384
+ * of the payload without it: the hub serves this method through a BAKED
24385
+ * router, so a hub whose framework train predates a change to this array
24386
+ * strips it out of an answer a newer recorder happily produced. A UI that
24387
+ * dereferences it unconditionally crashes the whole Storage page over a
24388
+ * missing disk bar.
24389
+ */
24390
+ locations: array(RecordingLocationUsageSchema).optional()
24332
24391
  });
24333
24392
  /**
24334
24393
  * The OPERATOR-ARMED half of multi-location recordings (D116).
@@ -33444,8 +33503,13 @@ Object.freeze({
33444
33503
  "network-access": "ingress",
33445
33504
  "smtp-provider": "email"
33446
33505
  });
33447
- new Map(AUDIO_MACRO_LABELS.flatMap((macro) => macro.icon === void 0 ? [] : [[macro.id, macro.icon]]));
33506
+ /** Schema defaults an untouched sub-field must author exactly these. */
33507
+ var NC_AUDIO_DEFAULTS = {
33508
+ hitPercent: 60,
33509
+ samplingSeconds: 10
33510
+ };
33448
33511
  new Set(["devices", "classes"]);
33512
+ NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
33449
33513
  /**
33450
33514
  * TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
33451
33515
  *
@@ -33677,6 +33741,39 @@ TimelapseRuleInputSchema.extend({
33677
33741
  createdAt: number(),
33678
33742
  updatedAt: number()
33679
33743
  });
33744
+ Object.freeze(Object.fromEntries([{
33745
+ stepId: "face-embedding",
33746
+ label: "Face recognition model",
33747
+ defaultModelId: "arcface-r100",
33748
+ indexName: "the enrolled face gallery",
33749
+ options: [
33750
+ {
33751
+ id: "arcface-r100",
33752
+ label: "ArcFace (ResNet34)"
33753
+ },
33754
+ {
33755
+ id: "auraface-r100",
33756
+ label: "AuraFace R100"
33757
+ },
33758
+ {
33759
+ id: "inception-resnet-v1",
33760
+ label: "Inception ResNet V1"
33761
+ }
33762
+ ]
33763
+ }, {
33764
+ stepId: "clip-embedding",
33765
+ label: "Semantic search model",
33766
+ defaultModelId: "mobileclip-s1",
33767
+ indexName: "the object semantic-search index",
33768
+ options: [{
33769
+ id: "mobileclip-s1",
33770
+ label: "MobileCLIP S1"
33771
+ }, {
33772
+ id: "mobileclip-s2",
33773
+ label: "MobileCLIP S2"
33774
+ }]
33775
+ }].map((s) => [s.stepId, s.defaultModelId])));
33776
+ string().min(1);
33680
33777
  object({
33681
33778
  /**
33682
33779
  * Fraction of the box's own size added on EACH side before cutting.
@@ -33697,10 +33794,21 @@ object({
33697
33794
  */
33698
33795
  square: boolean()
33699
33796
  });
33700
- ({
33797
+ /**
33798
+ * The convention in force when nobody has configured one — byte-for-byte the
33799
+ * behaviour of the pre-unification LIVE path (`DETAIL_CROP_PADDING_RATIO`).
33800
+ */
33801
+ var DEFAULT_DETAIL_CROP_CONVENTION = {
33701
33802
  paddingRatio: .15,
33702
33803
  square: false
33703
- }).paddingRatio;
33804
+ };
33805
+ Object.freeze({
33806
+ x: 0,
33807
+ y: 0,
33808
+ w: 1,
33809
+ h: 1
33810
+ });
33811
+ DEFAULT_DETAIL_CROP_CONVENTION.paddingRatio;
33704
33812
  /**
33705
33813
  * WHICH delivered frames the decode worker retains a native copy of.
33706
33814
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-mqtt-broker",
3
- "version": "1.2.22",
3
+ "version": "1.2.24",
4
4
  "description": "MQTT broker registry addon for CamStack — manages external broker entries + an optional embedded aedes broker. Consumers spin up their own `mqtt.js` clients via the `mqtt-broker` cap.",
5
5
  "keywords": [
6
6
  "camstack",