# Oya Domain — Architecture

> Architectural overview of Oya, the embodied-robotics "hive" domain: a
> performance-critical Rust engine, napi/wasm FFI bridges with bit-for-bit
> Rust↔TypeScript parity, a canonical contracts surface, a TypeScript platform
> layer, and fifteen Fastify control/coordination services — with an honest
> account of what is built versus legacy versus planned.

---

Oya is the Oshun platform's domain for **embodied autonomous robots operating as
one coordinated fleet** — what the code consistently calls _the embodied hive_.
A hive is a heterogeneous mix of physical machines: aerial drones, wheeled
ground robots, stair-climbers, floor-care units (vacuum/mop), and
manipulator-equipped robots, all sharing **one spatial world model, one safety
envelope, and one market-based task allocator**. Named after the Yoruba goddess
of winds, storms, and transformation, Oya spans the full stack from real-time
flight control and ISO/TS 15066 human-robot safety up to fleet economics and a
home-robot product surface (eldercare, pet care, security, ambient sensing).

This is a substantial, genuinely implemented system — roughly a thousand tracked
source files. An **earlier generation** of the domain was a single large
TypeScript library, `@oya/core` (≈101 modules of drone primitives). That library
still exists, but the code now describes it as the layer the services are
_migrating off of_: the performance-critical core has been ported to a Rust
engine, and the services call that engine through FFI bridges. The previous
version of this page described Oya as "entirely a library domain… no running
applications or services yet, all TypeScript." That is no longer true and this
rewrite corrects it: there are 15 services under `apps/oya/`, a 21-crate Rust
workspace under `libs/oya/engine/`, and a canonical contracts package — all with
tests.

---

## The Shape of the System

Oya is organised as five cooperating layers. Control and data flow downward from
the product/service tier, through the typed platform libraries and the canonical
contracts, across the FFI seam, into the Rust engine — and telemetry flows back
up. The hard architectural rule visible throughout the code is a **separation
between coordination and control**: the fleet orchestrator _assigns work and
reserves space-time_ but never emits a motor command; only the flight gateway
and on-robot control loops energise actuators, behind a fail-closed gate.

```mermaid
flowchart TB
  subgraph svc["Service tier — apps/oya/ (15 Fastify services)"]
    ctl["§4.1 control/safety plane\nflight-gateway · assistant · director · perception"]
    coord["§4.2 coordination/application plane\nfleet-orchestrator · mission · energy · dock ·\nfloorcare · home-map · hri · manipulation ·\nambient · eldercare · pet"]
  end
  subgraph libs["TypeScript platform — libs/oya/*"]
    core2["fastify-core · service-lib · sdk"]
    plat["database · event-publisher/handlers ·\nprivacy · security · maintenance · readiness-gates"]
    legacy["legacy: @oya/core (101 mods) +\nsibling readiness evaluators"]
  end
  contracts["@oshun/contracts/oya\n(canonical .strict() wire schemas)"]
  subgraph ffi["FFI seam — libs/oya/{node-bridge,wasm-bridge}"]
    napi["napi-rs → .node (Node services)"]
    wasm["wasm-bindgen → wasm32 (operator dashboard)"]
  end
  engine["Rust engine — libs/oya/engine/ (21 crates)\noya-types · math · estimation · swarm · mavlink ·\ncontrol · navigation · perception · cinematography ·\ndsp · floorcare · energy · safety · fleet · mapping ·\nscenegraph · manipulation · locomotion · ambient · comms"]

  ctl --> contracts
  coord --> contracts
  ctl --> core2
  coord --> core2
  coord --> plat
  contracts --> napi
  core2 --> napi
  napi --> engine
  wasm --> engine
  contracts -. "schema parity" .- engine
  napi -. "differential parity test" .- legacy
```

---

## Layer 1 — The Rust Engine (`libs/oya/engine/`)

