# ADR-306: Canonical spatial ontology — one Site→…→Event model for every surface - **Status**: Accepted — initial implementation planned (ADR-300 phase 1) - **Date**: 2026-08-11 - **Deciders**: ruv - **Tags**: ontology, worldgraph, schema, mqtt, matter, rufield, phase-1 ## Context This ADR is a child of **ADR-300** and owns primitive #6, *canonical spatial ontology*. In the ADR-300 DAG it is a spine root alongside **ADR-305** (authenticated identity) and feeds every downstream primitive that must speak about *where* and *what*: **ADR-301** (calibration), **ADR-307** (tracking, consumes `Track`/`Person`), **ADR-319** (witness chain), and every external surface named in the ADR-300 consequences (MQTT, REST, WebSocket, RuField, Matter, agents). RuView currently expresses "where something is" in several overlapping, per-surface schemas: the MQTT/Home-Assistant mapper has its own node/room shapes (**ADR-297** just introduced `NodeInference`/`RoomInference` to disambiguate node vs. room state); the `worldgraph` crate models a spatial graph; RuField carries `SemanticProvenance`; Matter/HomeKit has its own area model. The same physical fact — "a person is in the kitchen" — is re-encoded differently on each surface, and the review called for "one canonical `NodeInference`/`RoomInference` contract" (ADR-297 consequences). Without a single semantic model, every new surface multiplies the translation matrix and each translation is a place where provenance and evidence level (ADR-282) can be silently dropped. Substantial scaffolding already exists and must be **reused/extended, not rebuilt**. `v2/crates/worldgraph/wifi-densepose-worldgraph` already defines: - `WorldNode` variants including `Room { area_id, name, bounds_enu, floor }`, `Zone { parent_room, … }`, `Wall { rf_attenuation_db }`, and `Doorway`. - `WorldEdge` variants including `Observes { quality, last_seen_unix_ms }`, `LocatedIn { since_unix_ms }`, `AdjacentTo { via_doorway }`, and `Supports`. - `WorldGraph`, `WorldGraphSnapshot`, `WorldId`, `SemanticProvenance`, `PersonPosition`, and a HomeCore `area_id` linkage join key (ADR-127). The `worldgraph` crate is therefore the natural home for the canonical model. What is missing is (a) the full `Site → Building → Floor → Space → Zone` containment spine above `Room`, (b) first-class `Sensor`, `Object`, `Observation`, `Track`, and `Event` node types, (c) one canonical serialization that every surface consumes, and (d) a documented migration path from the existing per-surface schemas. ## Options considered 1. **Leave each surface with its own schema; add adapters pairwise.** Rejected: O(surfaces²) translations, and provenance/evidence loss at each hop. 2. **Invent a new top-level ontology crate.** Rejected: `worldgraph` already models rooms, zones, walls, doorways, observation edges, and HomeCore linkage; a parallel crate would fork the world model. 3. **Extend `worldgraph` into the canonical ontology and make every surface a projection of it.** Chosen. ## Decision Adopt **one canonical spatial ontology**, hosted in the `worldgraph` crate, that every RuView surface reads from and writes to. ### 1. The containment spine and entity types Define the full node taxonomy as an extension of the existing `WorldNode`: ``` Site ▸ Building ▸ Floor ▸ Space ▸ Zone └─▸ { Sensor, Person, Object, Observation, Track, Event } ``` - `Site`, `Building`, `Floor`, `Space` are new containment `WorldNode` variants above the existing `Room` (mapped to `Space`, keeping its `area_id` and `bounds_enu`) and `Zone`. `Wall`/`Doorway` remain as topological elements. Containment reuses the existing `LocatedIn`/`AdjacentTo` edge vocabulary; a new `PartOf` edge expresses the pure hierarchy (Zone `PartOf` Space `PartOf` Floor …). - `Sensor` is the entity **ADR-305** authenticates (`DeviceId` as its stable identity) and **ADR-320** (HAL, phase 2) describes the hardware of. `Person`, `Object`, `Observation`, `Track`, and `Event` are first-class nodes. `Observes`/`LocatedIn` edges already carry quality and dwell timestamps. - `Track` and `Person` are defined **here** as the ontology contract that **ADR-307** (persistent tracking) produces and updates. `Observation` is what an authenticated frame (ADR-305) becomes after calibration (ADR-301), and `Event` is the governed output that ADR-318 certifies and ADR-319 witnesses. ### 2. Canonical serialization - A single, versioned serialization (serde-based, stable field names) is the one wire/at-rest representation. Every surface — MQTT/Home-Assistant, REST, WebSocket, RuField observations, Matter/HomeKit, agent queries — is a **projection** of this model, not an independent schema. `NodeInference` and `RoomInference` (ADR-297) become projections of `Sensor→Observes` and the `Space`-level fused inference respectively, so ADR-297's node/room separation is preserved by construction rather than re-encoded per surface. - Every node and edge carries `SemanticProvenance` and exactly one `EvidenceLevel` (L0–L5, ADR-282 policy): the evidence ladder travels *with* the fact across every projection, so no surface can silently upgrade or drop it. ### 3. Migration path - Each existing per-surface schema gets a documented, tested bidirectional mapping to/from the canonical model, plus a migration accessor for consumers reading the old shape (mirroring ADR-297's migration accessor). Surfaces are cut over one at a time; a surface is "canonical" once its projection is the only encoder it uses. Until cutover, the mapping layer is authoritative and round-trip-tested so no fact is lost in translation. - The `worldgraph` HomeCore `area_id` linkage (ADR-127) remains the join key between the ontology's `Space` and external area registries. ## Consequences - The translation matrix collapses from O(surfaces²) to O(surfaces): each surface implements one projection. New surfaces (ROS 2, OpenUSD, OPC UA per ADR-282's roadmap) plug in as additional projections. - Provenance and evidence level are carried uniformly; a fact cannot cross a surface boundary and lose its lineage or its L-level. - A schema change reaching every surface; managed by the versioned serialization and per-surface migration accessors. Single-node deployments keep working (one `Sensor`, one `Space`). - The ontology is a *representation*, not an inference engine: it says nothing about *how* a `Track` or `Event` is produced — that is owned by ADR-307, ADR-301, ADR-302, and the model layer. This ADR does not itself make any accuracy claim to grade. - Extending `worldgraph` grows one crate's surface rather than forking a second world model; the geo/worldmodel sub-crates continue to build on the same node vocabulary. ## Validation - Unit tests (`cargo test -p wifi-densepose-worldgraph`): containment-spine construction and invariants (a `Zone` is `PartOf` exactly one `Space`, a `Space` on exactly one `Floor`, etc.); round-trip serialization of every node and edge type; every node/edge carries exactly one `EvidenceLevel`. - Migration tests: each per-surface schema maps to the canonical model and back with no loss of provenance or evidence level; `NodeInference`/`RoomInference` (ADR-297) project and re-project identically. - Contract test: a single canonical `Event` renders correctly through the MQTT, REST, and WebSocket projections from one source of truth. - No accuracy numbers are claimed; this ADR delivers the shared representation the rest of the phase-1 spine writes into.