mirror of
https://github.com/ruvnet/RuView
synced 2026-07-14 16:03:18 +00:00
docs(worldgraph,worldmodel): add crates.io READMEs
Plain-language overviews + feature lists, comparison tables (symbolic graph vs predictive occupancy; graph vs grid vs event-log), usage, and technical details. Adds readme = "README.md" to both manifests so they render on crates.io on the next release. Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
[package]
|
||||
name = "wifi-densepose-worldgraph"
|
||||
description = "ADR-139 — WorldGraph environmental digital twin (typed petgraph) for RuView"
|
||||
readme = "README.md"
|
||||
version = "0.3.0"
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
# wifi-densepose-worldgraph
|
||||
|
||||
**The environmental digital twin for RF sensing — a typed, evidence-tracked graph of a building and the people in it.**
|
||||
|
||||
[](https://crates.io/crates/wifi-densepose-worldgraph)
|
||||
[](https://docs.rs/wifi-densepose-worldgraph)
|
||||
|
||||
Part of the [RuView / WiFi-DensePose](https://github.com/ruvnet/RuView) project. Implements **ADR-139**.
|
||||
|
||||
---
|
||||
|
||||
## What it is (plain language)
|
||||
|
||||
When you sense a space with WiFi/RF (people, motion, vital signs), you get a firehose of *frames*.
|
||||
What you actually want is a **living map**: which rooms exist, where the walls and doorways are, which
|
||||
sensors watch which zones, where each person is right now, and *why the system believes that* — with
|
||||
enough structure to reason over and enough provenance to trust.
|
||||
|
||||
`wifi-densepose-worldgraph` is that map. It's a **typed graph** (built on [`petgraph`](https://crates.io/crates/petgraph)):
|
||||
|
||||
- **Nodes** are real things — `Room`, `Zone`, `Wall`, `Doorway`, `Sensor`, `RfLink`, `PersonTrack`, `ObjectAnchor`, `Event`, and `SemanticState` (a belief).
|
||||
- **Edges** are typed relations — `Observes`, `LocatedIn`, `AdjacentTo`, `Supports`, `Contradicts`, `DerivedFrom`, `PrivacyLimitedBy`.
|
||||
|
||||
It stores **fused beliefs, not raw frames** — it sits *downstream* of signal fusion and *upstream* of the
|
||||
semantic/agent layer. Every belief (`SemanticState`) is required to carry **provenance**: the signal
|
||||
evidence, the model, the calibration id, and the privacy decision that produced it. That's enforced
|
||||
*structurally*, so "where did this conclusion come from?" always has an answer.
|
||||
|
||||
## Why a graph (and not an occupancy grid or an event log)?
|
||||
|
||||
| Approach | Good at | Misses |
|
||||
|---|---|---|
|
||||
| **Raw event log** | append-only history, audit | no structure; can't ask "who's in the kitchen?" without re-deriving it |
|
||||
| **Occupancy grid / voxels** | dense geometry, ML input | no identity, no relations, no provenance, no semantics |
|
||||
| **Scene graph (this crate)** | relations, identity, semantics, provenance, privacy | not a dense field — pair it with a grid for ML (see [`wifi-densepose-worldmodel`](https://crates.io/crates/wifi-densepose-worldmodel)) |
|
||||
|
||||
The graph is the **symbolic, interpretable** layer. It answers *relational* questions ("is this person in a
|
||||
zone observed by sensor X?", "are these two beliefs contradictory?") in O(neighbors), and it keeps the
|
||||
*why* attached to every *what*.
|
||||
|
||||
## Features
|
||||
|
||||
- 🧱 **Typed node/edge model** — a closed `enum` schema (serde-tagged) → deterministic, schema-versioned wire format.
|
||||
- 🧭 **Geometry in ENU meters** — rooms/zones/walls/doorways carry East-North-Up bounds; walls carry `rf_attenuation_db`.
|
||||
- 🧠 **Beliefs with mandatory provenance** — `SemanticState` → `SemanticProvenance { signal evidence, model, calibration_id, privacy_decision }`.
|
||||
- 🔀 **Evidence reasoning built in** — `Supports` / `Contradicts` / `DerivedFrom` edges let you score and challenge conclusions, not just store them.
|
||||
- 🔒 **Privacy as a first-class edge** — `PrivacyLimitedBy` + `apply_privacy_mode()` roll up what a given mode/action is allowed to see.
|
||||
- 💾 **Deterministic JSON persistence** — `to_json` / `from_json` (the RVF payload), schema-versioned.
|
||||
- 🚫 **`#![forbid(unsafe_code)]`**, `missing_docs = warn`. Pure Rust, no async, edge-deployable (builds clean on aarch64 — runs on a Raspberry Pi).
|
||||
|
||||
## Install
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
wifi-densepose-worldgraph = "0.3"
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```rust
|
||||
use wifi_densepose_worldgraph::{WorldGraph, WorldNode, WorldEdge, ZoneBoundsEnu};
|
||||
// (GeoRegistration comes from wifi-densepose-geo — it anchors ENU to a real lat/lon origin)
|
||||
|
||||
let mut wg = WorldGraph::new(registration);
|
||||
|
||||
// Add a room and a sensor that observes it.
|
||||
let living_room = wg.upsert_node(WorldNode::Room {
|
||||
id: Default::default(),
|
||||
area_id: Some("living_room".into()),
|
||||
name: "Living Room".into(),
|
||||
bounds_enu: ZoneBoundsEnu { /* … */ },
|
||||
floor: 0,
|
||||
});
|
||||
let sensor = wg.upsert_node(/* WorldNode::Sensor { … } */);
|
||||
wg.add_edge(sensor, living_room, WorldEdge::Observes { quality: 0.9, last_seen_unix_ms: now });
|
||||
|
||||
// Query relations.
|
||||
let watched = wg.observed_by(sensor); // what this sensor sees
|
||||
let room = wg.room_for_area("living_room"); // area_id → room node
|
||||
|
||||
// Record a belief WITH provenance, and a contradiction against it.
|
||||
wg.add_semantic_state(/* state + SemanticProvenance */);
|
||||
wg.add_contradiction(belief_a, belief_b, /* magnitude */, "two sensors disagree");
|
||||
|
||||
// Privacy rollup for a mode/action, then persist.
|
||||
let rollup = wg.apply_privacy_mode("HOME", "occworld_inference", |node| /* allow? */ true);
|
||||
let bytes = wg.to_json()?; // RVF payload
|
||||
let restored = WorldGraph::from_json(&bytes)?;
|
||||
```
|
||||
|
||||
## Technical details
|
||||
|
||||
- **Backing store:** `petgraph::StableDiGraph` (stable indices across removals) wrapped as `WorldGraph`.
|
||||
- **Identity:** every node has a `WorldId`; `upsert_node` is idempotent on identity.
|
||||
- **Snapshots:** `snapshot()` → `WorldGraphSnapshot` (a serializable point-in-time view) with a `PrivacyRollup`.
|
||||
- **Schema versioning:** `SCHEMA_VERSION` is embedded in the JSON; the closed enum model means readers fail fast on incompatible payloads rather than silently mis-parsing.
|
||||
- **Coordinates:** ENU (East/North/Up) meters relative to a `GeoRegistration` origin (`wifi-densepose-geo`), so the twin can be georeferenced to a real building.
|
||||
- **Position in the pipeline:** `fusion (ADR-137) → WorldGraph (ADR-139) → semantic/agent layer (ADR-140) → eval harness (ADR-145)`. For **forward prediction** (where will people be next?), pair it with [`wifi-densepose-worldmodel`](https://crates.io/crates/wifi-densepose-worldmodel), which turns `PersonTrack` history into predicted occupancy + trajectory priors.
|
||||
|
||||
## Related crates
|
||||
|
||||
| Crate | Role |
|
||||
|---|---|
|
||||
| [`wifi-densepose-worldmodel`](https://crates.io/crates/wifi-densepose-worldmodel) | Forward **prediction** — occupancy world model over this graph's tracks |
|
||||
| [`wifi-densepose-geo`](https://crates.io/crates/wifi-densepose-geo) | Geospatial registration (ENU ↔ lat/lon, DEM, OSM) |
|
||||
|
||||
## License
|
||||
|
||||
Licensed as the parent project. See the [repository](https://github.com/ruvnet/RuView).
|
||||
@@ -1,6 +1,7 @@
|
||||
[package]
|
||||
name = "wifi-densepose-worldmodel"
|
||||
description = "ADR-147 — OccWorld thin-client bridge: WorldGraph PersonTrack history → OccWorld Python subprocess → TrajectoryPrior"
|
||||
readme = "README.md"
|
||||
version = "0.3.0"
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
# wifi-densepose-worldmodel
|
||||
|
||||
**Forward prediction for RF sensing — turn where people *were* into where they'll *be*, as occupancy + trajectory priors.**
|
||||
|
||||
[](https://crates.io/crates/wifi-densepose-worldmodel)
|
||||
[](https://docs.rs/wifi-densepose-worldmodel)
|
||||
|
||||
Part of the [RuView / WiFi-DensePose](https://github.com/ruvnet/RuView) project. Implements **ADR-147**.
|
||||
|
||||
---
|
||||
|
||||
## What it is (plain language)
|
||||
|
||||
[`wifi-densepose-worldgraph`](https://crates.io/crates/wifi-densepose-worldgraph) tells you **what the room is
|
||||
*now*** (who's where, the walls, the doorways). This crate answers the next question: **what happens *next*?**
|
||||
|
||||
It's a **thin, async client** to an *occupancy world model* (OccWorld). You give it a short history of where
|
||||
people have been (their `PersonTrack` positions); it rasterizes that into 3-D occupancy grids, ships them to
|
||||
an OccWorld inference process, and gets back:
|
||||
|
||||
- **predicted future occupancy** (the model rolls the scene forward N steps), and
|
||||
- **`TrajectoryPrior`s** — per-person predicted waypoints you can feed straight into a Kalman pose tracker to
|
||||
stabilize and *anticipate* movement (e.g. someone heading for a doorway).
|
||||
|
||||
It is **camera-free and privacy-first**: the world model reasons over **occupancy voxels**, not video — so it
|
||||
predicts *where*, never *who-looks-like-what*. (This is the deliberate contrast with pixel-space robot world
|
||||
models like ByteDance's IRASim: same "predict-the-future-conditioned-on-state" idea, kept in occupancy space
|
||||
for privacy and edge deployment.)
|
||||
|
||||
## Where it sits
|
||||
|
||||
```
|
||||
RF frames → fusion → WorldGraph (what is) ──PersonTrack history──► wifi-densepose-worldmodel
|
||||
▲ │
|
||||
│ OccWorld inference (Python subprocess)
|
||||
└────────── TrajectoryPriors (what's next) ◄──────┘
|
||||
(injected back into the Kalman tracker)
|
||||
```
|
||||
|
||||
## Symbolic vs predictive — the two halves of the world model
|
||||
|
||||
| | `wifi-densepose-worldgraph` | `wifi-densepose-worldmodel` (this crate) |
|
||||
|---|---|---|
|
||||
| **Question** | "What is the room *now*?" | "What happens *next*?" |
|
||||
| **Representation** | typed symbolic graph (rooms, tracks, beliefs) | dense 3-D occupancy voxels + trajectory priors |
|
||||
| **Nature** | interpretable, evidential, provenance-tracked | predictive, learned (OccWorld) |
|
||||
| **Compute** | pure Rust, microseconds, edge | Rust client + GPU inference subprocess |
|
||||
| **Output** | relations & beliefs | future occupancy + per-person waypoints |
|
||||
|
||||
Use them together: the graph supplies tracks + privacy decisions; this crate predicts forward and feeds the
|
||||
priors back.
|
||||
|
||||
## Features
|
||||
|
||||
- 🔌 **Thin async bridge** — `OccWorldBridge` talks to the OccWorld inference process over a Unix socket (newline-delimited JSON request/response).
|
||||
- 🧊 **Occupancy rasterization** — `worldgraph_to_occupancy()` turns person positions + scene bounds into a 3-D voxel grid (`200 × 200 × 16` by default; `CLASS_PERSON` / `CLASS_FREE` semantics).
|
||||
- 🧭 **ENU ↔ voxel mapping** — `SceneBounds::to_voxel_xy()` / `to_voxel_z()` with a configurable resolution (e.g. 0.1 m).
|
||||
- 🛰️ **Trajectory priors** — predicted per-`track_id` waypoints, ready for Kalman injection.
|
||||
- 🔁 **Backend-swappable** — the request/response contract (`OccupancyWorldModelRequest` → response with `confidence` + `trajectory_priors`) is model-agnostic (OccWorld today, RoboOccWorld / others later).
|
||||
- 🔒 **Privacy-gated by design** — meant to be called only when the WorldGraph's privacy mode permits it (ADR-141); reasons over occupancy, never pixels.
|
||||
- 🚫 **`#![forbid(unsafe_code)]`**, `missing_docs = warn`.
|
||||
|
||||
## Install
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
wifi-densepose-worldmodel = "0.3"
|
||||
```
|
||||
|
||||
> The bridge uses Unix domain sockets (`tokio`), so the client targets Unix-like hosts (Linux/macOS — e.g. a Raspberry Pi appliance). The data types (occupancy, bounds, priors) are platform-agnostic.
|
||||
|
||||
## Usage
|
||||
|
||||
```rust
|
||||
use wifi_densepose_worldmodel::{
|
||||
OccWorldBridge, OccupancyWorldModelRequest, SceneBoundsJson, worldgraph_to_occupancy,
|
||||
};
|
||||
use wifi_densepose_worldmodel::occupancy::{PersonPosition, SceneBounds};
|
||||
|
||||
# async fn example() -> Result<(), wifi_densepose_worldmodel::WorldModelError> {
|
||||
let bridge = OccWorldBridge::new("/tmp/occworld.sock");
|
||||
|
||||
let bounds = SceneBounds { min_e: -10.0, min_n: -10.0, max_e: 10.0, max_n: 10.0 };
|
||||
let persons = vec![PersonPosition { track_id: 1, east_m: 2.0, north_m: 3.0, up_m: 1.0 }];
|
||||
|
||||
// Rasterize current positions → an occupancy frame (0.1 m voxels).
|
||||
let frame = worldgraph_to_occupancy(&persons, &bounds, 0.1);
|
||||
|
||||
// Ask OccWorld to roll the scene forward 15 steps.
|
||||
let response = bridge.predict(OccupancyWorldModelRequest {
|
||||
past_frames: vec![frame],
|
||||
voxel_resolution_m: 0.1,
|
||||
scene_bounds: SceneBoundsJson { min_e: bounds.min_e, min_n: bounds.min_n,
|
||||
max_e: bounds.max_e, max_n: bounds.max_n },
|
||||
prediction_steps: 15,
|
||||
}).await?;
|
||||
|
||||
println!("confidence={:.2}", response.confidence);
|
||||
for prior in &response.trajectory_priors {
|
||||
println!("track {} → {} predicted waypoints", prior.track_id, prior.waypoints.len());
|
||||
}
|
||||
# Ok(())
|
||||
# }
|
||||
```
|
||||
|
||||
## Technical details
|
||||
|
||||
- **Wire protocol:** newline-delimited JSON over a Unix socket; one request → one response. The Python side
|
||||
(OccWorld) loads `PersonTrack` history as a `(B, F, H, W, D)` occupancy tensor and returns predicted voxels
|
||||
decoded into `TrajectoryPrior`s.
|
||||
- **Grid:** `GRID_WIDTH=200 × GRID_HEIGHT=200 × GRID_DEPTH=16` voxels by default; `CLASS_PERSON=10`,
|
||||
`CLASS_FREE=17` (RuView indoor class remap from the nuScenes outdoor set).
|
||||
- **Resolution:** configurable meters-per-voxel; `to_voxel_xy`/`to_voxel_z` handle ENU→index.
|
||||
- **Backend:** OccWorld (1.65 GB VRAM, ~375 ms/inference on an RTX-class GPU; runs on the Pi+Hailo appliance
|
||||
tier). Cosmos is the deferred heavier alternative (ADR-148).
|
||||
- **Provenance:** predictions carry the originating `calibration_id` + privacy decision so downstream
|
||||
consumers can gate on quality and consent (ADR-141).
|
||||
|
||||
## Related crates
|
||||
|
||||
| Crate | Role |
|
||||
|---|---|
|
||||
| [`wifi-densepose-worldgraph`](https://crates.io/crates/wifi-densepose-worldgraph) | The symbolic twin ("what is") that supplies the tracks this crate predicts from |
|
||||
|
||||
## License
|
||||
|
||||
Licensed as the parent project. See the [repository](https://github.com/ruvnet/RuView).
|
||||
Reference in New Issue
Block a user