The engine is the authoritative, performance-critical core. It is a **per-domain
Cargo workspace** (there is no monorepo-root Rust workspace; this mirrors
`libs/maya/engine-core`), declared in `libs/oya/engine/Cargo.toml` with 21
member crates, `resolver = "2"`, and a release profile tuned for
embedded/real-time use (`lto = true`, `codegen-units = 1`). Each crate is
greenfield Rust written against plain `f64`/SI types and `serde`; several carry
their own `benches/`, `tests/`, and `examples/`.

The crates group by responsibility:

**Foundations.** `oya-types` (`crates/oya-types/src/lib.rs`) is the type
vocabulary: branded UUID-v4 IDs (`DroneId`, `SwarmId`, `MissionId`,
`WaypointId`), geodetic/quaternion/Euler math types, the three coordinate frames
(`GPSCoordinates`, `LocalCoordinates`, `BodyCoordinates`), the flight/state/
airspace enums, and the composite records (`Telemetry`, `Mission`, `FlightPlan`,
`GeofenceZone`, …). Critically, every type derives `serde` with
`#[serde(rename_all = "camelCase")]` so its JSON wire format is **identical** to
the TypeScript `@oya/core`/contracts payloads, and its validators
(`is_valid_uuid_v4`, `Quaternion::is_unit`, `is_valid` range checks) mirror the
Zod schemas — its test module explicitly "re-proves the TypeScript schema's
accept/reject behavior." `oya-math` supplies the numeric toolkit: Vincenty and
Haversine geodesy, coordinate transforms, kinematics, CRC, lookup tables, and a
`simd` module.

**Estimation & navigation.** `oya-estimation` (IMU/GNSS/VIO/INS fusion, Mahony
AHRS, calibration, ZUPT, event-camera, `gps_security`), `oya-navigation` (A\*,
minimum-snap trajectories, potential-field and sampling planners, social-aware
avoidance), `oya-mapping` (TSDF, occupancy grids, pose-graph SLAM,
relocalization, multi-floor/multi-session, fiducials), and `oya-scenegraph` (the
hierarchical `Building → Floor → Room → Object` scene graph plus a
freshness-tracked spatial memory with a fail-loud `QueryResult`).

**Multi-robot coordination.** `oya-swarm` implements reciprocal collision
avoidance in depth — `orca`, `orca3d`, `nh_orca`, `rvo`, buffered Voronoi,
collision-cone and collision-probability, consensus, formations, the Hungarian
assignment, and `task_allocation`. `oya-fleet` holds the market allocator (CBBA
auction, coalition formation, MAPF). `oya-comms` provides the hive's nervous
system: gossip, a bandwidth-aware scheduler, descriptor exchange, access
control, and PTP/IEEE-1588 `timesync`.

**Control & protocol.** `oya-control` runs the flight/motion stack — SO(3)
attitude control, velocity/position loops, control allocation, motor-failure
compensation, feedforward, and a full mission lifecycle (`mission_modes`,
`mission_rth`, `mission_validate`). `oya-mavlink` is a from-scratch MAVLink2
implementation: codec, message signing (`sha256`/`signing`), the mission/
parameter/FTP/camera/gimbal sub-protocols, PX4 and ArduPilot dialects, a router,
a `tx_queue`, and reliability/high-latency handling (with a `fuzz_decode` test).

**Perception, cinematography, audio.** `oya-perception` (filters, two-view and
multi-view geometry, reconstruction, tracking), `oya-cinematography` (shot
library, camera-MAPF, multicam orchestration, continuity, trajectory generation
— consumed by the dashboard for path preview), and `oya-dsp` (AEC, beamforming,
FFT, VAD, wake-word, barge-in — the audio front-end for human-robot interaction,
with a real-time audio-path test).

**Embodiment & home autonomy.** This is what makes Oya a _hive_ rather than a
drone library: `oya-manipulation` (IK, grasp synthesis, grip control, whole-body
control, visual servoing, real-time action chunking), `oya-locomotion`
(locomotion-mode arbitration, morphing/reconfiguration, stair-climbing,
telescoping/foldable arms, perch-latching, dock reservation, cost-of-transport,
a capability passport), `oya-floorcare` (boustrophedon coverage-path planning
over a cellular decomposition, dynamic anytime replanning, multi-robot Voronoi
partition with failure-reabsorption, carpet detection, dirt-adaptive cleaning),
`oya-energy` (SOC/SOH, battery-swap, charge-banding, dock sizing, grid
scheduling, perch overwatch, wear), and `oya-ambient` (mmWave-radar CFAR,
range-Doppler, CSI, UWB, sensor-fusion presence detection).

