# Oya — Systems Deep Dive

> The `libs/oya/` area: eighteen Nx projects that make up the platform-side of
> **Oya, the embodied-robotics "hive" domain** — a large legacy TypeScript drone
> core, a 21-crate Rust engine being ported off it, a canonical persistence and
> eventing tier, deterministic safety/privacy/security runtimes, and a set of
> per-pipeline readiness evaluators and release gates. This page is the
> entity-catalog view; the narrative architecture lives in the Oya domain space
> (`DOMAINS/oya/architecture.md`).

## What this area is

Oya is the Oshun platform's domain for **embodied autonomous robots operating as
one coordinated fleet** — the code calls it _the embodied hive_: a heterogeneous
mix of aerial drones, ground robots, floor-care units, and manipulators sharing
one spatial world model, one safety envelope, and one task allocator.
`libs/oya/` holds the TypeScript platform libraries, the Rust engine, and the
persistence / eventing tier that the running services under `apps/oya/` compose.
(The services themselves are a separate area; this page covers only the eighteen
`libs/oya/` projects.)

The area is not uniform — it spans three layers visible in the project tags. A
single very large **`layer:domain` legacy core** (`@oya/core`, ~100
implementation modules) holds the original all-TypeScript drone primitives:
math, coordinate transforms, flight control, GPS/indoor positioning, visual
SLAM, path planning, obstacle avoidance, and swarm coordination. A
**`layer:engine` Rust workspace** (`oya-engine`) is porting the
performance-critical parts of that core to Rust, with a differential parity
harness that holds the two implementations bit-for-bit equal. And a cluster of
**`layer:infra` libraries** provides the modern spine the services actually
build on: `@oya/common`, `@oya/database`, `@oya/event-publisher` /
`@oya/event-handlers`, `@oya/fastify-core`, `@oya/service-lib`, `@oya/sdk`, and
the deterministic compliance runtimes `@oya/privacy`, `@oya/security`,
`@oya/maintenance`, and `@oya/readiness-gates`.

Sitting alongside the legacy core are five **per-pipeline readiness evaluators**
— `@oya/flight-control`, `@oya/telemetry`, `@oya/mission-planning`,
`@oya/safety`, and `@oya/swarm-intelligence`. These are not the live control
loops (those live in `@oya/core` and the engine); they are deterministic
scenario evaluators that take a structured description of a
fleet/mission/telemetry scenario, score coverage ratios against per-gate
thresholds, classify each unit `ready` / `needs-attention` / `blocked`, and emit
a serialized report with prioritized next-actions. They share one idiom
(`runOya<Pipeline>(scenarios) → { scenarios, report }`) so reading one teaches
all five.

## How it fits the wider system

The fifteen Fastify services under `apps/oya/` are the consumers. They build
their HTTP servers with `@oya/fastify-core`, draw config / health /
circuit-breaker / retry / JWT-auth / Postgres-pool primitives from
`@oya/service-lib`, persist through `@oya/database`'s zod-validated
repositories, and communicate over the typed bus from `@oya/event-publisher`
(reduced by `@oya/event-handlers`). The control and coordination planes call
into the performance-critical algorithms in `@oya/core` today and increasingly
into the Rust `oya-engine` across the napi/wasm FFI seam. The deterministic
compliance runtimes (`@oya/privacy`, `@oya/security`, `@oya/maintenance`) are
fail-closed gates the services invoke at the edge, and `@oya/readiness-gates` is
the release-time conjunction that must pass before a build ships. External
integrators use `@oya/sdk`. A hard architectural rule runs through it all:
**coordination assigns work but never energizes an actuator** — only the control
plane and on-robot loops do, behind fail-closed gates.

## Entity reference

### @oya/common

