RuView BFLD 隐私分级集成指南:Home Assistant 实体、Matter 集群边界与 MQTT ACL 设计
导读:本文基于 RuView 仓库架构决策文档 ADR-122(BFLD RuView Surface),讲解 Beamforming Feedback Layer for Detection(BFLD)如何以**隐私分级(privacy_class)**为骨架接入 Home Assistant、Matter 与 MQTT。读者读完可掌握:六类 BFLD 实体的 HA-DISCO 发现机制、按隐私等级路由的 MQTT 主题树、Mosquitto ACL 默认拒绝策略、Matter 集群的最小暴露边界,以及多节点向 cognitum-v0 联邦汇聚时"在发布节点剥离身份字段"的工程约束。文中同步结合
v2/crates/wifi-densepose-bfld的源码实现进行印证。
1. 背景:为什么 BFLD 需要一层"可被审计的对外表面"
BFLD(ADR-118)从 802.11ac/ax 的波束成形反馈信息(BFI)中提取人员存在、运动、人数、区域活动等感知原语,并计算一个 identity_risk_score(身份泄漏风险分)。它声明的三条结构不变量(I1:原始 BFI 永不离开节点;I2:身份 embedding 仅存内存;I3:跨站点身份关联在密码学上不可能)决定了它的对外接口不能是"一个 JSON 事件全量广播"。
ADR-115 已经为 RuView 部署了基于 wifi-densepose-sensing-server 的 Home Assistant 表面(21 个实体、MQTT 自动发现、mTLS、隐私模式),ADR-116 又把它包装为 cog-ha-matter Cognitum Seed cog。ADR-122 要回答的问题是:BFLD 如何融入这条已经投产的通道,同时不扩大隐私敏感足迹?
它给出的四条设计约束贯穿全文:
- 扩展 HA-DISCO,在既有 MQTT 自动发现机制上广播 BFLD 实体;
- 在 Matter 边界拒绝身份字段——Matter 只暴露 occupancy / motion / people-count,绝不暴露
identity_risk_score或rf_signature_hash; - MQTT 主题按隐私等级路由——class-2/3 事件走公共主题树,class-1 事件走受限的
research/子树,class-0 事件不发往网络; - 向 cognitum-v0 联邦时保持干净——多个节点的事件经
cognitum-rvf-agent(端口 9004)汇聚做跨节点分析,但身份衍生字段在发布节点边界就被剥离,而不是在联邦中心才处理。
实现证据:BFLD 隐私分级在代码中不是口头约定。
BfldEvent序列化时被遮蔽的字段会直接置为None并从 JSON 中整体省略(event.rs),"做过隐私分级的事件"在观测上与"从未拥有该字段的事件"不可区分。
2. 隐私分级速览:一个字节决定能发出什么
ADR-122 的全部门控逻辑都建立在 ADR-120 定义的 privacy_class: u8 字节上。理解本文之前,先明确四个等级:
| Class | 名称 | 适用场景 | 可用字段 |
|---|---|---|---|
| 0 | raw |
本地研究,永不联网 | 全部字段、全精度 BFI 矩阵、身份 embedding |
| 1 | derived |
运营者确认的研究场景(LAN) | 降采样角度矩阵、完整特征、identity_risk_score、身份 embedding |
| 2 | anonymous(默认) |
生产部署 | 仅聚合感知:presence、motion、person_count、zone_id、confidence |
| 3 | restricted |
养老院 / 受监管部署 | Class 2 减去 identity_risk_score 与 rf_signature_hash |
其中 identity_risk_score(身份风险分)只在 class 恰好等于 2 时发布,class 3 下"计算但不发布";identity_risk_score、rf_signature_hash、identity_embedding、原始 BFI 属于 ADR-120 默认拒绝分类表(#[must_classify])中身份相关的敏感字段。
代码层面的分级执行
event.rs 中的 apply_privacy_gating() 是字段遮蔽的幂等实现:
pub fn apply_privacy_gating(&mut self) {
if self.privacy_class.as_u8() >= PrivacyClass::Restricted.as_u8() {
self.identity_risk_score = None;
self.rf_signature_hash = None;
}
}
BfldEvent 的 Serialize derive 配合 skip_serializing_if = "Option::is_none",因此遮蔽字段是"消失"而非"输出 null"(event.rs)。rf_signature_hash 在 JSON 中以 "blake3:<64 位十六进制>" 字符串形式编码,便于下游解析。
3. HA 实体表面:每节点新增六个实体
ADR-122 §2.1 规定 cog 在重发布 ADR-115 已有 21 个实体的基础上,为每个节点新增六个 BFLD 实体:
| Entity ID | 类型 | Source field | Class 门控 | Diagnostic |
|---|---|---|---|---|
binary_sensor.<node>_bfld_presence |
occupancy | BfldEvent.presence |
≥ 2 | 否 |
sensor.<node>_bfld_motion |
gauge [0,1] |
BfldEvent.motion |
≥ 2 | 否 |
sensor.<node>_bfld_person_count |
int | BfldEvent.person_count |
≥ 2 | 否 |
sensor.<node>_bfld_zone_activity |
enum | BfldEvent.zone_activity |
≥ 2 | 否 |
sensor.<node>_bfld_identity_risk |
gauge [0,1] |
BfldEvent.identity_risk_score |
== 2 only | 是 |
sensor.<node>_bfld_confidence |
gauge [0,1] |
BfldEvent.confidence |
≥ 2 | 是 |
关键设计取舍:
identity_risk仅在隐私等级 2(anonymous)下暴露,并被标记entity_category: diagnostic,避免 HA 仪表盘把它提升为主卡片传感器;在 class 3 下它"被计算但从不发布"。- 发现(discovery)payload 遵循 ADR-115 的 schema,并额外携带一个
bfld_version属性,取值与BfldFrameHeader::version字段一致,方便 HA 侧做固件 / 协议版本审计。
源码印证:发现消息的等级门控
ha_discovery.rs 中的 render_discovery_payloads(node_id, class) 是发现消息的纯函数渲染器:
- class <
Anonymous直接返回空Vec——HA 根本看不到 raw / derived 级别的实体存在; - 五个"安全"实体(presence、motion、person_count、zone_activity、confidence)在任何 class ≥ 2 时都渲染,其中 motion / zone_activity / confidence 在
config_message中被标记为diagnostic; identity_risk只有在class == PrivacyClass::Anonymous时才被加入发现集合——这与 ADR-122 §2.1"class 3 下不向 HA 广告该实体"的验收标准 AC2 严格对应。
发现消息与状态消息的生命周期不同:发现消息应当每节点会话发布一次、broker 侧 retain = true(通过 RumqttPublisher::with_retain(true) 实现),而状态主题保持 retain = false,防止陈旧状态抖动。
MQTT 发现:发布方到消费者的最小示例
来自 ha_discovery.rs 的文档式 bootstrap 模式(对应生产代码 examples/bfld_handle.rs):
// Bootstrap: retained "online" + 6 retained HA-DISCO config payloads
publish_availability_online(&mut publisher, "seed-01")?;
publish_discovery(&mut publisher, "seed-01", PrivacyClass::Anonymous)?;
// 启动工作线程:每帧 handle.send(PipelineInput { inputs, embedding })
let handle = BfldPipelineHandle::spawn(
BfldPipeline::new(BfldConfig::new("seed-01")
.with_signature_hasher(SignatureHasher::new(salt))),
publisher,
);
handle.send(PipelineInput { inputs, embedding })?;
availability 主题用于 online/offline 标记(对应 crate src/availability.rs 与测试 availability_topic.rs);class-1 事件若被错误地下发,发布者会在 availability 主题发出 MQTT_RAW_DISABLED 提示。
4. MQTT 主题树:按隐私等级路由
ADR-122 §2.2 规定的主题树(实现见 mqtt_topics.rs):
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 派生的 BFI)根本不出现在发现 payload 里——操作者必须显式订阅并确认研究模式风险。发布 crate 在privacy_class < 1时向 availability 发出MQTT_RAW_DISABLED。zone_activity仅在zone_id存在(多区域部署)时发布,且以 JSON 字符串字面量输出;实现中json_string_literal会转义引号、反斜杠、控制字符,避免区域名中的元字符注入非法 JSON(mqtt_topics.rs)。
为什么是"一实体一主题"而非统一 JSON
ADR-122 §4(Alternatives)明确否决了 ruview/<node>/bfld 单主题 + JSON payload 方案:逐实体主题是 HA-DISCO 的约定(ADR-115),也让 ACL 可以精确到字段级。统一主题会迫使订阅方"要么全读要么全不读",无法区分 identity_risk 与普通运动量。
发布侧的路由渲染实现
render_events(event) 是等级门控的第二个纯函数关卡(mqtt_topics.rs):
- class < 2 的事件返回空向量,raw / derived 只留在本地;
- presence / motion / person_count / confidence 无条件发布;
zone_activity仅当zone_id = Some(_)时发布;identity_risk只在class_byte == Anonymous时发布——class 3(restricted)在内部计算分数,但从不发射到该主题。
测试 mqtt_topic_routing.rs、event_privacy_gating.rs、ha_discovery_publish.rs 分别锁定了路由、遮蔽与发现的这些行为。
5. Mosquitto ACL:默认拒绝 + 角色最小授权
BFLD 的隐私不依赖 broker 的"善意"。ADR-122 §2.3 给出了随 cog 附带的默认 ACL 模板(源码树中按规划位于 cog-ha-matter/etc/mosquitto.acl.d/bfld.conf,供使用内嵌 broker 的操作者使用;仓库内实际可查阅 cog-ha-matter 与 BFLD blueprints 目录):
# 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
这套模板的三层含义:
- 默认拒绝——除
state与availability通配外不授予任何读取; - 公共角色显式被
deny掉identity_risk与raw两个最敏感主题; - operator 角色可读
identity_risk用于诊断,research 角色可读raw(要求节点实际以 class-1 运行——等级在发布侧已把关,broker ACL 是第二道保险)。
这与 ADR-122 验收标准 AC4(默认 mosquitto ACL 拒绝 public 用户读 identity_risk/state)对应。
6. Matter 集群边界:结构化最窄暴露
Matter 是跨厂商表面——一个 Matter 控制器家庭里可能有多个第三方 hub。ADR-122 §2.4 因此把 BFLD 在 Matter 上的暴露压缩到三个集群:
| Matter cluster | Source entity | 说明 |
|---|---|---|
| Occupancy Sensing(0x0406) | binary_sensor.<node>_bfld_presence |
报告二元 occupancy + 从 confidence 映射的 uncertainty |
| Boolean State(0x0045) | sensor.<node>_bfld_motion >= 0.3 |
阈值化后的布尔状态;原始 motion 不暴露 |
| Occupancy Sensing 扩展 | sensor.<node>_bfld_person_count |
Matter 规范支持的 occupancy-sensor 计数能力处使用 |
明确不经过 Matter 暴露的字段清单:
identity_risk_scorerf_signature_hashidentity_embeddingrawBFIzone_activity(区域 ID 是站点特异的,而 Matter 是跨站点表面)confidence(仅 HA 内诊断用)
设计上,ADR-122 规划将 Matter 过滤实现在 cog-ha-matter/src/matter/bfld_filter.rs,作为一个 MatterSink trait 实现,在编译期拒绝 class 0 和 1 的帧(借助 ADR-120 §2.2 的 marker types)。
实现证据(当前仓库内的类型层):BFLD crate 的 sink.rs 已定义完整的 sink 层级——
LocalSink(class 0–3)⊃NetworkSink(class 1–3,拒绝 class 0)⊃MatterSink(仅 class 2/3),并有impl MatterSink for MatterKind {}。也就是说"Matter 只收 anonymous/restricted 帧"在类型系统层面已经成立;而 cog 侧实际的 Matter bridge 生产接线仍处于 ADR-116 P7(依赖 matter-rs 就绪),cog-ha-mattercrate 目前聚焦 cog manifest、mDNS 与 witness 链部分。从源码结构看,MatterSink标记 +sink_enforcement.rs测试把"错误暴露"变成编译错误而非运行时事故。
7. 向 cognitum-v0 的联邦:身份在发布节点就消失
多节点部署中,各节点 BFLD 事件会流经联邦 hub cognitum-rvf-agent(端口 9004)做跨节点分析。ADR-122 §2.5 强调:到达 hub 的事件已经是 class-2/3——身份衍生字段在每个发布节点就被剥离,hub 看不到也无法重建原始 BFI 或身份 embedding。
| 在发布节点 | 在 cognitum-rvf-agent |
|---|---|
| 按 ADR-120 剥离 class-0/1 字段 | 只接收 class-2/3 事件 |
按 ADR-120 §2.3 轮换 rf_signature_hash |
聚合计数;不做跨站点 hash 关联 |
| 用节点 Ed25519 密钥为事件签名 | 验签;拒绝未签名事件 |
配套的 federation-witness 脚本(扩展 ADR-028)在 hub 上每晚运行,证明过去 24 小时接收的事件中未出现任何 class-0/1 字段。ADR-122 §3 指出该机制存在一个"两轮 witness 之间的短窗口泄漏"边界——但由于每日密钥轮换,即使 class-1 字段被成功外泄,也需要被重建为身份才能构成威胁,而日轮换会打断这个过程。
8. HA Blueprints:随 cog 交付的三条开箱自动化
ADR-122 §2.6 规划三条面向操作者的 blueprint,落在 cog-ha-matter/blueprints/。当前仓库已实装于 v2/crates/cog-ha-matter/blueprints/bfld/(含 README):
- Presence-driven lighting(存在驱动照明)——
[presence-lighting.yaml](https://gitcode.com/GitHub_Trending/wi/RuView/blob/c4021f98846cb03759140dcb265b157082b2ef81/v2/crates/cog-ha-matter/blueprints/bfld/presence-lighting.yaml?utm_source=gitcode_repo_files):消费binary_sensor.*_bfld_presence⇒light.turn_on/off,可配置保持时间。 - Motion-aware HVAC(运动感知暖通)——
[motion-hvac.yaml](https://gitcode.com/GitHub_Trending/wi/RuView/blob/c4021f98846cb03759140dcb265b157082b2ef81/v2/crates/cog-ha-matter/blueprints/bfld/motion-hvac.yaml?utm_source=gitcode_repo_files):sensor.*_bfld_motion > 0.3⇒ 将 HVAC 设定点上调 ΔT。 - Identity-risk anomaly notification(身份风险异常通知)——
[identity-risk-anomaly.yaml](https://gitcode.com/GitHub_Trending/wi/RuView/blob/c4021f98846cb03759140dcb265b157082b2ef81/v2/crates/cog-ha-matter/blueprints/bfld/identity-risk-anomaly.yaml?utm_source=gitcode_repo_files):sensor.*_bfld_identity_risk超过滚动 z-score 阈值 ⇒ 向 operator 的notify.*发送含来源节点与 7 天基线的通知。
安装方式:将 .yaml 复制到 HA 的 blueprints/automation/ 目录,或通过 HA UI(Settings → Automations & Scenes → Blueprints → Import)导入。
blueprint 的隐私注意事项(来自 blueprints/bfld/README.md)值得强调:
identity-risk-anomaly.yaml依赖的sensor.*_bfld_identity_risk只在privacy_class = Anonymous(class 2)时存在;class 3(如养老院)下实体根本不会向 HA 广告,该 blueprint 会校验失败——这是设计使然,不是 bug;identity_riskblueprint 的statistics_entity输入要求操作者先创建带 7 天窗口的 HA Statistics helper,blueprint 读取mean+standard_deviation属性计算 z-score。
源码树还配了 blueprint 结构测试:ha_blueprints.rs 在构建期用 include_str! 校验每个 YAML,断言必备字段(blueprint.name、blueprint.domain、input 块、trigger、action、mode)。
9. Soul Signature 部署形态:class-1 专属诊断面,永不进 Matter
当 cog 以 --features soul-signature 编译时(Soul Signature 是 consent-based 的注册人员被动重识别研究,docs/research/soul/),HA 表面额外暴露三个实体——仅限 class 1,且永不经过 Matter:
| Entity ID | 类型 | Source | Class 门控 | Matter |
|---|---|---|---|---|
sensor.<node>_soul_match_id |
string(不透明 person_id) |
Soul Signature match oracle | == 1 only | rejected |
sensor.<node>_soul_match_score |
gauge [0,1] |
Match similarity | == 1 only | rejected |
sensor.<node>_soul_enrollment_quality |
gauge [0,1] |
注册期间的 identity_risk_score 镜像 |
== 1 only | rejected |
这些实体构成运行 Soul Signature 部署(有明确 GDPR Art. 9 依据的养老院、获得同意的雇佣场景等)操作者的 consent-based 诊断面。§2.4 的 Matter 集群边界已经按类型拒绝它们——MatterSink 实现只接受 class-2/3 帧,因此 soul_match_id 在结构上无法经 Matter 触达。
Class-3 部署整体禁用 Soul Signature:match_against_enrolled() 调用返回 MatchOutcome::Suppressed,不发布任何 soul 实体。这使 class 3 成为"同意状态不确定、或监管方要求 Soul Signature 不可用"场景下的正确设置。
第四条 blueprint 仅在启用 --features soul-signature 时交付:
- Enrolled-person arrival notification(注册人员到达通知)——
sensor.*_soul_match_id转为非空值 ⇒ 向注册人配置的联系人(通常是本人或指定照护者)发送notify.*。默认关闭,操作者须按每个注册人员单独 opt-in。
10. 后果评估
正面
- 六个新 HA 实体为操作者提供完整的 BFLD 诊断仪表盘,同时不泄漏身份信息;
- Matter 暴露在结构上很窄——集群过滤实现因类型系统拒绝身份字段,不可能意外泄漏;
- 默认 ACL 模板让操作者开箱即得可用的隐私姿态;
- 联邦契约明确:即便把所有节点事件取并集,hub 也无法重建身份(发布节点已剥离 + 每日轮换)。
负面
identity_riskHA 实体仅在 class 2 下存在——class 3 部署的操作者即使在自家仪表盘也看不到该分数。这是正确的取舍,但可能让养老院安装人员感到意外,文档必须写清;- 三个 Matter 集群偏保守——部分 HA 用户可能希望把人数暴露为百分比或速率,Matter 原生不支持;
- HA blueprint 覆盖面刻意很小——需要自定义自动化的操作者得自己写 YAML。
中性
federation-witness每晚运行,两次 witness 之间的短暂泄漏窗口是存在但有界的;任何成功的 class-1 字段外泄仍须重建为身份才有意义,而每日轮换会破坏重建路径。
11. 验收标准(AC)
- AC1:HA 自动发现首次连接时每个节点发布六个新实体,HA 全部识别;
- AC2:class 3 下
sensor.<node>_bfld_identity_risk从 MQTT 发现 payload 中缺席; - AC3:
MatterSink::publish在源码privacy_class < 2时于编译期拒绝该帧; - AC4:默认 mosquitto ACL 拒绝
public用户角色读取ruview/+/bfld/identity_risk/state; - AC5:三条 HA blueprint 能干净地安装进全新 HA,并能针对 mock BFLD 事件流触发各自动作;
- AC6:
federation-witness脚本能在合成事件中检测到注入的 class-1 字段并非零退出; - AC7:HA
binary_sensor.*_bfld_presence状态变化后 1 秒内 Matter occupancy-sensing 集群报告 presence。
对应仓库测试覆盖:ha_discovery.rs、ha_discovery_publish.rs(AC1/AC2)、sink_enforcement.rs(AC3 类型层)、ha_blueprints.rs(AC5 结构)、pipeline_i3_isolation.rs 与 signature_hasher.rs(跨站点隔离与轮换)。
12. 备选方案回顾
| 备选 | 结论 | 理由 |
|---|---|---|
Alt 1:把 identity_risk 经 Generic Sensor 集群暴露到 Matter |
拒绝 | Matter 是跨厂商表面,暴露风险分会泄漏给家庭内每个 Matter 控制器(包括操作者无法控制的第三方 hub);保持 HA 内部 |
Alt 2:统一 MQTT 主题 ruview/<node>/bfld + JSON |
拒绝 | 逐实体主题是 HA-DISCO 约定,且让 ACL 字段级可配;统一主题导致全有或全无的读取策略 |
| Alt 3:把原始 BFI 联邦到 cognitum-v0 做跨节点分析 | 拒绝 | 违反 ADR-120 I1(raw 永不离开节点);聚合足够跨节点分析,raw 集中化是硬性禁区 |
Alt 4:identity_risk 默认非 diagnostic |
拒绝 | 把身份邻近的仪表盘 gauge 提到主卡片会惊吓操作者;diagnostic 分类是正确的默认值 |
13. 相关资源与延伸阅读
- 架构总纲:ADR-118 BFLD 总览,子 ADR 链:ADR-119(帧格式)、ADR-120(隐私分级与 hash 轮换)、ADR-121(身份风险评分)、ADR-123(采集路径)
- 宿主表面:ADR-115 HA 集成、ADR-116 cog-ha-matter、ADR-031 sensing-first RF 模式
- BFLD 设计卷宗:docs/research/BFLD/;Soul Signature 配套研究:docs/research/soul/
- 核心实现:wifi-densepose-bfld crate 说明、event.rs、mqtt_topics.rs、ha_discovery.rs、sink.rs
- 随 cog 交付的 blueprint:presence-lighting.yaml、motion-hvac.yaml、identity-risk-anomaly.yaml
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00