**Safety.** `oya-safety` (`crates/oya-safety/src/lib.rs`) is the
functional-safety heart: ISO/TS 15066 **speed-and-separation monitoring**
(`ssm`, the protective separation `Sp = Sh + Sr + Ss + C + Zd + Zr`),
**power-and-force limiting** (`pfl`, reduced mass, transient contact energy,
per-body-region limits), a **control-barrier-function shield** (`cbf`, min-norm
velocity projection into the safe set), indoor `flight_safety` guards,
`edge_safety` (cliff/stair/threshold drop detection), and `child_safety`
interlocks — every one fail-closed. `oya-integration-tests` exercises the crates
together through a `pipeline.rs`.

---

## Layer 2 — FFI Bridges and Rust↔TS Parity

The engine reaches TypeScript through two thin bridges, each exposing a **typed
subset** of the crates (not the whole engine):

- **`libs/oya/node-bridge/`** — a napi-rs crate (`src/lib.rs`) compiled to a
  native `.node` addon for the Node services. It re-exports geodesy
  (`vincenty_distance`, `haversine_distance`, `bearing`), `euler_to_quaternion`,
  `crc32`, and the 2-D ORCA `orca_half_plane`, each delegating straight to the
  engine crates. Its header is explicit about intent: this is "the production
  Rust↔TypeScript seam: the `apps/oya/*` services call these native functions
  instead of the legacy `@oya/core` TypeScript."
- **`libs/oya/wasm-bridge/`** — a wasm-bindgen crate (`src/lib.rs`) compiled to
  `wasm32-unknown-unknown` for the browser operator dashboard. It exposes the
  same geodesy/quaternion/ORCA functions plus the _plotting_ surface the
  dashboard needs: cinematography camera-path samplers (`orbit_camera_path`,
  `crane_camera_path`, `helix_camera_path`, `bezier_camera_path`) and
  `oya-navigation` minimum-snap evaluation, all returning flat `Float64Array`
  buffers with documented `*_STRIDE` column layouts to avoid per-point
  allocation. Absent optional angles are encoded as `NaN`, never a fabricated
  `0.0`.

Because both bridges delegate to the _same_ crates, the napi addon, the wasm
module, and the legacy TS produce bit-for-bit identical values. That equivalence
is enforced, not assumed: `libs/oya/engine/parity/check.mjs` is a **differential
test** that runs the Rust producer (`cargo run --example parity_dump`) and the
TypeScript producer (`@oya/core` via `ts_dump.ts`) over identical inputs and
asserts every named float agrees to relative error ≤ 1e-12 (or absolute ≤ 1e-9
near zero) and every integer (CRC) matches exactly, exiting non-zero to gate CI.
The bridges' own tests pin oracle values (e.g. London→Paris Vincenty ≈
`343923.12 m`).

---

## Layer 3 — Canonical Contracts (`@oshun/contracts/oya`)

`libs/contracts/src/oya/` is the single source of truth for everything that
crosses a wire or process boundary. Its `index.ts` documents the surface and its
purpose: schemas "coherent with the Rust engine/hive types in `libs/oya/engine`
… so payloads validate identically on both sides." Every object schema is
`.strict()`, so an unexpected key is a loud rejection rather than a silently
dropped field. The modules:

- **`primitives.ts`** — `Vec3`, the unit-quaternion `QuaternionSchema` (norm ≈
  1, tolerance 0.01, matching `oya_types::Quaternion::is_unit`),
  `GpsCoordinate`, the branded `DroneId`/`MissionId`/`DockId`, and the
  **`Capability`** enum (`fly`, `roll`, `grasp`, `climb_stairs`, `vacuum`,
  `mop`, `camera`) — the vocabulary the allocator arbitrates over.