Shared foundation types and utilities for the Oya domain
(`libs/oya/common/src`). A small `layer:infra` library re-exporting five focused
modules from `src/index.ts`: `result.ts` (a `Result<T, E>` discriminated union
with combinators), `units.ts` (exact length/speed/angle/temperature/energy
conversions), `geo.ts` (latitude/longitude clamping, bounding boxes, GPS
validation), `ids.ts` (UUID-v4 validation and branded id types), and
`constants.ts` (Oya physical/system constants). It sits at the bottom of the
dependency graph with only a `typescript` peer — the dependency-free vocabulary
the rest of the area shares.

### @oya/core

The large legacy drone core (`libs/oya/core/src`), tagged `layer:domain` and
marked `private`. Its `src/index.ts` is an ~8,300-line barrel re-exporting
roughly a hundred implementation modules: branded ids and zod schemas
(`types.ts`), WGS84 / ISA-atmosphere constants and lookup tables
(`constants.ts`), coordinate transforms and a deep `math-utils.ts` (Vincenty,
Kalman/EKF, Madgwick, splines, CRC), full 6-DOF multirotor `kinematics.ts`,
cascaded attitude / velocity / position control, mission execution, GPS and
indoor (UWB/VIO) positioning, visual SLAM, the full A*/RRT*/CHOMP/MPC
path-planning family, obstacle avoidance, and swarm coordination /
collision-avoidance / formation-flying / task-allocation suites — each numbered
against the §33 spec. The domain architecture is explicit that this is the
**earlier generation** the services are migrating off of: it is real,
substantial, deterministic TypeScript, but the performance-critical parts are
being re-homed in `oya-engine`. It also carries `docs/`, `deploy/`, and
`scripts/` directories and a `typedoc.json`.

### @oya/database

The Oya persistence layer (`libs/oya/database/src`), a `layer:infra` library.
Its `index.ts` re-exports three modules: `schema.ts` (the SQL schema plus an
ordered `MIGRATIONS` array for missions, telemetry, and fleet state),
`query-executor.ts` (a `QueryExecutor` seam satisfied by a real `pg.Pool` in
production and by an in-memory double in tests), and `repositories.ts` (typed,
zod-validated repositories such as `MissionRepository`). The module docblock
shows the intended wiring — iterate `MIGRATIONS` against a `pg` pool, then
construct a repository over the pool — so the boundary to a real Postgres is
explicit and injectable rather than hard-wired.

### oya-engine

The Rust engine workspace (`libs/oya/engine`), tagged `layer:engine`; the
`project.json` name is `oya-engine` while its `package.json` is `@oya/engine`.
Its `Cargo.toml` declares a 21-crate workspace (`oya-math`, `oya-estimation`,
`oya-control`, `oya-navigation`, `oya-perception`, `oya-swarm`, `oya-mavlink`,
`oya-floorcare`, `oya-fleet`, `oya-mapping`, `oya-manipulation`,
`oya-locomotion`, and more, plus `oya-integration-tests`) housing the
performance-critical core ported from `@oya/core` and intended to bridge to
TypeScript via napi-rs / wasm-pack. The `oya-math` crate (whose `src/lib.rs` is
a 52-line module aggregator re-exporting the submodules `constants.rs`,
`coordinate_transforms.rs`, and `math_utils.rs`) is an f64-precise port of
`@oya/core`'s constants, coordinate transforms, and math utilities, with an
optional nalgebra-backed `simd` feature parity-tested against the scalar path.
The honesty-keeping piece is `parity/check.mjs`: a differential comparator that
runs the Rust `parity_dump` example and the TS `@oya/core` source over identical
inputs and asserts every output matches to a relative error ≤ 1e-12 (integers
like CRC exactly), exiting non-zero so it can gate CI.

### @oya/event-handlers

Cross-domain event handlers for the Oya bus (`libs/oya/event-handlers/src`), a
`layer:infra` library depending on `@oshun/contracts` and
`@oya/event-publisher`. It subscribes to the typed bus and reduces each event
into an injected in-memory `OyaHandlerStore`: `oya.telemetry.updated` updates a
latest-telemetry cache, `oya.mission.started` / `oya.mission.completed`
accumulate mission stats, `oya.safety.estop` latches a per-drone emergency-stop,
and `oya.fleet.allocation.changed` updates a per-drone task index **gated by
that safety latch** so an e-stop wins over a re-tasking. Every handler is a
deterministic reducer (no clock, no randomness, no IO); `registerOyaHandlers`
wires them all to a bus and returns one unsubscribe-all disposer.

