docs/adr/ADR-122-bfld-ruview-ha-matter-exposure.md
| Field | Value |
|---|---|
| Status | Proposed |
| Date | 2026-05-24 |
| Deciders | ruv |
| Parent | ADR-118 |
| Relates to | ADR-031 (sensing-first), ADR-100 (cog packaging), ADR-115 (HA-DISCO + HA-MIND), ADR-116 (Matter cog), ADR-120 (privacy class) |
| Tracking issue | TBD |
ADR-115 shipped the RuView Home Assistant surface (21 entities, MQTT auto-discovery, mTLS, privacy mode) on the wifi-densepose-sensing-server Rust binary. ADR-116 is packaging this as the cog-ha-matter Cognitum Seed cog. BFLD must integrate into this surface without expanding the privacy-sensitive footprint already in production.
The integration must:
identity_risk_score or rf_signature_hash.research/ subtree, class-0 events nowhere.cognitum-rvf-agent (port 9004 per CLAUDE.local.md) for cross-node analytics, but identity-derived fields are stripped at the publishing-node boundary, not at the federation hub.The cog republishes the existing 21 ADR-115 entities and adds:
| Entity ID | Type | Source field | Class gate | Diagnostic |
|---|---|---|---|---|
binary_sensor.<node>_bfld_presence | occupancy | BfldEvent.presence | ≥ 2 | no |
sensor.<node>_bfld_motion | gauge [0,1] | BfldEvent.motion | ≥ 2 | no |
sensor.<node>_bfld_person_count | int | BfldEvent.person_count | ≥ 2 | no |
sensor.<node>_bfld_zone_activity | enum | BfldEvent.zone_activity | ≥ 2 | no |
sensor.<node>_bfld_identity_risk | gauge [0,1] | BfldEvent.identity_risk_score | == 2 only | yes |
sensor.<node>_bfld_confidence | gauge [0,1] | BfldEvent.confidence | ≥ 2 | yes |
The identity_risk entity is exposed only under privacy class 2 and is flagged entity_category: diagnostic so HA dashboards do not promote it to a main-card sensor by default. Under class 3 it is computed but not published (per ADR-121 §2.4).
MQTT discovery payload follows the ADR-115 schema, plus a bfld_version attribute matching the BfldFrameHeader::version field.
ruview/<node_id>/bfld/presence/state # class >= 2
ruview/<node_id>/bfld/motion/state # class >= 2
ruview/<node_id>/bfld/person_count/state # class >= 2
ruview/<node_id>/bfld/zone_activity/state # class >= 2
ruview/<node_id>/bfld/confidence/state # class >= 2
ruview/<node_id>/bfld/identity_risk/state # class == 2 only
ruview/<node_id>/bfld/raw # class 1, OFF by default
ruview/<node_id>/bfld/availability # online/offline marker
raw (class-1 derived BFI) is not present in the discovery payload at all — operators must explicitly subscribe and acknowledge the research-mode caveat. The publishing crate emits MQTT_RAW_DISABLED to availability when privacy_class < 1.
# Default-deny everything not explicitly granted
pattern read ruview/+/bfld/+/state
pattern read ruview/+/bfld/availability
# Public roles cannot read identity_risk or raw
user public
deny read ruview/+/bfld/identity_risk/state
deny read ruview/+/bfld/raw
# Operator role can read identity_risk for diagnostics
user operator
allow read ruview/+/bfld/identity_risk/state
# Research role can read raw (requires class-1 operation)
user research
allow read ruview/+/bfld/raw
The cog ships a default ACL template under cog-ha-matter/etc/mosquitto.acl.d/bfld.conf for operators who use the embedded broker (ADR-116 §2.2).
cog-ha-matter exposes BFLD via three Matter clusters only:
| Matter cluster | Source entity | Notes |
|---|---|---|
| Occupancy Sensing (0x0406) | binary_sensor.<node>_bfld_presence | reports binary occupancy + uncertainty (mapped from confidence) |
| Boolean State (0x0045) | sensor.<node>_bfld_motion >= 0.3 | thresholded; raw motion not exposed |
| Occupancy Sensing extension | sensor.<node>_bfld_person_count | uses occupancy-sensor count where Matter spec supports |
Explicitly NOT exposed via Matter:
identity_risk_scorerf_signature_hashidentity_embeddingraw BFIzone_activity (zone IDs are site-specific and Matter is a cross-site surface)confidence (HA-only diagnostic)The Matter filter is implemented in cog-ha-matter/src/matter/bfld_filter.rs as a MatterSink trait impl that rejects classes 0 and 1 at compile time (via ADR-120 §2.2 marker types).
cognitum-rvf-agent (port 9004) receives BFLD events from multiple nodes. The events arriving at the federation hub are already class-2/3 — identity-derived fields were stripped at each publishing node. The hub does not see and cannot reconstruct raw BFI or identity embeddings.
The federation contract:
| At publishing node | At cognitum-rvf-agent |
|---|---|
| Strip class-0/1 fields per ADR-120 | Receive class-2/3 events only |
Rotate rf_signature_hash per ADR-120 §2.3 | Aggregate counts; do not correlate hashes across sites |
| Sign event with node Ed25519 key | Verify signature; reject unsigned events |
A federation-witness script (extending ADR-028) runs nightly on the hub and proves that no class-0/1 fields appeared in any received event over the previous 24 h.
Three operator-ready blueprints under cog-ha-matter/blueprints/:
binary_sensor.*_bfld_presence ⇒ light.turn_on/off with configurable hold time.sensor.*_bfld_motion > 0.3 ⇒ raise HVAC setpoint by ΔT.sensor.*_bfld_identity_risk exceeds rolling z-score threshold ⇒ HA notify.* to the operator with the originating node and the 7-day baseline.identity_risk HA entity exists only under class 2. Operators who run class 3 deployments cannot see the score even in their own dashboard. This is correct but may surprise care-home installers; documentation must be clear.identity_risk over Matter (Generic Sensor cluster)Rejected: Matter is a cross-vendor surface; exposing identity-risk there leaks the score to every Matter controller in the home, including third-party hubs the operator may not control. Keep it HA-internal.
ruview/<node>/bfld with JSON payloadRejected: per-entity topics are the HA-DISCO convention (ADR-115) and let ACLs be field-specific. A unified topic forces an all-or-nothing read policy.
Rejected: violates ADR-120 I1 (raw never leaves the node). Aggregates are sufficient for cross-node analytics; raw centralization is a hard no.
entity_category: diagnostic = false for identity_riskRejected: promoting identity_risk to a main-card sensor would surprise operators with an identity-adjacent gauge on their main dashboard. Diagnostic category is the right default.
sensor.<node>_bfld_identity_risk is absent from the MQTT discovery payload.MatterSink::publish rejects any frame at compile time when the source has privacy_class < 2.read ruview/+/bfld/identity_risk/state to the public user role.binary_sensor.*_bfld_presence state change.cog-ha-matter cog packaging)http://cognitum-v0:9000/