- **`telemetry.ts`** — the downlink `Telemetry` snapshot and the uplink
  `ControlCommand` (flight-mode + setpoint vocabulary mirroring `oya-control`).
- **`mission.ts`**, **`dock.ts`**, **`capability.ts`** —
  missions/waypoints/flight plans; dock slot-occupancy and charge handshake
  (mirroring `oya-energy`); and the §15.7 hot-swap payload **capability
  passport** (mass/CoM/power budget + the capabilities a payload grants when
  bound).
- **`fleet.ts`** — `FleetAgent`, `FleetTask`, `FleetState`, `TaskBid`,
  `Allocation`, and the **hard capability gate**
  `bidIsCapabilityValid(agent, bid)` — the contract-layer mirror of
  `FleetAgent::can_service` in `oya-fleet`.
- **`world-model.ts`** — the scene graph and the **fail-loud** discriminated
  `QueryResult` union: `Fresh` (a confident remembered value), `Stale` (an
  honest "not sure anymore, last known at tick N"), or `Unknown` (never
  observed). The store "never fabricates a confident answer for a decayed
  memory; that refusal is the contract."
- **`sensor.ts`** — observations are **compressed descriptors** (embeddings,
  occupancy patches, beamformed spectra) with PTP-disciplined timestamps; there
  is deliberately **no raw-frame field** (bandwidth + privacy).
- **`safety.ts`** — the ISO/TS 15066 `SafetyEnvelope` (per-body-region
  `forceLimitsN`, `ssmMinSeparationM`) and the `EStopState`
  (`nominal`/`soft_stop`/`hard_stop`).

---

## Layer 4 — The TypeScript Platform (`libs/oya/*`)

A set of focused libraries provides the service runtime on top of the contracts:

- **`@oya/common`** — `Result<T, E>`, exact unit conversions, geo helpers,
  branded IDs, domain constants.
- **`@oya/fastify-core`** — the shared service core: `createOyaServer` (typed
  error envelope, 404 handler, `/health`, request-id propagation, JSON body
  limit) and a testable `registerGracefulShutdown`. Every service is built on
  it.
- **`@oya/service-lib`** — production-hardening primitives: a `CircuitBreaker`,
  retry/backoff, a config schema + loader, health aggregation, a Postgres
  `DbConnectionManager` over a mockable pool boundary, and **fail-closed** JWT
  auth middleware.
- **`@oya/database`** — the persistence schema (§3.1): six tables — `missions`,
  `flights`, `telemetry`, `maps`, `fleet_state`, `consumables` — plus a
  `query-executor` and repository layer.
- **`@oya/event-publisher` / `@oya/event-handlers`** — a typed event catalogue
  that validates each payload against its Zod schema before publish, and
  subscribers that reduce events into an injected in-memory store, **gated by
  the latched per-drone e-stop**.
- **`@oya/privacy`** (§9.2) — a deterministic, fail-closed enforcement runtime:
  redact every _unrecognised_ person by default, planner/perception no-record
  geofences via exact point-in-polygon, consent policy, and storage policy.
- **`@oya/security`** (§9.3) — real `node:crypto` only: Ed25519 device identity,
  AES-256-GCM media encryption, HKDF-SHA256 per-home tenancy isolation, a
  fail-closed two-factor door-unlock gate, and cross-modal anti-spoofing.
- **`@oya/maintenance`** (§9.4) — consumable-level accounting (filters, brushes,
  mop pads, charge-cycle budget) and the anti-bricking "dignity" guarantee.
- **`@oya/readiness-gates`** (§10.2/§10.3) — ten **anti-fabrication** release
  gates (coverage-completeness, grasp-honesty, map-freshness, energy-reserve,
  safety-conformance, privacy-enforcement, offline-degradation, mode-economy,
  economic-viability, live-OTA-safety) plus post-update rollback. Each is a pure
  function returning `{ gate, status, reasons, metrics }` that _recomputes its
  invariant from first principles_; `runAllGates` is a conjunction — the release
  is `BLOCKED` if any gate fails.
- **`@oya/sdk`** (§3.1) — a thin, Zod-validated REST client for external
  consumers.

