RuView Evidence Engine 深度解析:为物理感知而生的 Append-Only 精度账本(ADR-304 与 `ruview-evidence` 实现)
2026/9/10 14:13:09 网站建设 项目流程

RuView Evidence Engine 深度解析:为物理感知而生的 Append-Only 精度账本(ADR-304 与ruview-evidence实现)

【免费下载链接】RuViewπ RuView turns commodity WiFi signals into real-time spatial intelligence, vital sign monitoring, and presence detection — all without a single pixel of video.项目地址: https://gitcode.com/GitHub_Trending/wi/RuView

导读

本文以 RuView 感知基座项目(perception-substrate program,ADR-300)中的第 4 号原语——证据引擎(Evidence Engine,ADR-304)为主题,结合其参考实现 cratev2/crates/ruview-evidence,讲解 RuView 如何用一套"按 (房间, 设备, 主体) 上下文分片的、只追加的、诚实分级"的账本,来回答 OEM 与集成商真正关心的问题:"这个模型在这个房间、这台设备、这个主体上到底表现如何?校准还有多新鲜?"。读完本文,你将理解证据引擎的设计动机、EvidenceRecord/EvidenceLedger/EvidenceSlice三类核心对象的用法与不变量,以及它在能力证书(ADR-318)、基准计分板(ADR-317)、见证链(ADR-319)中所处的枢纽位置。


一、为什么物理感知需要"MLflow",而不是又一个仪表盘

ADR-304 文档开门见山:"MLflow made ML experiments trackable; physical sensing needs the equivalent for deployed accuracy, drift, and evidence level"——MLflow 让机器学习实验可追踪,而物理感知(WiFi CSI 感知)需要的是部署后精度、漂移与证据级别的可追踪。这是两者本质的区别:

  • 实验期追踪:模型还在训练,指标可以被覆盖、被迭代;
  • 部署期追踪:模型已经在真实房间跑推理,昨天的数字被今天的数字覆盖,等于抹掉了退化历史。

RuView 的战略评估(ADR-300)把该原语判定为比又一套姿态网络更有商业价值:真正能打开 OEM 与集成商对话的不是更高的头条精度数字,而是一份"可辩护、可审计"的记录,说明模型在具体房间、具体设备、具体主体上、随时间推移到底表现如何。因此证据引擎的形态是一个追加式(append-only)账本(ledger),而不是"会覆盖昨天的数字"的仪表盘。

ADR-304 明确它复用了项目内已有资产,而非重新发明:

  • RuField 的 provenance/signature 类型(ADR-260/262/277/279)—— 现成的签名、带来源记录类型;
  • AetherArena 见证账本模式(ADR-149)—— 只追加、见证锚定的计分结果账本,作为结构模板;
  • frame::EvidenceLevelL0–L5(ADR-282)—— 每条记录必须携带的证据级别;
  • ADR-302 的DomainState、ADR-137 的QualityScore、ADR-301 的证书版本与年龄 —— 需要逐条累积的按推理信号。

在 ADR-300 的原始语映射表(docs/adr/ADR-300-perception-substrate-program.md)中,证据引擎是第 4 号原语,所属 Phase 1(证书骨干),上游是 OOD 检测(ADR-302)与校准证书(ADR-301),下游对接能力证书(ADR-318)与真实基准服务(ADR-317)。


二、方案取舍:为什么不用 MLflow,也不写普通文件

ADR-304 记录了三类候选方案及否决理由:

  1. 把精度写进普通文件 / 指标仪表盘—— 被否决:可变的、未签名、无上下文范围、无法跨时间比较,这正是要填补的缺口。
  2. 直接复用通用实验追踪器(如 MLflow)—— 被否决:它是"实验期"工具而非"部署期"工具;没有房间/设备/主体上下文的概念,不懂校准年龄、证据级别或签名 provenance;还会引入外部服务依赖,违背基座"边缘优先、依赖最小"的方向。
  3. 构建原生只追加证据账本,复用 RuField 记录类型与 AetherArena 账本模式—— 被采纳。

被采纳的决策原文是:构建一个证据引擎——按(room, device, subject)为键的只追加精度账本,每个模型都会自动写入。而参考实现随后进一步把键细化成四元组(room, device, subject-class, model-version)(见下文)。


三、实现落地:ruview-evidencecrate 的整体设计

证据引擎的参考实现位于 v2/crates/ruview-evidence/src/lib.rs,是一个刻意保持**叶子化(leaf)、确定性(deterministic)、诚实(honest)**的纯 Rust crate:

  • Leaf:只依赖serde/thiserrorEvidenceLevel阶梯在本地镜像定义(避免把 frame crate 拉进来);
  • Deterministic:不读墙钟、不用随机数,记录时间由调用方注入,账本只分配单调递增的追加序号;
  • Honest by construction:证据级别由写入时的 provenance 固定,账本记录只能通过只读引用被访问——不可变、不可升级在类型层面被保证。