### @oya/event-publisher

The typed Oya event bus and publish helpers (`libs/oya/event-publisher/src`), a
`layer:infra` library over the §3.2 Oya contracts. `index.ts` exposes
`createOyaEventBus({ sourceDomain: 'oya' })` — an in-memory, compile-time-typed
bus whose `publish`/`subscribe` are generic over an `OyaEventTypes` registry and
**validate every payload against the zod contracts before delivery
(fail-loud)**, stamping `source`, a caller-supplied `id`, and a caller-supplied
`now` (no clock reads). It ships the event-type registry, a §10.4 topic
registry, per-event payload schemas (telemetry, mission lifecycle, fleet
allocation, fall detect/confirm/clear, anomaly, dock charging, safety e-stop,
emergency raise/escalate/resolve), and a typed publish helper per event plus
`OyaEventValidationError` / `OyaEventDispatchError`.

### @oya/fastify-core

The Fastify service core for Oya (`libs/oya/fastify-core/src`), a `layer:infra`
library. Three modules: `create-server.ts` (`createOyaServer` — a configured
Fastify factory with an error handler, 404 handler, `/health` route, request-id
/ correlation-id propagation, and a JSON body limit), `errors.ts` (the pure
`mapErrorToResponse` / `resolveStatusCode` mapping from thrown errors to a typed
error envelope), and `graceful-shutdown.ts` (`registerGracefulShutdown` — a
testable SIGTERM/SIGINT drain-and-close with injectable signal hooks). It is the
shared HTTP shell every Oya service starts from.

### @oya/flight-control

A per-pipeline **readiness evaluator** for low-level control, stabilization, and
autonomous navigation (`libs/oya/flight-control/src/index.ts`), tagged
`layer:domain`, `pipeline:flight-control`. It is not the control loop itself; it
takes `OyaFlightControlScenario`s (each a set of `OyaFlightControllerNode`s with
attitude/velocity/position loops, GPS/IMU/sensor health, navigation route, and
battery state) and scores four coverage ratios per controller — low-level,
stabilization, navigation, safety — via `ratioFromFlags`, raising typed warning
/ blocking issues when a ratio falls below the scenario's threshold or a loop is
out of tolerance (`loopReady` checks update rate, RMS error, saturation,
failsafe hook). `createOyaFlightControlReport` rolls scenarios into a `ready` /
`needs-attention` / `blocked` status with averaged ratios, de-duplicated
next-actions, and a serialized `exportPayload`.

### @oya/maintenance

The §9.4 consumables & maintenance subsystem and §15.7 anti-bricking dignity
guarantee (`libs/oya/maintenance/src`), a `layer:infra` library. `index.ts`
re-exports four deterministic surfaces: `consumables.ts` (append-only per-unit
accounting for HEPA/pre filters, brushes, mop pad, detergent, water tank, vacuum
bag, and battery charge-cycle budget — record usage, compute remaining %,
project a depletion ETA from a usage rate, classify ok/low/depleted), `wear.ts`
(per- component wear against rated life with remaining-useful-life and a
`needsService` threshold), `service-alerts.ts` (loud prioritized alerts plus a
`designForService` right-to-repair metadata model), and `dignity.ts` (the §15.7
guarantee: complete portable `dataExport`, `assertNoBricking` that fails loud
when a core feature is cloud-gated, `antiManipulativeEngagement` rejecting
dark-pattern engagement plans, and a `selfHostable` owner-control check).

### @oya/mission-planning