**Legacy / prior generation.** `@oya/core` (the 101-module TS drone library) and
the single-file sibling readiness evaluators (`@oya/flight-control`,
`@oya/mission-planning`, `@oya/safety`, `@oya/swarm-intelligence`,
`@oya/telemetry`) remain in the tree. They are real and tested, but the bridge
headers and contracts describe them as the surface being migrated off of — the
Rust engine is now authoritative for the performance-critical math, with
`@oya/core` retained as the parity oracle.

---

## Layer 5 — The Service Tier (`apps/oya/`)

Fifteen Fastify microservices, each built on `createOyaServer`, listening on the
`401x`/`402x` port band. They split along the coordination/control line the
codebase is careful to maintain:

**§4.1 — control & safety plane.**

- **`svc-flight-gateway`** — the secure-link control plane. A per-drone
  `LinkRegistry` (`gateway.ts`) owns one `ArmingInterlock` FSM and one signed
  MAVLink2 `FrameBuilder` per vehicle. Every outbound command must clear the
  **fail-closed `command-gate`** (`command-gate.ts`): a disarm (`armed: false`)
  is _always_ allowed; an arming/motor command is accepted only when the
  interlock is `Armed`, the e-stop is `nominal`, **and** the drone is inside the
  geofence — with the default verdict being reject.
- **`svc-assistant`** (§4.1) — goal decomposition, tool invocation, and
  free-form planning, every action mediated by a mandatory `SafetyGate`.
- **`svc-director`** — DroneDirector live composition scoring, a
  preference-learning loop, and the Yemaya shot-list → flight bridge.
- **`svc-perception`** — deterministic detection post-processing
  (NMS/thresholding/class-filter/bbox→world projection), a multi-object tracker,
  and map publishing.

**§4.2 — coordination & application plane.**

- **`svc-fleet-orchestrator`** — the router (Open-RMF pattern, `app.ts`/
  `auction.ts`). It ingests pose/battery/capability, runs a **CBBA market
  auction** (the SGA / diminishing-marginal-gain consensus-based bundle
  algorithm, mirroring `oya-fleet::auction`), and reserves shared resources in
  space-time via a `TrafficSchedule`. It "deliberately exposes no endpoint that
  returns a motor command, velocity setpoint, or actuator value." The auction is
  fully deterministic (id-ordered tie-breaks) and validates its output against
  `AllocationSchema` before returning — fail-loud if it ever produced an
  off-contract shape.
- **`svc-mission`** — mission CRUD over a `MissionRepository` (on an injected
  `QueryExecutor`) plus energy-aware and follow-me planning.
- **`svc-energy`** — dock registry / charge broker, fleet SOC/SOH aggregation,
  and return-to-dock decisions. **`svc-dock`** — the dock network, per-slot
  charging FSMs, perch-routine planning, and battery-swap orchestration.
- **`svc-floorcare`** — coverage jobs, a dirt heatmap, a zone scheduler, and the
  omni-dock self-empty/refill cycle (over `oya-floorcare`).
- **`svc-home-map`** — the scene store, spatial query, change tracking, and
  privacy zones (the service face of `oya-scenegraph` + `@oya/privacy`).
- **`svc-hri`** — hive-wide turn-taking floor arbitration, mic-array speaker
  localization, per-resident persona/trust, and per-embodiment affect.
- **`svc-manipulation`** — a grasp-confidence gate, an object-handoff
  coordinator, and per-embodiment VLA (vision-language-action) policy.
- **`svc-ambient`** — a Matter/Thread device registry (capability-validated
  command dispatch) and sensing escalation.
- **`svc-eldercare`** — multimodal fall-fusion with a trigger→confirm→escalate
  FSM, closed-loop medication adherence, engagement, and conversation.
- **`svc-pet`** — weight-based pet identification, per-pet calorie budgeting,
  behaviour, and navigation policy.

Most services keep their state in **in-memory, dependency-free, injectable
collaborators** so the _same_ handler code runs under `fastify.inject()` in
tests and in production with no test-only branch; persistence is defined in
`@oya/database` and reached through injected executors where a service needs it
(e.g. `svc-mission`).

