Files
ruvnet--RuView/v2/crates/ruview-groundtruth/src/scope.rs
T
Claude 49c594822f feat: implement ADR-297 phase-2 world-model core — HAL, ground-truth, tracking, fusion
The layer that turns the certificate spine into a modality-agnostic perception
substrate. Four crates, all deterministic and green independently (43 tests).

ruview-hal (ADR-317): one abstraction mapping any modality (CSI/802.11bf/BLE/
UWB/mmWave/acoustic/camera/lidar/IMU/custom) to a canonical ontology Observation.
SensorHal trait + two SYNTHETIC/L0 reference adapters; malformed input yields a
degraded UNKNOWN observation, never a panic; synthetic can never alias measured.
8 tests.

ruview-groundtruth (ADR-300): reference sensors as a formal VALIDATION plane
(never an estimator input, enforced by the type boundary); modality-agnostic
ReferenceSeries, deterministic cross-correlation alignment, AgreementReport with
mandatory SessionScope, emitting per-context ruview-evidence records; Measured
requires reference + coverage + reproducer. 15 tests.

ruview-track (ADR-304): privacy-preserving persistent tracks (opaque person ids,
coarse non-reversible features, no civil-identity binding); ambiguous detections
stay tentative rather than misassigned; cross-zone hand-off. 8 tests.

ruview-fusion (ADR-308): multiple HalObservations -> one probabilistic WorldState,
uncertainty-aware (confidence-weighted, not naive averaging); irreconcilable
conflict or insufficient coverage yields UNKNOWN, not a confident average.
9+ tests incl. irreconcilable_conflict_yields_unknown.

Flips ADR-300/304/308/317 to implemented; registers the four crates as workspace
members. SYNTHETIC/L0 throughout; no hardware/MEASURED claims.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_015TcKegTS7QqhWPC2L2SzaS
2026-08-11 03:16:33 +00:00

94 lines
2.9 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Mandatory session scope (ADR-300 §3, mirroring ADR-290).
//!
//! An agreement report without scope cannot be constructed: WiFi-sensing
//! numbers without stated scope (subject count, motion, line-of-sight,
//! distance) are systematically misleading (ADR-290 Context). [`SessionScope`]
//! is a required argument to [`crate::AgreementReport::build`], so the type
//! system enforces the rule.
use serde::{Deserialize, Serialize};
use crate::error::GroundTruthError;
/// The largest subject count accepted, bounding untrusted input.
pub const MAX_SUBJECTS: u16 = 4096;
/// Whether subjects were static or moving during the session.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum MotionState {
/// Subject(s) static / at rest.
Static,
/// Subject(s) moving.
Moving,
/// A mix of static and moving intervals.
Mixed,
}
/// The propagation condition between sensor and subject.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum LineOfSight {
/// Line-of-sight.
Los,
/// Non-line-of-sight (obstructed, same room).
Nlos,
/// Through-wall.
ThroughWall,
}
/// A coarse distance band between sensor and subject.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum DistanceBand {
/// Near (roughly < 2 m).
Near,
/// Mid (roughly 25 m).
Mid,
/// Far (roughly > 5 m).
Far,
}
/// Mandatory metadata attached to every [`crate::AgreementReport`]. A report
/// cannot exist without it, so an agreement number always states the conditions
/// it was measured under.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct SessionScope {
/// Number of subjects present (0 is valid for an empty-room session).
pub subject_count: u16,
/// Motion state during the session.
pub motion: MotionState,
/// Line-of-sight condition.
pub line_of_sight: LineOfSight,
/// Distance band.
pub distance: DistanceBand,
}
impl SessionScope {
/// Construct a validated session scope. `subject_count` is bounded to
/// [`MAX_SUBJECTS`] so untrusted metadata cannot claim an absurd count.
///
/// # Errors
/// [`GroundTruthError::SubjectCountTooLarge`] if `subject_count` exceeds
/// [`MAX_SUBJECTS`].
pub fn new(
subject_count: u16,
motion: MotionState,
line_of_sight: LineOfSight,
distance: DistanceBand,
) -> Result<Self, GroundTruthError> {
if subject_count > MAX_SUBJECTS {
return Err(GroundTruthError::SubjectCountTooLarge {
count: u32::from(subject_count),
max: u32::from(MAX_SUBJECTS),
});
}
Ok(Self {
subject_count,
motion,
line_of_sight,
distance,
})
}
}