A per-pipeline **readiness evaluator** for pre-programmed waypoints, actions,
and triggers (`libs/oya/mission-planning/src/index.ts`), tagged `layer:domain`,
`pipeline:mission-planning`. It models `OyaMissionPlan`s of
`OyaMissionWaypoint`s (position, speed, hold, acceptance radius, heading, gimbal
pitch, required action ids), `OyaMissionAction`s (typed
`takeoff`/`land`/`orbit`/`scan-volume`/ `director-cue`/… with payload-validated,
timecode-locked, rehearsal-verified, fallback flags), and `OyaMissionTrigger`s
(timecode / waypoint-arrival / telemetry-condition / director-cue /
safety-event). Following the same scenario→evaluate→report idiom as the other
readiness libs, it scores upload-gate coverage and surfaces blocking/warning
issues and next-actions rather than commanding any flight.

### @oya/privacy

The §9.2 deterministic privacy-enforcement runtime (`libs/oya/privacy/src`), a
`layer:infra` library. `index.ts` re-exports four fail-closed surfaces:
`redaction.ts` (redact every UNRECOGNIZED person by default via a real
bounding-box masking transform; only an allowlist of recognized ids passes
through), `no-record-zones.ts` (planner no-fly and perception no-record geofence
enforcement via exact point-in-polygon and segment/footprint intersection —
grazing a boundary counts as a violation), `storage-policy.ts` (local-first
classification where cloud needs explicit opt-in and biometrics never leave the
box, plus retention windows and guest-mode suspension), and `consent.ts`
(all-party consent gating with an append-only audit log and a mandatory teleop
operator-blur + owner-consent gate). The module docblock is explicit that
face/person **detection** is an ML seam supplied as inputs; the geometry,
transforms, policy, and gating here are real and value-deterministic.

### @oya/readiness-gates

The §10.2/§10.3 release-gate evaluators (`libs/oya/readiness-gates/src`), a
`layer:infra` library and the release-time conjunction for the domain.
`index.ts` composes ten deterministic, anti-fabrication gates — each returning
the uniform `{ gate, status, reasons, metrics }` shape: coverage-completeness
(over _reachable_ free cells), grasp-honesty (no claimed grasp without sensed
contact), map-freshness, energy-reserve (a reserve to a free dock),
safety-conformance (ISO/TS 15066 SSM+PFL bounds), privacy-enforcement,
offline-degradation (safety loops survive cloud loss), mode-economy (never fly
what a ground route could serve), economic-viability, and live-ota-safety
(§10.3). `runAllGates` runs them over one combined input and returns `READY`
only if **every** gate passes — "a release gate is a conjunction, not a vote." A
companion `evaluatePostUpdateRollback` decides per-unit auto-rollback from
post-update telemetry and is deliberately kept out of the pre-update
conjunction.

### @oya/safety

A per-pipeline **readiness evaluator** for geofencing, emergency procedures, and
regulatory compliance (`libs/oya/safety/src/index.ts`), tagged `layer:domain`,
`pipeline:safety`. It models `OyaSafetyCase`s composed of `OyaGeofenceRule`s
(altitude bounds vs regulatory max, actor buffer, breach action, no-fly-zone
clearance), `OyaEmergencyProcedure`s (auto-land / RTH / immediate-ground /
kill-motors / parachute with response-time bounds, command-path redundancy,
rehearsal, operator override), and `OyaRegulatoryComplianceGate`s (FAA Part 107
/ EASA / CAA / local film permit with certification, authorization, Remote ID,
airspace, insurance, permit, and audit-log flags). Like the other readiness libs
it scores coverage against per-case minimums and emits a
`ready`/`needs-attention`/ `blocked` report — it checks that the safety case is
complete, it does not execute the emergency itself.

### @oya/sdk

The client SDK for external Oya consumers (`libs/oya/sdk/src`), a `layer:infra`
library. `index.ts` exposes `OyaClient`, a thin typed wrapper over the Oya REST
surface with methods `getTelemetry`, `listMissions`, `createMission`,
`getMission`, `getFleetState`, and `requestCharge` (the dock charge handshake).
Responses are validated with the canonical `@oshun/contracts/oya` schemas and
non-2xx responses throw a typed `OyaApiError`; the `fetch` implementation is
injectable so the client is fully testable without a network.