模块顶部用#![forbid(unsafe_code)]强制无 unsafe 代码,这与文档中"边界校验、不 panic"的工程纪律一致。

3.1 常量与 ID 边界

  • MAX_ID_LEN = 256:任何上下文标识字符串的最大字节长度,用于在不可信输入边界限制分配(注释明确引用 CLAUDE.md);
  • DEFAULT_MAX_RECORDS = 1_000_000:单个账本默认持有的记录上限,可用EvidenceLedger::with_capacity调高或调低——防止失控生产者耗尽内存。

3.2EvidenceLevel:L0–L5 的忠实本地镜像

实现中的EvidenceLevel枚举与 ADR-282 §4 定义在frame::EvidenceLevel上的语义一一对应,其#[derive(PartialOrd, Ord)]使顺序承载逻辑(summary 的"取地板"规则直接取min),JSON 序列化采用SCREAMING_SNAKE_CASEL0L5):

级别语义(ADR-282)
L0仅仿真 / 合成,无信号证据
L1采集回放 / 启发式证据
L2受控单一场景信号证据
L3互证 / 留出房间与主体验证
L4已校准的多站点现场证据
L5生产、经见证 / 认证(ADR-319)

ADR-304 强调这个阶梯是"忠实本地拷贝,而非独立刻度",且每条EvidenceRecord恰好携带一个EvidenceLevel

3.3ProvenanceClass:精度声明的"诚实标签"

pub enum ProvenanceClass { Synthetic, // 仿真器/生成器产出 —— 结构上就是 L0(ADR-276/301) Claimed, // 真实推理,但没有 ADR-303 真值参照背书精度 Measured, // 由 ADR-303 参照 + 复现句柄背书 }

关键规则:类别由所用构造器决定,无法别名——合成输入永远不能被铸造成Measured。这对应 ADR-304 正文"引擎无法提升证据级别;级别在写入时由 provenance 决定"的诚实纪律。


四、EvidenceContext:账本按部署上下文分片的键

pub struct EvidenceContext { pub room: String, // 空间/房间 id(ADR-306) pub device: String, // 签名设备 id(ADR-305) pub subject_class: String, // 经同意/可得的主体类别;空串 = "无主体" pub model_version: String, // 产生推理的模型版本(ADR-136) }
  • 身份由调用方提供(ADR-306 空间 id、ADR-305 签名设备 id),本 crate 把这些字段当作不透明的、有界句柄,绝不自行发明。
  • EvidenceContext::new在边界做双重校验:room/device/model_version必须非空,所有字段(含可空的subject_class)长度受MAX_ID_LEN约束;违规返回EvidenceError::EmptyFieldEvidenceError::IdTooLong
  • 值得注意:ADR-304 正文写的键是(room, device, subject),实现扩展为subject_class并附加model_version——因为部署精度必须按模型版本隔离,且"主体 id 只在经主体同意时才可用",空串表示"无主体"而非缺失信息。

五、AccuracyMetricsEvidenceRecord:一条记录装什么

AccuracyMetrics是一个窗口内精度指标的紧凑载体(字段均带严格的边界校验validate()):

字段含义校验规则
moving_recall移动主体召回率[0,1]且有限
stationary_recall静止主体召回率[0,1]且有限
false_positive_rate误报率[0,1]且有限
drift与 ADR-301 校准基线的指纹距离幅值有限且非负
uncertainty预测不确定性有限且非负
calibration_age_secs生效中的校准证书年龄(秒,ADR-301)u64
sample_count本条记录汇总的推理数必须 ≥ 1(保证聚合权重非零)

EvidenceRecord承载context + metrics + level + class + reproducer + timestamp_ns + seq,其中所有字段都是私有的:没有 setter、没有&mut访问器,因此级别无法被升级、记录无法原地修改——"更正是一条新记录"。

构造器决定 provenance 与级别,实现层面有三个:

// 1) 合成记录:强制 L0 + Synthetic,无路可升(ADR-304 §3) EvidenceRecord::synthetic(context, metrics, timestamp_ns)?; // 2) 声称记录:真实推理但无 ADR-303 参照;级别由调用方按 provenance 设定, // 但绝不允许 L0(L0 保留给合成输入)——否则返回 SyntheticOnlyL0 EvidenceRecord::claimed(context, metrics, level, timestamp_ns)?; // 3) 测量记录:精度由 ADR-303 参照背书,必须携带非空且不超过上限的 reproducer 句柄 EvidenceRecord::measured(context, metrics, level, reproducer, timestamp_ns)?;

timestamp_ns由调用方注入(本 crate 永不自行读时钟,保证确定性);seqappend前为None,入账后由账本盖章。


六、EvidenceLedger:只追加账本的三条核心 API

// 新建空账本(默认上限 1_000_000 条),或给定上限 EvidenceLedger::new(); EvidenceLedger::with_capacity(max_records); // 追加:按值消费记录,盖上单调递增 seq 后存储; // 满员时返回 LedgerFull,失控生产者无法耗尽内存 let seq: u64 = ledger.append(record)?; // 只读视图;只返回恰好匹配该上下文的记录(保证单上下文) let slice: EvidenceSlice = ledger.query(&context);

设计要点:

