mirror of
https://github.com/ruvnet/RuView
synced 2026-08-03 19:21:42 +00:00
926c66f677
Iter 13. Lands ADR-121 §2.1 (output event) + ADR-122 §2.1 (field-gating
policy). BfldEvent collapses the GateAction-driven sensing pipeline
into the canonical wire-format publishable on MQTT.
Added:
- serde (workspace, derive feature, optional) + serde_json (workspace, optional) deps
- New crate feature `serde-json` (default-on; requires `std`)
- src/event.rs (gated on `feature = "std"`):
* BfldEvent struct with all sensing + identity-derived fields
* with_privacy_gating(...) constructor that applies field-gating policy:
class < Restricted (3): identity_risk_score + rf_signature_hash kept
class >= Restricted (3): both nulled to None
* apply_privacy_gating() — idempotent in-place masking
* to_json() -> Result<String, serde_json::Error> (gated on serde-json)
* Custom ser_privacy_class serializer emits lowercase names
("anonymous", "restricted", etc.) per the BFLD JSON spec
* skip_serializing_if = "Option::is_none" on identity-derived fields so
privacy-gated events are observationally indistinguishable from
events that never had the field set
- pub use BfldEvent from lib.rs
tests/event_privacy_gating.rs (9 named tests, all green):
anonymous_event_retains_identity_risk_and_hash
restricted_event_strips_identity_fields (class 3 → None)
apply_privacy_gating_is_idempotent
event_type_is_always_bfld_update (parameterized over 3 classes)
json::json_round_trip_emits_type_field_first_or_last_but_present
json::anonymous_json_includes_identity_fields
json::restricted_json_omits_identity_fields_entirely
(asserts the JSON string does NOT contain identity_risk_score or
rf_signature_hash, verifying skip_serializing_if works as intended)
json::privacy_class_serializes_to_lowercase_name
json::zone_id_none_is_omitted_from_json
ACs progressed:
- ADR-121 AC6 (identity_risk score absent at class 3) — structurally
enforced by with_privacy_gating + skip_serializing_if combination.
- ADR-122 AC1 — JSON shape matches the HA-DISCO publishable event
contract; identity fields can be reliably stripped by privacy_class.
- ADR-118 AC5 — privacy_mode = engaged maps to PrivacyClass::Restricted
with no identity fields in the published event.
Test config:
- cargo test --no-default-features → 64 passed (unchanged; event cfg-out)
- cargo test → 102 passed (93 + 9)
Out of scope (next iter target):
- Emitter struct that wires GateAction + privacy class + sensing inputs
into BfldEvent construction (ADR-118 §2.1 pipeline diagram).
- MQTT topic publisher (ADR-122 §2.2) — depends on a runtime (tokio).
Co-Authored-By: claude-flow <ruv@ruv.net>
45 lines
1.3 KiB
TOML
45 lines
1.3 KiB
TOML
[package]
|
|
name = "wifi-densepose-bfld"
|
|
description = "BFLD — Beamforming Feedback Layer for Detection. Privacy-gated WiFi BFI sensing primitives. See ADR-118."
|
|
version.workspace = true
|
|
edition.workspace = true
|
|
authors.workspace = true
|
|
license.workspace = true
|
|
repository.workspace = true
|
|
documentation.workspace = true
|
|
keywords.workspace = true
|
|
categories.workspace = true
|
|
|
|
[features]
|
|
default = ["std", "serde-json"]
|
|
std = []
|
|
# JSON serialization for BfldEvent (ADR-121 §2.1, ADR-122 §2.1). Pulls in
|
|
# serde + serde_json; tied to `std` because serde_json is std-only.
|
|
serde-json = ["std", "dep:serde", "dep:serde_json"]
|
|
# Soul Signature integration (ADR-118 §1.4, ADR-120 §2.7, ADR-121 §2.6) —
|
|
# enables privacy_class = 1 (derived) mode and the SoulMatchOracle gate
|
|
# exemption. Disabled by default per the structural class-2 default.
|
|
soul-signature = []
|
|
|
|
[dependencies]
|
|
thiserror.workspace = true
|
|
static_assertions = "1.1"
|
|
crc = "3"
|
|
serde = { workspace = true, features = ["derive"], optional = true }
|
|
serde_json = { workspace = true, optional = true }
|
|
|
|
[dev-dependencies]
|
|
proptest.workspace = true
|
|
|
|
[lints.rust]
|
|
unsafe_code = "forbid"
|
|
missing_docs = "warn"
|
|
|
|
[lints.clippy]
|
|
all = "warn"
|
|
pedantic = "warn"
|
|
nursery = "warn"
|
|
module_name_repetitions = "allow"
|
|
missing_const_for_fn = "allow"
|
|
missing_panics_doc = "allow"
|