### @oya/security

The deterministic §9.3 security primitives for the Oya home
(`libs/oya/security/src`), a `layer:infra` library that uses **real
`node:crypto` only**. `index.ts` re-exports five modules: `device-identity.ts`
(per-device Ed25519 keypairs and self-describing certificates per RFC 8032,
signed/verified without a central authority on the hot path, with a
tenant-scoped revocation list), `media-encryption.ts` (E2E AES-256-GCM media
encryption), `tenancy.ts` (per-home HKDF-SHA256 tenancy isolation),
`door-unlock-gate.ts` (the §15.5 fail-closed two-factor door-unlock gate), and
`anti-spoofing.ts` (UWB/sensor cross-modal anti-spoofing). The device-identity
docblock is explicit that no `Math.random()` stands in for signatures — the
cryptography is genuine.

### @oya/service-lib

Service primitives shared across Oya services (`libs/oya/service-lib/src`), a
`layer:infra` library. `index.ts` exports a `CircuitBreaker` (with
`CircuitOpenError`), `computeBackoff` / `retryWithBackoff`, a base
`serviceConfigSchema` + `loadConfig` with `ConfigValidationError`,
`aggregateHealth` health rollup, a `DbConnectionManager` over a mockable
`PgPoolLike` boundary (`pg` under the hood, with `isTransientPgError` retry
classification), and fail-closed JWT auth middleware for Fastify (`verifyToken`,
`requireAuth`, `requireRole`, `extractBearerToken`, `AuthError`, built on
`jsonwebtoken`). The pure primitives stay clock- and dependency-free while the
db/auth pieces keep their external boundaries injectable so they remain
unit-testable without a live database or HTTP stack.

### @oya/swarm-intelligence

A per-pipeline **readiness evaluator** for multi-drone fleet coordination
(`libs/oya/swarm-intelligence/src/index.ts`), tagged `layer:domain`,
`pipeline:swarm-intelligence`, and the richest of the five evaluators. Beyond
scenario scoring it actually **builds a command model**
(`buildOyaSwarmCommandModel`) from real sub-APIs: leader election
(`highest_battery` / `closest_to_center` / `round_robin` / `manual`),
formation-slot offset computation for line / V / grid / circle / diamond shapes,
market-style task allocation (nearest / first-available), mission load, and a
step-wise `SwarmSimulationAPI` that integrates drone positions toward waypoints
and counts pairwise collisions. `evaluateOyaSwarmIntelligenceScenario` then
scores fleet / formation / mission / autonomy / safety coverage ratios, raises
typed issues (fleet-size, online-ratio, battery, capability, leader,
command/telemetry link, formation, mission, task-allocation, autonomy, safety,
collision-risk), and `createOyaSwarmIntelligenceReport` rolls them into a status
with next-actions and an `exportPayload`.

### @oya/telemetry

A per-pipeline **readiness evaluator** for real-time battery, GPS, IMU, motor,
and temperature monitoring (`libs/oya/telemetry/src/index.ts`), tagged
`layer:domain`, `pipeline:telemetry`. It models `OyaDroneTelemetryFeed`s with
battery (voltage/current/percent/cell-voltages/imbalance/estimated-flight-time),
GPS (fix type, satellites, HDOP/VDOP, RTK, position validity), IMU
(accel/gyro/mag health, vibration, temperature), per-motor (RPM, ESC temp,
current, fault code), and component temperatures, plus stream-quality fields
(latency, sample rate, link quality, timecode lock, redundancy).
`runOyaTelemetry` scores realtime / battery / GPS / IMU / motor / temperature
coverage ratios per feed against scenario minimums — including a real
`cellImbalance` computation and an `allMotorsHealthy` check — classifies each
feed and scenario, and emits the standard report with prioritized next-actions
and a serialized payload.