  1. append按值消费记录,调用方无法保留句柄去修改已存副本,追加式在类型层面成立;
  2. records()只返回共享引用,整个 crate 不存在返回可变引用的 API,测试注释明说:"如果存在&mut访问器,本测试就需要改;它不存在,正是这个不变量";
  3. query永不跨上下文——切片只含与给定 context 等值的记录,"把两个上下文平均成一个数"的 API 在结构上不存在;
  4. summarize()返回每个上下文各一条摘要,绝不产生跨上下文的全局平均(对应 ADR-304 Consequences:"never paper over a thin context with a global average")。

七、EvidenceSlice::summarize:纯函数聚合的精确语义

聚合是一次对追加日志在查询时刻的纯函数——账本是真相源,摘要是派生值,永远不是权威(呼应 CLAUDE.md 的 "source over summaries" 规则)。其不变量值得逐条看:

  • 空上下文 →NoEvidence:与"存在但精度为 0"是两种不同结果。下游(ADR-318)必须把 "no evidence" 当作"没有能力",而不是0.0分;
  • 级别取地板(floor/min):切片摘要级别 = 各记录级别的最小值。一条 L4 的强测量记录如果与一条 L0 合成记录同处一个上下文,摘要被钉在 L0——切片永远不能报出高于其最弱记录的水平
  • 聚合类别不可升级:只有所有记录都是Measured,摘要类别才是Measured;任何更弱的记录(Synthetic/Claimed)都会把聚合类别降级;
  • 数值聚合规则moving_recall/stationary_recall/false_positive_rate/uncertainty采用sample_count 加权平均driftcalibration_age_secs输出"最新记录(按 seq 取最大者)的当前值 + 历史最大值";sample_count求和;由于每条记录sample_count ≥ 1,除数永不为零;
  • 确定性summarize()不依赖墙钟,同一条输入日志反复聚合约等(测试summarize_is_deterministic_and_serde_round_trips同时验证了 JSON round-trip 稳定)。

ContextSummary结构永远携带其所属EvidenceContext,并有has_evidence()方法区分AggregatedNoEvidence——摘要不可能被误读成全局汇总。


八、错误模型与容量安全:一切越界都是返回值,不 panic

EvidenceError覆盖账本所有输入边界(docs/adr/ADR-304-evidence-engine.md的 Validation 强调"no variant panics;malformed input is always a returned error",对齐 CLAUDE.md):

错误变体触发场景
EmptyField { field }必填上下文字段为空
IdTooLong { field, len, max }上下文/reproducer 标识超MAX_ID_LEN
RateOutOfRange { field, value }比率指标超出[0,1]或非有限
NegativeMagnitude { field, value }幅值指标为负或非有限
ZeroSamplessample_count为 0
SyntheticOnlyL0非合成记录试图以 L0 铸造
MissingReproducer测量记录缺 reproducer 句柄
LedgerFull { max }追加时已达容量上限

九、测试如何锁住不变量:src/lib.rs内置单元测试

ruview-evidence在源码文件底部直接内嵌约十组测试,是理解 ADR-304 语义最直接的"可执行规格"(见 v2/crates/ruview-evidence/src/lib.rs 的mod tests):

