mirror of
https://github.com/ruvnet/RuView
synced 2026-08-11 20:41:44 +00:00
ba978041ae
# Conflicts: # docs/adr/README.md
143 lines
7.5 KiB
Markdown
143 lines
7.5 KiB
Markdown
# 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.
|