mirror of
https://github.com/ruvnet/RuView
synced 2026-07-15 16:13:18 +00:00
Merge PR #1312: wire WDP_GUARD_INTERVAL_US/WDP_TDM_* into EngineBridge
This commit is contained in:
@@ -230,6 +230,17 @@ impl StreamingEngine {
|
||||
/// cycle on, the adapter id is part of provenance `model_version` — and
|
||||
/// therefore of the witness — so the exact weights shaping inference are
|
||||
/// pinned in the trust chain. Pass the result of hashing the adapter file.
|
||||
/// Override the multistatic fuser's timestamp guard interval (#1049/#1057).
|
||||
/// Without this, `StreamingEngine::new` always builds
|
||||
/// `MultistaticFuser::with_config(MultistaticConfig::default())` — a
|
||||
/// hardcoded 60 ms hard guard that ignores whatever schedule/override the
|
||||
/// caller derived from `WDP_TDM_SLOTS`/`WDP_GUARD_INTERVAL_US`, so
|
||||
/// WiFi/ESP-NOW-synced multi-node deployments spuriously fail governed
|
||||
/// trust cycles even after widening the guard elsewhere.
|
||||
pub fn set_multistatic_config(&mut self, cfg: MultistaticConfig) {
|
||||
self.fuser = MultistaticFuser::with_config(cfg);
|
||||
}
|
||||
|
||||
pub fn set_room_adapter(&mut self, info: AdapterInfo) {
|
||||
self.adapter = Some(info);
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ use wifi_densepose_bfld::{PrivacyClass, PrivacyMode};
|
||||
use wifi_densepose_engine::{AdapterInfo, EngineError, StreamingEngine, TrustedOutput};
|
||||
use wifi_densepose_geo::types::GeoRegistration;
|
||||
use wifi_densepose_signal::ruvsense::fusion_quality::CalibrationId;
|
||||
use wifi_densepose_signal::ruvsense::multistatic::MultistaticConfig;
|
||||
use wifi_densepose_worldgraph::WorldId;
|
||||
|
||||
use super::multistatic_bridge::node_frames_from_states;
|
||||
@@ -79,8 +80,24 @@ pub struct EngineBridge {
|
||||
impl EngineBridge {
|
||||
/// Build a bridge for one installation. `room_area_id`/`room_name` name the
|
||||
/// observation scope; `mode` is the starting privacy mode.
|
||||
pub fn new(mode: PrivacyMode, model_version: u16, room_area_id: &str, room_name: &str) -> Self {
|
||||
///
|
||||
/// `multistatic_cfg` is `None` on the pure default (60 ms/20 ms guard);
|
||||
/// callers that derive a config from `WDP_TDM_SLOTS`/`WDP_GUARD_INTERVAL_US`
|
||||
/// (see `main.rs::multistatic_guard_config_from_env`) should pass it here
|
||||
/// too — otherwise the governed trust cycle silently keeps using the
|
||||
/// hardcoded default even though the sibling `multistatic_fuser` field on
|
||||
/// `AppState` picked up the override (#1049/#1057).
|
||||
pub fn new(
|
||||
mode: PrivacyMode,
|
||||
model_version: u16,
|
||||
room_area_id: &str,
|
||||
room_name: &str,
|
||||
multistatic_cfg: Option<MultistaticConfig>,
|
||||
) -> Self {
|
||||
let mut engine = StreamingEngine::new(mode, model_version, GeoRegistration::default());
|
||||
if let Some(cfg) = multistatic_cfg {
|
||||
engine.set_multistatic_config(cfg);
|
||||
}
|
||||
let room = engine.add_room(room_area_id, room_name);
|
||||
Self {
|
||||
engine,
|
||||
@@ -267,7 +284,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn empty_states_produce_no_belief() {
|
||||
let mut bridge = EngineBridge::new(PrivacyMode::PrivateHome, 1, "living_room", "Living Room");
|
||||
let mut bridge = EngineBridge::new(PrivacyMode::PrivateHome, 1, "living_room", "Living Room", None);
|
||||
let out = bridge.process_cycle_from_states(&HashMap::new(), 1_000);
|
||||
assert!(out.is_none());
|
||||
// No belief published, no sensor wired.
|
||||
@@ -276,7 +293,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn live_cycle_produces_witnessed_belief_with_provenance() {
|
||||
let mut bridge = EngineBridge::new(PrivacyMode::PrivateHome, 1, "living_room", "Living Room");
|
||||
let mut bridge = EngineBridge::new(PrivacyMode::PrivateHome, 1, "living_room", "Living Room", None);
|
||||
let states = two_node_states();
|
||||
let out = bridge
|
||||
.process_cycle_from_states(&states, 10_000)
|
||||
@@ -299,7 +316,7 @@ mod tests {
|
||||
fn live_path_is_deterministic() {
|
||||
let states = two_node_states_fixed();
|
||||
let run = || {
|
||||
let mut b = EngineBridge::new(PrivacyMode::PrivateHome, 1, "r", "R");
|
||||
let mut b = EngineBridge::new(PrivacyMode::PrivateHome, 1, "r", "R", None);
|
||||
b.process_cycle_from_states(&states, 5_000).unwrap().unwrap()
|
||||
};
|
||||
let a = run();
|
||||
@@ -325,7 +342,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn nodes_registered_once_across_cycles() {
|
||||
let mut bridge = EngineBridge::new(PrivacyMode::PrivateHome, 1, "r", "R");
|
||||
let mut bridge = EngineBridge::new(PrivacyMode::PrivateHome, 1, "r", "R", None);
|
||||
let states = two_node_states();
|
||||
bridge.process_cycle_from_states(&states, 1_000);
|
||||
bridge.process_cycle_from_states(&states, 2_000);
|
||||
@@ -336,7 +353,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn retention_bounds_world_graph_growth() {
|
||||
let mut bridge = EngineBridge::new(PrivacyMode::PrivateHome, 1, "r", "R");
|
||||
let mut bridge = EngineBridge::new(PrivacyMode::PrivateHome, 1, "r", "R", None);
|
||||
bridge.set_semantic_retention(5);
|
||||
let states = two_node_states();
|
||||
for i in 0..20i64 {
|
||||
@@ -349,7 +366,7 @@ mod tests {
|
||||
#[test]
|
||||
fn adapter_identity_flows_into_live_witness() {
|
||||
let states = two_node_states_fixed();
|
||||
let mut bridge = EngineBridge::new(PrivacyMode::PrivateHome, 1, "r", "R");
|
||||
let mut bridge = EngineBridge::new(PrivacyMode::PrivateHome, 1, "r", "R", None);
|
||||
let base = bridge
|
||||
.process_cycle_from_states(&states, 1_000)
|
||||
.unwrap()
|
||||
@@ -381,7 +398,7 @@ mod tests {
|
||||
/// the status endpoint, with a zero error count on the happy path.
|
||||
#[test]
|
||||
fn observe_cycle_records_trust_state() {
|
||||
let mut bridge = EngineBridge::new(PrivacyMode::PrivateHome, 1, "r", "R");
|
||||
let mut bridge = EngineBridge::new(PrivacyMode::PrivateHome, 1, "r", "R", None);
|
||||
assert!(bridge.last_trust_witness().is_none());
|
||||
assert_eq!(bridge.effective_class(), None);
|
||||
|
||||
@@ -430,7 +447,7 @@ mod tests {
|
||||
m
|
||||
}
|
||||
|
||||
let mut bridge = EngineBridge::new(PrivacyMode::PrivateHome, 1, "r", "R");
|
||||
let mut bridge = EngineBridge::new(PrivacyMode::PrivateHome, 1, "r", "R", None);
|
||||
let mismatched = mismatched_states();
|
||||
|
||||
assert!(bridge.observe_cycle(&mismatched, 1_000).is_none());
|
||||
@@ -461,7 +478,7 @@ mod tests {
|
||||
/// mapping bfld's privacy gate applies at `Restricted`.
|
||||
#[test]
|
||||
fn restricted_class_suppresses_raw_outputs() {
|
||||
let mut bridge = EngineBridge::new(PrivacyMode::PrivateHome, 1, "r", "R");
|
||||
let mut bridge = EngineBridge::new(PrivacyMode::PrivateHome, 1, "r", "R", None);
|
||||
bridge.set_privacy_mode(PrivacyMode::StrictNoIdentity); // base = Restricted
|
||||
bridge
|
||||
.observe_cycle(&two_node_states(), 1_000)
|
||||
@@ -472,7 +489,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn identity_strict_mode_is_carried_into_provenance() {
|
||||
let mut bridge = EngineBridge::new(PrivacyMode::PrivateHome, 1, "r", "R");
|
||||
let mut bridge = EngineBridge::new(PrivacyMode::PrivateHome, 1, "r", "R", None);
|
||||
bridge.set_privacy_mode(PrivacyMode::StrictNoIdentity);
|
||||
let out = bridge
|
||||
.process_cycle_from_states(&two_node_states(), 7_000)
|
||||
|
||||
@@ -7514,6 +7514,11 @@ async fn main() {
|
||||
let field_surface: rufield_surface::FieldState =
|
||||
Arc::new(RwLock::new(rufield_surface::FieldSurface::from_env()));
|
||||
|
||||
// Populated inside the `multistatic_fuser` field initializer below, then
|
||||
// threaded into `engine_bridge` so both fusion paths honor the same
|
||||
// WDP_TDM_SLOTS/WDP_GUARD_INTERVAL_US-derived guard (#1049/#1057).
|
||||
let mut engine_bridge_multistatic_cfg: Option<MultistaticConfig> = None;
|
||||
|
||||
let state: SharedState = Arc::new(RwLock::new(AppStateInner {
|
||||
latest_update: None,
|
||||
rssi_history: VecDeque::new(),
|
||||
@@ -7588,7 +7593,7 @@ async fn main() {
|
||||
);
|
||||
let mut fuser = MultistaticFuser::with_config(MultistaticConfig {
|
||||
min_nodes: 1, // single-node passthrough
|
||||
..cfg
|
||||
..cfg.clone()
|
||||
});
|
||||
if let Some(ref pos_str) = args.node_positions {
|
||||
let positions = field_bridge::parse_node_positions(pos_str);
|
||||
@@ -7600,6 +7605,10 @@ async fn main() {
|
||||
fuser.set_node_positions(positions);
|
||||
}
|
||||
}
|
||||
engine_bridge_multistatic_cfg = Some(MultistaticConfig {
|
||||
min_nodes: 1,
|
||||
..cfg
|
||||
});
|
||||
fuser
|
||||
},
|
||||
engine_bridge: engine_bridge::EngineBridge::new(
|
||||
@@ -7607,6 +7616,7 @@ async fn main() {
|
||||
1,
|
||||
"default",
|
||||
"Default Room",
|
||||
engine_bridge_multistatic_cfg,
|
||||
),
|
||||
field_model: if args.calibrate {
|
||||
info!("Field model calibration enabled — room should be empty during startup");
|
||||
|
||||
Reference in New Issue
Block a user