  • append_assigns_monotonic_seq_and_query_filters_by_context—— 序号 0/1/2 单调递增;query(kitchen)只命中 kitchen 的两条记录,且断言切片内每条context()都等于 kitchen;
  • records_are_append_only_no_in_place_edit—— "更正"以第二条measured记录追加;原记录seq=0sample_count=100reproducer="repro-1"保持原样未被改动;
  • no_pooling_across_contexts—— kitchen 好(recall=1.0)、bedroom 差(recall=0.0),summarize()返回两条独立摘要;测试注释点明"若存在全局平均它会得到 0.5 并掩盖差上下文——API 不提供该值";
  • evidence_level_floor_is_the_minimum_never_an_upgrade—— L4 测量记录 + L0 合成记录 → 摘要级别被钉在L0、聚合类别被降为Synthetic
  • synthetic_is_forced_l0_and_cannot_be_upgraded—— 合成记录级别必为 L0;claimed(…, L0, …)返回SyntheticOnlyL0;类型无set_level
  • empty_context_is_no_evidence_not_zero_accuracy—— 从未出现过的上下文query为空、has_evidence()为假、枚举等于NoEvidence,显式断言它不是Aggregated的零精度摘要;
  • summarize_is_deterministic_and_serde_round_trips—— 同样输入两次聚合结果相等;加权平均验算(权重 100/300 → recall=0.8);级别取 L3、L4 的地板 L3;JSON round-trip 等值;
  • boundary_validation_rejects_malformed_input_without_panicking—— 空 room →EmptyField、超长 id →IdTooLongmoving_recall=1.5RateOutOfRangeuncertainty=NaNNegativeMagnitudesample_count=0ZeroSamples、空 reproducer →MissingReproducer
  • ledger_capacity_is_bounded—— 容量 1 的账本第二条追加返回LedgerFull { max: 1 }

ADR-304 的 Validation 还规划了跨 ADR 测试ruview-evidence要能够摄取 ADR-302 的DomainState(Phase 2 再摄取 ADR-303 的一致性报告);一份 ADR-318 测试从账本切片铸证书、一份 ADR-317 测试从账本读取精度。真实部署证据(来自带 ADR-303 参照的实时 ESP32 捕获、已填充的账本)是成熟度里程碑,按 CLAUDE.md 要求硬件证据;合成账本按构造即为 L0。


十、在证书骨干中的枢纽位置:账本如何被下游消费

证据引擎不是孤立组件,而是 ADR-300 证书骨干(certificate spine)的"精度事实源":

  1. 能力证书(ADR-318)从账本铸成:ADR-318 明确"能力证书是对账本某一片段的签名证明(signed attestation over a slice of the ledger)"。其上的moving_recall/stationary_recall/false_presence_per_24h从 ADR-304 账本按精确上下文切片而来(非全局平均),每条如实标注;若账本对该上下文报 "no evidence",则不发证——缺失证据永不是能力(见 docs/adr/ADR-318-capability-certificates.md)。证书不能升级其铸造来源账本的级别(ADR-304 诚实规则)。
  2. 真实基准服务(ADR-317)从账本读取真实精度源,替代 PR 里的自报数字,成为每次合并的精度闸门。
  3. 见证链(ADR-319)与账本共用同一套只追加、签名、见证锚定的基础设施,ADR-304 记录与 ADR-301/ADR-317/ADR-318 产物一起写入同一根链;"更正即新链/新记录"与 ADR-304 追加式互为镜像。
  4. OOD 门控(ADR-302)把每次推理的DomainState(KNOWN/DEGRADED/UNKNOWN)与四个输入一并写入证据记录;校准证书(ADR-301)的版本与年龄随每条记录累积——这使"账本 + 校准年龄"能回答"这个能力现在还算数吗"。

用 ADR-304 Consequences 的话说:RuView 从此对一个问题是单一可审计答案——"这个模型在这里、在这台设备、对这个主体到底工作得多好?校准有多新鲜?"——这正是 OEM/集成商尽职调查真正要的产物。


十一、取舍与代价:诚实的另一面

ADR-304 同样记录了这一设计的代价与边界:

  • 存储与密钥管理成本:签名 + 只追加设计必然比覆写式仪表盘更重,但通过"按上下文保留策略"限制规模,并复用现有 RuField/见证基础设施而非新建存储;
  • 稀疏或不讨喜的上下文:有些上下文只会显示稀疏甚至难看的证据。把这些如实暴露正是目的——引擎绝不能拿全局平均去遮盖一个薄弱的上下文;
  • 空上下文语义:"no evidence" 与 0 精度严格区分,下游必须把前者视为"无能力",避免把"从未测过"伪装成"测出 0 分"。

若要进一步阅读本方案在项目中的上下文,建议按依赖顺序查看:程序框架 ADR-300 → 校准证书 ADR-301 → OOD 门控 ADR-302 → 真值同步(Phase 2 上游)ADR-303 → 能力证书 ADR-318 与见证链 ADR-319;证据级别阶梯的权威定义见 ADR-282。


小结:一张会拒绝撒谎的账本

证据引擎把三个看似平凡的设计决策——追加式、按上下文、provenance 定级——做成了类型级不变量:更正只能是新记录,聚合绝不跨上下文求平均,摘要级别永远是切片内最小值,空上下文报 "no evidence" 而非零分。对于以 WiFi 射频感知为核心的 RuView 而言,这正是把"论文里的模型精度"转译为"可交付、可审计、会过期、可辩护的部署事实"所缺的那一层基础设施。

【免费下载链接】RuViewπ RuView turns commodity WiFi signals into real-time spatial intelligence, vital sign monitoring, and presence detection — all without a single pixel of video.项目地址: https://gitcode.com/GitHub_Trending/wi/RuView

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询