---

## Cross-Cutting Invariants and Failure Modes

A competent engineer working on Oya must respect a handful of invariants that
the architecture enforces in more than one place:

1. **The hard capability gate.** A task carries the single `Capability` it
   requires; an agent may only _bid on or win_ a task whose capability it holds.
   This rule lives identically in the contract (`bidIsCapabilityValid`), the TS
   auction (`canService`), and `oya-fleet`. A `grasp` task can never be assigned
   to a non-grasp robot.
2. **Coordination never actuates.** The orchestrator assigns and reserves; only
   the flight gateway and on-robot control loops move motors, behind the
   fail-closed command gate. New endpoints must preserve this boundary.
3. **Fail-loud over fabrication.** The world-model query union refuses to invent
   a confident answer for a decayed memory; the auction validates its own output
   against the schema; the readiness gates recompute invariants from first
   principles rather than trusting a claimed status. The sensor contract carries
   no raw frames, only descriptors.
4. **Determinism.** Allocation, the gates, and the gateway decisions are pure,
   clock-free functions — identical inputs yield identical outputs regardless of
   ordering, which is what makes `fastify.inject()` assertions exact.
5. **Parity is enforced, not assumed.** Rust ↔ wasm ↔ TS agree to 1e-12, gated
   by `parity/check.mjs`. Any change to engine math must keep the bridges and
   the `@oya/core` oracle in lock-step.
6. **Offline degradation & timing.** The `offline-degradation` gate requires
   every safety-critical loop to survive cloud loss; `oya-comms::timesync`
   (PTP/IEEE-1588) makes observations comparable across the hive's clocks.

---

## Cross-Domain Integration Boundaries and Extension Points

Oya owns flight/actuation authorisation, mission execution, hive coordination,
and robot safety policy; it consumes and exposes typed objects at its edges. The
clearest live boundary is the **Yemaya shot-list → flight bridge** in
`svc-director`, which turns a creative shot list into drone cinematography
trajectories (built on `oya-cinematography`). The `@oshun/contracts/oya` package
is the integration surface other domains import; the typed event catalogue in
`@oya/event-publisher` is how Oya broadcasts telemetry, mission lifecycle,
fleet-allocation changes, and e-stop events for cross-domain reaction.

Extension points follow the same grain: add a robot capability by extending the
`Capability` enum (contract) and the locomotion/manipulation crates; add a new
coordination behaviour as a §4.2 service on `@oya/fastify-core` with injectable
state; add an engine capability as a crate plus a bridge function (and a parity
oracle); add a release invariant as another `@oya/readiness-gates` evaluator
folded into the `runAllGates` conjunction.

---

## Status: Implemented vs Legacy vs Planned

- **Implemented (real code, with tests):** the 21-crate Rust engine, the
  napi/wasm bridges and the parity differential test, the `@oshun/contracts/oya`
  surface, the TypeScript platform libraries (`fastify-core`, `service-lib`,
  `database`, `event-publisher`/`handlers`, `privacy`, `security`,
  `maintenance`, `readiness-gates`, `common`, `sdk`), and all 15 `apps/oya/`
  services.
- **Legacy / prior generation (retained):** `@oya/core` (the 101-module TS drone
  library) and the single-file sibling readiness evaluators. These remain real
  and tested but are described in-code as the surface being migrated off of; the
  Rust engine is now authoritative and `@oya/core` serves as the parity oracle.
- **Honest caveats:** the FFI bridges expose a _typed subset_ of the engine (the
  geodesy/quaternion/ORCA/cinematography/min-snap functions read in
  `node-bridge`/`wasm-bridge`), not the entire crate surface — much engine logic
  is exercised in-crate and via the services rather than re-exported across the
  boundary. Service state is largely in-memory and injectable by design;
  `@oya/database` defines the persistence schema and is wired where a service
  needs durability. This document is grounded in reading the source, not in
  running the build, so it asserts no pass/coverage metrics; the parity test and
  the readiness gates are the mechanisms the repo uses to keep those claims
  honest in CI.
