# Galatea Domain — Technical Specifications

> **Galatea** — Humanoid Robotic Mannequin and Fashion Robotics Platform

This document specifies the contracts that actually exist in `libs/galatea/*`.
Every type, schema, enum, state machine, store, and event listed here is
traceable to source. Galatea is a **pure library domain**: it has no `apps/` or
`services/` projects. Items not yet implemented are explicitly marked
`(planned)`.

This is a reference document, not a tutorial. The Features doc explains _what_
each library does and _why_; this document records _exactly what_ is exported:
field names, constraints, enum values, method signatures, and package structure.
A new engineer reading this doc should treat it as the ground truth for
understanding what they can import from any `@galatea/*` package.

---

## Table of Contents

1. [Domain Scope and Project Layout](#1-domain-scope-and-project-layout)
2. [Core Domain Model (`@galatea/core`)](#2-core-domain-model-galateacore)
3. [Error Taxonomy and Recovery (`@galatea/core`)](#3-error-taxonomy-and-recovery-galateacore)
4. [Runtime Configuration (`@galatea/core`)](#4-runtime-configuration-galateacore)
5. [Physical Constants and Safety Thresholds (`@galatea/core`)](#5-physical-constants-and-safety-thresholds-galateacore)
6. [Kinematics (`@galatea/kinematics`)](#6-kinematics-galateakinematics)
7. [Safety (`@galatea/safety`)](#7-safety-galateasafety)
8. [Choreography and Show Authoring (`@galatea/choreography`)](#8-choreography-and-show-authoring-galateachoreography)
9. [Fleet Orchestration (`@galatea/fleet`)](#9-fleet-orchestration-galateafleet)
10. [Event Handlers (`@galatea/event-handlers`)](#10-event-handlers-galateaevent-handlers)
11. [Persistence (`@galatea/database`)](#11-persistence-galateadatabase)
12. [SDKs (`@galatea/sdk`)](#12-sdks-galateasdk)
13. [Firmware and Hardware Abstraction (Rust manifests)](#13-firmware-and-hardware-abstraction-rust-manifests)
14. [Other Library Surfaces](#14-other-library-surfaces)
15. [V2 Vehicle-As-Articulated-Body Modeling Surface](#15-v2-vehicle-as-articulated-body-modeling-surface)
16. [Technology Stack](#16-technology-stack)
17. [Acceptance Criteria](#17-acceptance-criteria)

---

## 1. Domain Scope and Project Layout

Galatea is organised as **20 module directories** under `libs/galatea/`
(established by TODOS Phase 63.1.1.1). Four of those directories — `database`,
`event-handlers`, `inclusivity`, `sdk` — are split into sub-packages, so the
domain currently builds **36 packages** (36 `package.json`) tracked by 37
`project.json` files (the four split directories carry an aggregator
`project.json` in addition to one per sub-package).

The table below maps each module directory to the package names it produces.
Directories without sub-packages each produce a single package named after the
directory.

| Module directory       | Packages                                                                                                       |
| ---------------------- | -------------------------------------------------------------------------------------------------------------- |
| `core`                 | `@galatea/core`                                                                                                |
| `firmware`             | `@galatea/firmware`                                                                                            |
| `hardware-abstraction` | `@galatea/hardware-abstraction`                                                                                |
| `kinematics`           | `@galatea/kinematics`                                                                                          |
| `locomotion`           | `@galatea/locomotion`                                                                                          |
| `whole-body-control`   | `@galatea/whole-body-control`                                                                                  |
| `pose-engine`          | `@galatea/pose-engine`                                                                                         |
| `choreography`         | `@galatea/choreography`                                                                                        |
| `perception`           | `@galatea/perception`                                                                                          |
| `ai`                   | `@galatea/ai`                                                                                                  |
| `garment-management`   | `@galatea/garment-management`                                                                                  |
| `fleet`                | `@galatea/fleet`                                                                                               |
| `analytics`            | `@galatea/analytics`                                                                                           |
| `simulation`           | `@galatea/simulation`                                                                                          |
| `safety`               | `@galatea/safety`                                                                                              |
| `communication`        | `@galatea/communication`                                                                                       |
| `database`             | `@galatea/database/{event-store,garment-store,pose-store,show-store,telemetry-store}`                          |
| `event-handlers`       | `@galatea/event-handlers/{customer-events,garment-events,robot-events,safety-events,show-events}`              |
| `inclusivity`          | `@galatea/inclusivity/{accessibility,body-profiles,cultural-config,multilingual}`                              |
| `sdk`                  | `@galatea/sdk`, `@galatea/sdk/show-sdk`, `@galatea/sdk/analytics-sdk`, plus the `client-python` Python package |

Every package exports `GALATEA_LIBRARY_ID` and `getGalateaLibraryId()` from its
`src/index.ts`. All packages are `version: 0.1.0`, `type: module`, with
`publishConfig.access: restricted`.

---

## 2. Core Domain Model (`@galatea/core`)

`@galatea/core` is the dependency-free foundation for the entire domain.
`src/index.ts` re-exports `types/`, `constants/`, `utils/`, `errors/`,
`config/`. Every other `@galatea/*` package imports from this one. The sections
below document each major module in `src/`.

### 2.1 Robot State Types (`src/types/robot-state.ts`)

These types represent the complete observable state of a robot at a single point
in time. They are used throughout the domain as the authoritative representation
of what a robot is doing, where its joints are, and what its sensors are
reporting.

The robot has at minimum **52 degrees of freedom**:
`export const MIN_ROBOT_DOF = 52`. All joint vectors are validated against this
floor.

#### `JointSegment` (Zod enum `JointSegmentSchema`)

`JointSegment` groups the robot's joints into anatomical regions. It is used to
target commands, apply region-specific safety limits, and annotate sensor data.

`head_neck` · `torso_spine` · `left_arm` · `right_arm` · `left_hand` ·
`right_hand` · `left_leg` · `right_leg` · `morphing`.

#### `JointState` / `JointStateSchema`

`JointState` carries the full runtime state of a single joint, including its
position, velocity, applied torque, and the raw electrical and thermal readings
from the actuator. The field constraints reflect physical hardware limits.

| Field         | Type           | Constraints                  |
| ------------- | -------------- | ---------------------------- |
| `jointId`     | `string`       | non-empty (trimmed)          |
| `segment`     | `JointSegment` | enum                         |
| `position`    | `number`       | finite                       |
| `velocity`    | `number`       | finite                       |
| `torque`      | `number`       | finite                       |
| `temperature` | `number`       | finite, −40 … 180            |
| `current`     | `number`       | finite, −250 … 250 (Amperes) |
| `encoderRaw`  | `number`       | non-negative integer         |

#### `Vector3` / `Quaternion`

These are the fundamental geometric primitives used throughout the domain for
positions, velocities, forces, and orientations. `QuaternionSchema` additionally
`superRefine`s that the quaternion norm is `> 0.0001` to reject degenerate
(zero-length) quaternions that would cause division-by-zero in rotation math.

`Vector3` = `{ x, y, z }`, all finite. `Quaternion` = `{ x, y, z, w }`, all
finite.

#### Sensor types

The following types model the outputs of the robot's sensor subsystems. Each
type corresponds directly to a hardware sensor category.

- `ImuState` — `orientation: Quaternion`, `angularVelocity: Vector3`,
  `linearAcceleration: Vector3`.
- `ForceTorqueState` — `sensorId`, `frame`, `force: Vector3`, `torque: Vector3`.
- `TactileTaxelState` — `taxelId`, `pressureKPa` (non-negative), `shearXKPa`,
  `shearYKPa`, `temperature` (−20 … 120).
- `TactileSensorState` — `panelId`, `contactDetected`, `taxels[]` (≥ 1).
- `PressureCellState` — `cellId`, `pressureKPa`, `healthy`.
- `PressureArrayState` — `arrayId`, `location: PressureArrayLocation`, `cells[]`
  (≥ 1), `centerOfPressureMm: { x, y }`.
- `ProximityState` — `sensorId`, `distanceMm` (non-negative), `confidence` (0 …
  1), `objectDetected`.
- `SensorState` — aggregates `imu`, `forceTorque[]`, `tactile[]`, `pressure[]`,
  `proximity[]`; each array must have ≥ 1 element.

`PressureArrayLocation` (Zod enum) identifies where each foot/hand pressure
array is mounted: `left_foot` · `right_foot` · `left_hand` · `right_hand` ·
`torso`.

#### `BodyMorphState` / `BodyMorphStateSchema`

`BodyMorphState` tracks the robot's current body dimension configuration when
the body-morphing subsystem is active. All measurements are in centimeters.

`bustCm` (50–150), `waistCm` (40–150), `hipsCm` (60–160), `shouldersCm` (25–80),
`heightCm` (130–220), `morphingActive: boolean`, `lastMorphAt` (ISO-8601 with
offset).

#### `GarmentState` / `GarmentFitStatus`

`GarmentFitStatus` describes the current state of garment fitting on the robot.
`GarmentState` associates an outfit identifier with its RFID tags and fit
status; `superRefine` rejects duplicate RFID tags (a garment cannot have the
same tag twice).

`GarmentFitStatus` enum: `not_fitted` · `fitting` · `fitted` ·
`adjustment_required` · `invalid_fit`. `GarmentState` =
`{ outfitId, rfidTags[] (≥ 1), fitStatus }`.

#### `BatteryState`

`BatteryState` represents the complete electrical state of the robot's power
system, including charge level, voltage, current draw, temperature, health
degradation, and charge cycle count.

`stateOfChargePercent` (0–100), `voltage` (≥ 0), `current` (finite),
`temperature` (−30 … 100), `healthPercent` (0–100), `cycleCount` (non-negative
integer).

#### `RobotOperationMode` (Zod enum)

`RobotOperationMode` is the top-level mode of the robot's control software.
Transitions between modes are gated by the safety and fleet systems.

`booting` · `idle` · `teleop` · `autonomous` · `show_execution` · `safe_stop` ·
`fault`.

#### `RobotState` / `RobotStateSchema`

`RobotState` is the complete snapshot of a robot at a moment in time. It
aggregates all of the types above. The `superRefine` pass enforces that
`jointStates` length matches the joint-vector length and that all `jointId`s are
unique, preventing partial or contradictory state objects.

| Field             | Type                 | Constraints                        |
| ----------------- | -------------------- | ---------------------------------- |
| `robotId`         | `string`             | non-empty                          |
| `sequence`        | `number`             | non-negative integer               |
| `timestamp`       | `string`             | ISO-8601 with offset               |
| `operationMode`   | `RobotOperationMode` | enum                               |
| `jointStates`     | `JointState[]`       | ≥ `MIN_ROBOT_DOF` entries          |
| `jointPositions`  | `number[]`           | ≥ `MIN_ROBOT_DOF`, all finite      |
| `jointVelocities` | `number[]`           | length must equal `jointPositions` |
| `jointTorques`    | `number[]`           | length must equal `jointPositions` |
| `sensorState`     | `SensorState`        | —                                  |
| `bodyMorphState`  | `BodyMorphState`     | —                                  |
| `garmentState`    | `GarmentState`       | —                                  |
| `batteryState`    | `BatteryState`       | —                                  |

Helpers: `parseRobotState(input)` and the type guard `isRobotState(input)`.

### 2.2 Pose and Motion Types (`src/types/pose-motion.ts`)

These types describe how the robot moves: individual poses, trajectories through
joint space, motion primitives, and the abstract syntax tree used for
choreography scripts.

- `PoseSegmentName` (Zod enum) — same nine values as `JointSegment`.
- `PoseSegmentRange` — `{ segment, startIndex, endIndex }`;
  `endIndex >= startIndex`.
- `Pose` — `poseId`, `label`, `capturedAt` (ISO-8601), `jointAngles[]` (≥
  `MIN_ROBOT_DOF`), `namedSegments: PoseSegmentRange[]` (≥ 1). `superRefine`
  rejects duplicate segments, out-of-range `endIndex`, and overlapping ranges.
- `PoseCategory` (Zod enum) — classifies poses for the pose library and garment
  compatibility matching: `runway` · `editorial` · `commercial` · `lifestyle` ·
  `dramatic` · `neutral` · `transition` · `gesture`.
- `GarmentCompatibility` — `{ garmentClass, compatibilityScore (0–1) }`.
- `PoseMetadata` — `poseId`, `category`, `style`, `garmentCompatibility[]` (≥
  1), `stabilityScore` (0–1), `tags[]`.
- `TrajectoryPoint` — `atMs`, `pose`, `jointVelocityProfile[]`,
  `jointAccelerationProfile[]` (both ≥ `MIN_ROBOT_DOF`, lengths must match
  `pose.jointAngles`).
- `VelocityProfile` (Zod enum) — describes how joint velocity varies along a
  trajectory: `constant` · `trapezoidal` · `minimum_jerk` · `s_curve` ·
  `custom`.
- `AccelerationProfile` (Zod enum) — describes how joint acceleration varies
  along a trajectory: `constant` · `parabolic` · `minimum_jerk` · `s_curve` ·
  `custom`.
- `Trajectory` — `trajectoryId`, `name`, `points[]` (≥ 2), `velocityProfile`,
  `accelerationProfile`. `superRefine` enforces strictly increasing `atMs`.
- `GaitParameters` — `strideLengthMeters` (0.05–2.5), `frequencyHz` (0.2–4.5),
  `hipSwayMeters` (0–0.4), `armSwingDegrees` (0–90), `crossoverRatio` (0–1).
- `BlendCurve` (Zod enum) — the interpolation curve used when blending between
  poses: `linear` · `ease_in` · `ease_out` · `ease_in_out` · `cubic` · `custom`.
- `MotionPrimitiveBlending` — `blendInMs`, `blendOutMs`, `blendCurve`,
  `compatiblePrimitiveIds[]`.
- `MotionPrimitive` — `primitiveId`, `name`, `trajectory`, `gaitParameters`,
  `blending`.

#### Choreography AST

The choreography model is an **abstract syntax tree of timed nodes**, not a flat
cue list. This structure lets the show engine reason about timing relationships
and validate them before execution. The AST is the runtime representation
produced by parsing a `ChoreographyScript`.

`FormationPattern` (Zod enum) — the geometric arrangement of robots on stage:
`line` · `v` · `arc` · `grid` · `staggered` · `runway_cross`. `CueDomain` (Zod
enum) — which production system a cue targets: `lighting` · `audio` · `video` ·
`effects` · `narration` · `automation`.

The node union `ChoreographyAstNode` is discriminated by `nodeType`. Each node
type carries a `TimingWindow` and node-specific fields:

| `nodeType`         | Extra fields                                |
| ------------------ | ------------------------------------------- |
| `motion_call`      | `timing`, `primitiveId`, `robotIds[]` (≥ 1) |
| `formation_change` | `timing`, `formation: FormationSpec`        |
| `cue_trigger`      | `timing`, `cueId`, `cueDomain`              |
| `wait`             | `timing`                                    |

`TimingWindow` = `{ startMs, durationMs }`. `ChoreographyScript` =
`{ scriptId, showId, version, totalDurationMs, ast[] (≥ 1) }`. `superRefine`
enforces non-decreasing `startMs`, that node timing never exceeds
`totalDurationMs`, and unique `cueId`s. Parse helpers: `parsePose`,
`parsePoseMetadata`, `parseTrajectory`, `parseMotionPrimitive`,
`parseChoreographyScript`.

### 2.3 Math Utilities (`src/utils/`)

`@galatea/core` also exports math utility modules used throughout the domain.
These are low-level building blocks for the kinematics and control packages.

`quaternion.ts`, `se3.ts` (SE(3) rigid-body transforms; exports
`toRotationMatrix` used by IK), `trajectory-interpolation.ts`,
`procedural-motion.ts`.

---

## 3. Error Taxonomy and Recovery (`@galatea/core`)

Rather than using generic `Error` objects, Galatea defines a typed error
hierarchy so that error-handling code can make decisions based on which
subsystem failed and how severe the failure is. This section documents that
hierarchy and the recovery infrastructure built on top of it.

### 3.1 `error-taxonomy.ts`

The following enums define the classification axes for Galatea errors. Every
error carries a severity and a subsystem identifier, and the escalation routes
are derived deterministically from those two values.

`GalateaErrorSeverity`: `info` · `warning` · `critical` · `safety-critical`.
`GalateaSubsystem`: `firmware` · `kinematics` · `locomotion` · `perception` ·
`ai` · `safety`. `EscalationRoute`: `observability-log` · `operator-console` ·
`fleet-supervisor` · `safety-controller` · `emergency-stop-chain`.

`resolveEscalationRoutes(severity, subsystem)` derives routes deterministically
(e.g. `safety-critical` always appends `emergency-stop-chain`). The base
`GalateaError` class carries `code`, `severity`, `subsystem`, optional `context`
(`robotId`, `correlationId`, `metadata`), `occurredAt` (normalised ISO
timestamp), and computed `escalationRoutes`; `toJSON()` serialises all of these.
Type guard: `isGalateaError(value)`.

Each subsystem has its own error subclass with a narrowed code union. The table
below lists the allowed error codes per subsystem class.

| Class             | Code union                                                              |
| ----------------- | ----------------------------------------------------------------------- |
| `FirmwareError`   | `motor_fault` · `sensor_fault` · `communication_fault` · `safety_fault` |
| `KinematicsError` | `ik_failure` · `singularity` · `joint_limit_violation`                  |
| `LocomotionError` | `balance_loss` · `footstep_failure` · `gait_fault`                      |
| `PerceptionError` | `slam_failure` · `detection_failure` · `camera_fault`                   |
| `AIError`         | `policy_confidence_low` · `ood_detection` · `inference_timeout`         |
| `SafetyError`     | `force_limit` · `e_stop` · `stability_margin`                           |

### 3.2 `error-recovery.ts`

`error-recovery.ts` provides the infrastructure for automated error recovery,
retry policies, and audit logging. The `ErrorRecoveryManager` orchestrates the
full lifecycle: classify the error, attempt recovery with backoff, degrade
gracefully if recovery fails, and write an immutable audit record of every
attempt.

- `RecoverySafeState` — the safe state reached after failed recovery:
  `operational` · `degraded` · `safe_stop` · `emergency_stop`.
- `RetryBackoffPolicy`, `RecoveryAuditEventInput`, `RecoveryAuditEvent`.
- `ImmutableRecoveryEventStore` interface +
  `InMemoryImmutableRecoveryEventStore` implementation (append-only audit log).
- `RecoveryExecutionOptions<T>`, `RecoveryExecutionResult<T>`,
  `OperatorNotifier`.
- `isTransientError(error)`, `resolveDegradationPath(error)`.
- `ErrorRecoveryManager` — orchestrates retry/backoff, degradation, and audit.
- Factory helpers: `createTransientFirmwareError`, `createCriticalSensorError`,
  `createSafetyCriticalError`, `createTransientAIError`.

---

## 4. Runtime Configuration (`@galatea/core`)

`src/config/runtime-config.ts` defines `GalateaRuntimeConfigSchema` (a strict
Zod object) and its inferred type `GalateaRuntimeConfig`. All configuration for
the Galatea runtime — database URLs, messaging brokers, compute device,
per-sensor enable flags, safety overrides, and feature flags — flows through
this single validated schema.

### 4.1 Config shape

The config is divided into sections covering infrastructure, hardware
capabilities, safety parameters, and feature flags. The table below lists each
section and its fields.

| Section           | Fields                                                                                                                           |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `database`        | `primaryUrl`, `telemetryUrl`, `eventStoreUrl` (all URLs)                                                                         |
| `redis`           | `url`                                                                                                                            |
| `nats`            | `servers[]` (≥ 1 URL), `streamName`                                                                                              |
| `mqtt`            | `brokerUrl`, `clientId`, optional `username`/`password`, `qos` (0–2)                                                             |
| `compute`         | `device: ComputeDevice` (`jetson-thor` \| `jetson-orin`)                                                                         |
| `sensors`         | booleans: `imu`, `forceTorque`, `tactile`, `pressure`, `proximity`, `camera`, `lidar`                                            |
| `safetyOverrides` | `maxTcpVelocityMmPerSec`, `forceLimitScale`, `pressureLimitScale`, `supportPolygonMarginScale`, `emergencyStopDecelerationScale` |
| `logging`         | `level`: `fatal`\|`error`\|`warn`\|`info`\|`debug`\|`trace`                                                                      |
| `featureFlags`    | booleans: `vla`, `lbm`, `morphing`, `showEngine`, `teleoperation`, `fleetAnalytics`                                              |

`safetyOverrides` are clamped to `CERTIFIED_SAFETY_OVERRIDE_BOUNDS` to prevent
operators from inadvertently configuring unsafe parameters:
`maxTcpVelocityMmPerSec` 50–250, `forceLimitScale` 0.5–1.0, `pressureLimitScale`
0.5–1.0, `supportPolygonMarginScale` 1.0–2.0, `emergencyStopDecelerationScale`
1.0–1.5.

### 4.2 Loading

The config loader supports a layered merge strategy so that defaults can be
overridden by file, environment, and in-process overrides without any layer
silently winning over a more specific one.

`DEFAULT_GALATEA_RUNTIME_CONFIG` provides the baseline.
`loadGalateaRuntimeConfig(options)` deep-merges, in order: defaults → JSON file
(`GALATEA_CONFIG_FILE` or `configFilePath`) → environment overlay → explicit
`runtimeOverrides`; the merged result is validated by the schema.
`GalateaRuntimeConfigManager` wraps the loader with `getConfig()`,
`getSubsystemConfig(key)`, `reload()`, and `applyRuntimeOverride()`.

### 4.3 Environment variables consumed

Every field in the config schema has a corresponding environment variable. The
following variables are read during config loading.

`GALATEA_CONFIG_FILE`, `GALATEA_DATABASE_PRIMARY_URL`,
`GALATEA_DATABASE_TELEMETRY_URL`, `GALATEA_DATABASE_EVENT_STORE_URL`,
`GALATEA_REDIS_URL`, `GALATEA_NATS_SERVERS` (CSV), `GALATEA_NATS_STREAM_NAME`,
`GALATEA_MQTT_BROKER_URL`, `GALATEA_MQTT_CLIENT_ID`, `GALATEA_MQTT_USERNAME`,
`GALATEA_MQTT_PASSWORD`, `GALATEA_MQTT_QOS`, `GALATEA_COMPUTE_DEVICE`,
`GALATEA_SENSOR_{IMU,FORCE_TORQUE,TACTILE,PRESSURE,PROXIMITY,CAMERA,LIDAR}_ENABLED`,
`GALATEA_SAFETY_MAX_TCP_VELOCITY_MM_PER_SEC`,
`GALATEA_SAFETY_FORCE_LIMIT_SCALE`, `GALATEA_SAFETY_PRESSURE_LIMIT_SCALE`,
`GALATEA_SAFETY_SUPPORT_POLYGON_MARGIN_SCALE`,
`GALATEA_SAFETY_ESTOP_DECEL_SCALE`, `GALATEA_LOG_LEVEL`,
`GALATEA_FEATURE_{VLA,LBM,MORPHING,SHOW_ENGINE,TELEOPERATION,FLEET_ANALYTICS}`.

---

## 5. Physical Constants and Safety Thresholds (`@galatea/core`)

`@galatea/core` exports a complete set of physical constants describing the
robot's body geometry, joint kinematic chain, actuator specs, and
safety-critical force limits. These constants are the authoritative source of
truth for physically meaningful values used across the domain — the kinematics
solver, safety monitor, and locomotion controller all read from here.

### 5.1 `physical-constants.ts`

This file defines the robot's kinematic skeleton and the physical properties of
every link and actuator.

- `GALATEA_JOINT_KINEMATIC_CHAIN` — the full ordered joint chain built from
  per-segment templates. For example, the `head_neck` segment defines joints
  `neck_yaw`, `neck_pitch`, `neck_roll`, and `jaw_pitch`; the `left_arm` segment
  defines `left_shoulder_pitch/roll/yaw`, `left_elbow_pitch`,
  `left_forearm_roll`, and `left_wrist_pitch/yaw`. Each entry is a
  `JointKinematicDescriptor` with `index`, `jointId`, `segment`, `parentLinkId`,
  `childLinkId`, `axis`.
- `GALATEA_DOF` — the chain length (the actual DOF count).
- `GALATEA_JOINT_LIMITS` — `JointLimitSpec[]` (`lowerAngleRad`, `upperAngleRad`,
  `maxVelocityRadPerSec`, …) derived from the chain.
- `GALATEA_DH_PARAMETERS` — `DenavitHartenbergParameter[]`.
- `GALATEA_LINK_INERTIA_SPECS` — `LinkInertiaSpec[]`.
- `GALATEA_BODY_SEGMENT_LENGTHS` — `BodySegmentLengthSpec[]`.
- `GALATEA_ACTUATOR_SPECS` — `ActuatorSpecification[]`.
- `GALATEA_SENSOR_SPECS` — `SensorSpecification[]`; `SensorType` = `imu` ·
  `force_torque` · `tactile` · `pressure` · `proximity`.
- Lookups: `getJointLimitSpec`, `getDenavitHartenbergParameter`,
  `getActuatorSpecification`.

### 5.2 `safety-thresholds.ts`

This file encodes the ISO 13482-derived force and pressure limits for each body
region, the emergency stop deceleration profiles, and the standstill zone radii.
Every safety decision in the force-limiting and emergency-systems modules
derives its thresholds from these constants.

`BodyRegion` (12 regions): `skull` · `forehead` · `neck` · `shoulder` ·
`upper_arm` · `forearm` · `hand` · `chest` · `abdomen` · `thigh` · `calf` ·
`lower_leg`.

- `MAX_TCP_VELOCITY_NEAR_HUMANS_MM_PER_SEC = 250`.
- `BODY_REGION_FORCE_LIMITS` — per-region `transientNewton` /
  `quasiStaticNewton` limits (e.g. `skull` 130 / 65, `neck` 110 / 55, `shoulder`
  180 / 90).
- `BODY_REGION_PRESSURE_LIMITS_KPA` — per-region `maxPressureKPa`.
- `REDUCED_SUPPORT_POLYGON_MARGIN_METERS` — `SupportPolygonMargin`
  (`front/rear/left/right` metres).
- `EMERGENCY_STOP_DECELERATION_PROFILES` — `EmergencyStopDecelerationProfile[]`,
  each tagged `category_0` / `category_1` / `category_2` with linear/angular
  deceleration, jerk, and nominal stop time.
- `SAFE_STANDSTILL_ZONE_RADII_METERS`.
- Helpers: `getForceLimitForBodyRegion`, `getPressureLimitForBodyRegion`,
  `getEmergencyStopProfile`, `isTcpVelocitySafeNearHumans`,
  `isContactForceWithinLimit`, `isContactPressureWithinLimit`,
  `classifyStandstillZone` returning `StandstillZoneClassification` (`touch` ·
  `approach` · `outside`).

### 5.3 `morphing-constants.ts`

`morphing-constants.ts` defines the physical operating limits for the
body-morphing subsystem, which controls pneumatic bladders to adjust body
segment dimensions.

`MorphProfileCm`, `MorphMeasurementRangeCm`, `MorphSpeedLimits`,
`MorphRepeatabilityTolerance`, `BladderPneumaticPressureLimits`. Constants:
`MORPH_MEASUREMENT_RANGES_CM`, `MORPH_SPEED_LIMITS_CM_PER_SEC`,
`MORPH_REPEATABILITY_TOLERANCE`, `BLADDER_PNEUMATIC_PRESSURE_LIMITS_KPA`.
Helpers: `isMorphProfileWithinRange`, `clampMorphProfileToRange`,
`isBladderPressureWithinOperatingRange`, `isBladderPressureWithinAbsoluteLimit`.

---

## 6. Kinematics (`@galatea/kinematics`)

`@galatea/kinematics` contains six computation modules. Each module pairs a
TypeScript implementation with a `*-rust-manifest.ts` describing the planned
Rust crate that will replace the TypeScript for production real-time use. The
TypeScript implementations are fully functional and used in simulation and
development; the Rust crates will be used on the embedded control targets.

The six modules are: `forward-kinematics`, `inverse-kinematics`, `dynamics`,
`jacobian-computation`, `collision-geometry`, `urdf-parser`.

### 6.1 Forward kinematics (`forward-kinematics.ts`)

`JointAnglesRad = Readonly<Partial<Record<string, number>>>`. Types:
`FootContactGeometry`, `FootContactState`, `ForwardKinematicsOptions`,
`FramePose`, `CenterOfMassEstimate`, `SupportPolygon`,
`ForwardKinematicsResult`. `computeFullBodyForwardKinematics(jointMap)` returns
link transforms (4×4 matrices keyed by link ID), a center-of-mass estimate, and
a support polygon. `getLinkTransform(...)` resolves a single link.

### 6.2 Inverse kinematics (`inverse-kinematics.ts`)

The IK solver is the most complex module in the domain. It resolves multiple
competing task objectives (end-effector position, balance, gaze direction,
preferred posture) simultaneously using a priority hierarchy and null-space
projection. The algorithm is described in the Features doc; this section
documents the exact type contracts.

`IkTaskType`: `end_effector` · `center_of_mass` · `gaze` · `posture`. The task
union `InverseKinematicsTask` is discriminated by `type`. The table below shows
the distinguishing fields for each variant; all tasks also share `id`, `type`,
`priority`, optional `weight`, and `tolerance`.

| Variant              | Distinguishing fields                                                                       |
| -------------------- | ------------------------------------------------------------------------------------------- |
| `EndEffectorIkTask`  | `linkId`, optional `targetPositionMeters` / `targetOrientation`, optional `workspaceBounds` |
| `CenterOfMassIkTask` | `targetPositionMeters`                                                                      |
| `GazeIkTask`         | `targetDirection`, optional `linkId`                                                        |
| `PostureIkTask`      | `targetJointAnglesRad` (partial joint map)                                                  |

`InverseKinematicsRequest` fields: `currentJointAnglesRad`, `tasks[]`,
`dtSeconds`, `maxIterations`, `damping`, `convergenceTolerance`,
`numericalJacobianStepRad`, `maxJointVelocityScale`, `jointLimitMarginRad`,
`workspaceBounds`, `selfCollisionAvoidance`
(`{ enabled, minimumHandDistanceMeters }`). `WorkspaceBounds` is an axis-aligned
box (`xMin/xMax/yMin/yMax/zMin/zMax` metres).

`solveWholeBodyInverseKinematics(request)` returns `InverseKinematicsResult`:
`backend: 'hierarchical-qp-osqp-compatible'`, `iterations`, `converged`,
`jointAnglesRad`, `jointVelocitiesRadPerSec`, `taskReports: IkTaskReport[]`
(per-task `errorNorm`, `tolerance`, `satisfied`, `degraded`, optional `note`),
`degradedTaskIds`. The algorithm clamps solver parameters, solves
damped-least-squares per priority level, projects lower-priority tasks into the
null space of higher-priority ones, applies joint-limit / velocity constraints,
and optionally enforces hand-to-hand self-collision avoidance.

### 6.3 Other kinematics modules

`dynamics.ts`, `jacobian-computation.ts`, `collision-geometry.ts`, and
`urdf-parser.ts` provide recursive-Newton-Euler dynamics, geometric/analytical
Jacobians, swept-volume / self-collision checks, and URDF/XACRO parsing
respectively. Each module pairs its TypeScript implementation with a
corresponding `*-rust-manifest.ts`.

---

## 7. Safety (`@galatea/safety`)

`@galatea/safety` is organized into eight modules. Safety is the most
architecturally significant package in the domain: its outputs gate every motion
command and its events write to the append-only audit log. The three primary
modules — ISO 13482 compliance, force limiting, and emergency systems — are
documented in detail here.

Eight modules: `access-control`, `audit-logger`, `emergency-systems`,
`force-limiting`, `functional-safety`, `iso-13482`, `regulatory-toolkit`,
`risk-assessment`.

### 7.1 ISO 13482 compliance engine (`iso-13482/iso-13482.ts`)

`Iso13482ComplianceEngine` is a stateful HAZOP + checklist register. It
maintains a database of operating states, hazard entries (with guidewords, risk
scores, and status), and checklist items against specific ISO clause numbers. At
any point, `getComplianceSummary` and `generateComplianceAuditDocument` produce
reports that can be used for certification.

`OperatingStateId` identifies the robot's operational contexts, which are the
subjects of the HAZOP analysis. Eight states are seeded by default: `idle` ·
`walking` · `customer_interaction` · `garment_change` · `charging` ·
`maintenance` · `protective_stop` · `emergency_stop`.

`HazopGuideWord` encodes the structured HAZOP deviation vocabulary: `NO_OR_NOT`
· `MORE` · `LESS` · `AS_WELL_AS` · `PART_OF` · `REVERSE` · `OTHER_THAN`.
`HazopEntryStatus` tracks the resolution state of each hazard: `open` ·
`mitigated` · `accepted` · `closed`.

`Iso12100RiskFactors` = `{ severity, probability, exposure }`; each factor is
clamped to integer 1–5. `assessIso12100Risk` computes `score = S × P × E` and
maps the score to an `Iso12100RiskLevel`: `score ≥ 80 → intolerable`,
`≥ 45 → high`, `≥ 20 → medium`, else `low`; `actionRequired` is true for
`high`/`intolerable`.

`ComplianceChecklistStatus`: `not_started` · `in_progress` · `compliant` ·
`non_compliant` · `not_applicable`. Five `DEFAULT_CHECKLIST_ITEMS` are seeded
against clauses ISO 13482:2014 §5.4, §5.5, §5.6, §6 and ISO 12100:2010.

Engine methods: `listOperatingStates`, `registerOperatingState`,
`createHazopEntry`, `updateHazopEntryStatus`, `listHazopEntries`,
`upsertChecklistItem`, `listChecklistItems`, `evaluateOperatingStateCoverage`,
`getComplianceSummary` (returns `Iso13482ComplianceSummary` with hazard totals,
checklist totals, and operating-state coverage),
`generateComplianceAuditDocument` (returns a `ComplianceAuditDocument` including
a Markdown audit package). Factory: `createIso13482ComplianceEngine`.

### 7.2 Force limiting (`force-limiting/force-limiting.ts`)

`ForceLimitingEngine` evaluates incoming contact samples against the per-body-
region force and pressure limits from `safety-thresholds.ts` and emits an
action: continue normally, reduce speed, or trigger a protective stop.

`ContactEvaluationMode`: `transient` · `quasi_static`. `ForceLimitingAction`:
`normal` · `reduce_speed` · `protective_stop`. Types: `TactileContactSample`,
`ForceTorqueContactSample`, `EvaluateForceLimitingRequest`,
`BodyRegionForceAssessment`, `ForceLimitingEvaluationResult`,
`ForceLimitingValidationScenario`, `ForceLimitingValidationSuiteResult`.
Factory: `createForceLimitingEngine`.

### 7.3 Emergency systems (`emergency-systems/emergency-systems.ts`)

`EmergencySystemsEngine` is the stateful manager for emergency stop and
protective stop events. It maintains an event log of every trigger and recovery,
which provides the audit trail required for ISO 13482 compliance.

`EmergencyOperatingMode`, `EmergencyStopCategory` (`category_0` · `category_1`),
`EmergencyTriggerSource`, `EmergencyRecoveryAction`, `EmergencyEventType`. State
and request/result types cover E-stop activation and recovery, protective-stop
activation and clearance, and proximity-safety assessment
(`ProximitySafetyInput` / `ProximitySafetyAssessment`). `EmergencySystemsEngine`
maintains an `EmergencyEventLogEntry` history and exposes an
`EmergencySystemsSnapshot`. Factory: `createEmergencySystemsEngine`.

### 7.4 Other safety modules

The remaining four modules provide supporting safety infrastructure.
`access-control` governs operator authorisation. `audit-logger` maintains the
safety audit trail. `functional-safety` implements watchdog and heartbeat
monitoring. `regulatory-toolkit` generates CE/UL documentation.
`risk-assessment` implements ISO 12100 hazard identification.

---

## 8. Choreography and Show Authoring (`@galatea/choreography`)

`@galatea/choreography` provides everything needed to author, validate, and
execute multi-robot fashion shows. It is organized into nine modules. The core
module is `show-designer`, which maintains the `ShowDocument` — the central
authored artefact that captures all show content.

Nine modules: `show-designer`, `show-dsl`, `formation-engine`, `music-sync`,
`lighting-bridge`, `stage-mapper`, `timing-engine`, `rehearsal-engine`,
`show-scheduler`.

### 8.1 Show document model (`show-designer/show-designer.ts`)

The `ShowDocument` is the central authored artefact. It holds all the
information needed to execute a show: which robots participate, their track
events, formations, music sync points, lighting cues, and outfit change timing.

`ShowTrackType` identifies the type of motion event on a robot's track:
`entrance` · `walk` · `pose` · `pivot` · `exit`. `FormationType` describes the
spatial arrangement of robots: `line` · `v` · `scatter` · `pair` · `arc` ·
`custom`. `CollaborationRole` identifies what kind of access a collaborator has
to the show document: `designer` · `director` · `programmer` · `producer` ·
`observer`.

The `ShowDocument` schema is:

| Field                         | Type                    |
| ----------------------------- | ----------------------- |
| `showId`                      | `string`                |
| `title`                       | `string`                |
| `description`                 | `string?`               |
| `durationMs`                  | `number`                |
| `createdAtMs` / `updatedAtMs` | `number`                |
| `revision`                    | `number`                |
| `robots`                      | `ShowRobot[]`           |
| `trackEvents`                 | `ShowTrackEvent[]`      |
| `formationMarkers`            | `FormationMarker[]`     |
| `musicSyncPoints`             | `MusicSyncPoint[]`      |
| `lightingCues`                | `LightingCue[]`         |
| `outfitChangeTriggers`        | `OutfitChangeTrigger[]` |

Sub-types include `ShowRobot` (`robotId`, `displayName`, optional `modelId`,
`defaultOutfitId`), `ShowTrackEvent` (timed `waypoints`/`poseId`/
`pivotAngleDeg`), `FormationMarker` (timed `robotPositions`), `MusicSyncPoint`
(`barNumber`, `beatInBar`, `tempoBpm`, `phraseLabel`), `LightingCue`
(`colorHex`, `intensityPercent`, optional `artNetUniverse` / `sacnUniverse` /
`followRobotId`, `channelValues`), and `OutfitChangeTrigger` (`outfitId`,
`changeWindowMs`, `blocking`).

### 8.2 Editing operations

The show designer uses an operation-based editing model (similar to CRDT
document editors) where every change to a `ShowDocument` is represented as a
typed operation. This enables optimistic concurrency, undo/redo, and
collaboration.

`ShowDesignerOperation` is a discriminated union of **16 operation types** —
`update_show_metadata` plus add/update/remove triplets for `track_event`,
`formation_marker`, `music_sync_point`, `lighting_cue`, and
`outfit_change_trigger`. `ApplyOperationsInput` carries optional `actorUserId`,
`baseRevision` (optimistic concurrency), `summary`, and the operations array.

`ShowVersionSource` identifies how each version was produced: `create` ·
`operations` · `undo` · `redo` · `restore`; each edit produces a
`ShowVersionRecord`. The engine also models real-time collaboration
(`CollaborationSession`, `CollaborationCursor`,
`CollaborationJoinInput`/`CollaborationCursorInput`), a WebSocket event surface
(`ShowDesignerWebSocketEvent`, `ShowDesignerWebSocketEventType`,
`ShowDesignerWebSocketListener`, `SubscribeOptions`), and a REST surface
(`ShowDesignerRestMethod`, `ShowDesignerRestRequest`,
`ShowDesignerRestSuccessResponse<T>`, `ShowDesignerRestErrorResponse`,
`ShowDesignerRestResponse<T>`).

`ShowDesignerApiEngine` (factory `createShowDesignerApiEngine`) implements
`createShow`, `listShows`, `getShow`, `applyOperations`, version history, and
collaboration. **All state is in memory** — there is no HTTP server; the REST
types describe a request/response shape the engine can answer in-process.

### 8.3 Other choreography modules

The remaining modules handle specialized aspects of show production. `show-dsl`
provides a textual show description language. `formation-engine` implements
`planFormationLayout` and the slot geometry for each formation type.
`music-sync` performs audio analysis: beats, downbeats, phrase boundaries, and
robot tempo mapping. `lighting-bridge` translates cues to Art-Net / sACN
protocol messages. `stage-mapper` handles spatial coordinate mapping between the
show coordinate system and the physical stage. `timing-engine` implements
PTP-style clock synchronization, grandmaster election, and sub-microsecond
timeline execution planning with skew/jitter metrics. `rehearsal-engine` runs
shows in reduced-speed mode. `show-scheduler` provides the `ShowSchedulerEngine`
to schedule shows, poll for due schedules, and manage per-robot scheduler state.

---

## 9. Fleet Orchestration (`@galatea/fleet`)

`@galatea/fleet` manages multiple deployed robots as an operational fleet. It
handles tenant/robot registration, status ingestion, remote command dispatch,
and event streaming. Like the show designer, the core orchestrator is an
in-memory service that exposes a typed API surface rather than a live HTTP
server.

Ten modules: `orchestrator`, `capacity-planning`, `digital-nervous-system`,
`federated-learning`, `health-monitoring`, `incident-management`, `ota-updates`,
`raas-billing`, `remote-diagnostics`, `scheduling-engine`.

### 9.1 Fleet orchestrator (`orchestrator/fleet-orchestrator.ts`)

`FleetTenantTier` identifies the subscription level for fleet operators:
`starter` · `pro` · `enterprise`. `RobotOperationalMode` tracks what each robot
is currently doing: `idle` · `performing` · `charging` · `maintenance` ·
`offline`.

Records: `FleetTenant`, `FleetRobotRecord`, `RobotStatusSnapshot`,
`RemoteCommandRecord`, `FleetDashboardSnapshot`. Requests:
`RegisterTenantRequest`, `RegisterRobotRequest`, `ProvisionRobotRequest`,
`RobotStatusUpdate`, `DispatchRemoteCommandRequest`,
`AcknowledgeCommandRequest`.

`RemoteCommandType` enumerates the commands that can be sent to a robot from the
fleet: `goto` · `pose` · `show_start` · `show_stop` · `morph`. The
`RemoteCommandPayload` is the discriminated union carrying the command-specific
parameters. A `RemoteCommandRecord` tracks the command through its status
lifecycle (`queued` / `sent` / …); `pendingCommandCount` counts `queued` +
`sent` records.

`FleetApiSurface` describes the fleet API as data — `RestEndpointDefinition[]`
and `GrpcMethodDefinition[]`. `FleetEvent` is the orchestrator event type
(carries `sequence`, `type`, `timestampMs`, optional `robotId`; `type` includes
`status_ingested`).

`FleetOrchestratorService` (factory `createFleetOrchestratorService`) is an
in-memory service exposing `registerTenant`, `registerRobot`, `provisionRobot`,
`listTenantRobots`, `ingestStatus`, `getDashboardSnapshot`, `listCommands`,
`dispatchRemoteCommand`, `acknowledgeCommand`, and `readEventStream`.

### 9.2 Other fleet modules

The remaining modules address the full operational lifecycle of a robot fleet.
`capacity-planning` models fleet sizing for upcoming events.
`digital-nervous-system` provides the fleet-wide telemetry mesh.
`federated-learning` enables on-device model improvements without centralizing
raw data. `health-monitoring` tracks per-robot health scores.
`incident-management` records and routes incidents. `ota-updates` manages staged
firmware rollout. `raas-billing` implements robotics-as-a-service billing
metering. `remote-diagnostics` enables deep inspection of individual robots
without physical access. `scheduling-engine` manages multi-robot task scheduling
across locations.

---

## 10. Event Handlers (`@galatea/event-handlers`)

Five sub-packages, each an in-process stateful engine. The design is documented
in the architecture doc: these are not message-bus subscribers. Each defines a
frozen event-type constant array, a corresponding event type, an event
interface, an event-handler class, and a factory. Handlers maintain append-only
event logs with listable, filterable event histories.

### 10.1 `robot-events`

The robot-events handler models the complete lifecycle of a robot, from power-on
through boot, fault handling, recovery, and shutdown.

`ROBOT_LIFECYCLE_STATES` (9): `offline` · `booting` · `ready` · `degraded` ·
`faulted` · `recovering` · `shutting_down` · `charging` · `powered_off`.
`SUBSYSTEM_STATES` (8): `offline` · `initializing` · `ready` · `faulted` ·
`isolated` · `restarting` · `recalibrating` · `shutting_down`.

`FaultCategory`: `hardware` · `software` · `safety` · `communications` · `power`
· `environmental` · `unknown`. `FaultSeverity`: `low` · `medium` · `high` ·
`critical`. `RecoveryStrategy`: `restart_subsystem` · `recalibrate_subsystem` ·
`restart_and_recalibrate` · `manual_intervention`. `FaultEscalationLevel`:
`none` · `operator` · `remote_engineering` · `emergency_response`.
`IsolationMode`: `degraded_operation` · `safe_hold` · `manual_override`.

`ROBOT_EVENT_TYPES` (20 events): `robot_registered`, `boot_started`,
`subsystem_initialized`, `self_test_completed`, `robot_ready`, `boot_failed`,
`fault_detected`, `subsystem_isolated`, `recovery_attempted`, `fault_recovered`,
`fault_recovery_failed`, `fault_escalated`, `subsystem_restarted`,
`subsystem_recalibrated`, `operation_resumed`, `shutdown_started`,
`subsystem_powered_down`, `state_persisted`, `charging_started`,
`shutdown_completed`.

`RobotLifecycleEventHandlers` models seven default subsystems
(`power_management`, `safety_controller`, `locomotion_controller`,
`perception_stack`, `choreography_runtime`, `garment_interface`,
`comms_gateway`) with boot priorities, dependency graphs, and
restart/calibration flags. It topologically sorts subsystems by dependency and
boot priority, runs boot self-tests, classifies and isolates faults, selects and
executes recovery strategies, escalates, and persists shutdown state. Public
methods: `registerRobot`, `executeBootSequence`, `handleFault`,
`restartSubsystem`, `recalibrateSubsystem`, `resumeOperation`,
`executeShutdown`, `getRobotSnapshot`, `listFaults`, `getPersistedState`,
`listEvents`. Factory: `createRobotLifecycleEventHandlers`.

### 10.2 `safety-events`

`SAFETY_EVENT_TYPES` (5 events): `e_stop_triggered`, `manual_reset_completed`,
`force_limit_approached`, `collision_detected`, `stability_margin_low`.
`CollisionSeverity`: `low` · `medium` · `high` · `critical`. The module
re-declares the emergency-systems and force-limiting types it needs and exposes
input/result pairs for each event plus a `SafetyRobotSnapshot`.

### 10.3 `show-events`

`SHOW_LIFECYCLE_STATES` (6): `draft` · `ready` · `running` · `degraded` ·
`completed` · `aborted`. `SHOW_CUE_TYPES` (3): `lighting` · `formation_change` ·
`outfit_reveal`. `SHOW_EVENT_TYPES` (8 events): `show_registered`,
`robot_readiness_updated`, `show_started`, `cue_dispatched`,
`robot_fault_handled`, `show_degraded`, `show_aborted`, `show_ended`.
`ShowCueDefinition` is a union of `LightingCueDefinition`,
`FormationChangeCueDefinition`, `OutfitRevealCueDefinition`. The handler
registers show definitions, tracks robot readiness, starts shows, dispatches
cues (producing `CueDispatchCommand`s), handles robot faults during a show, and
ends shows.

### 10.4 `garment-events`

`GARMENT_EVENT_TYPES` (4 events): `tag_read`, `garment_dressed`,
`garment_undressed`, `dpp_scanned`. `GarmentEventHandlers` maintains a garment
catalog, RFID/NFC tag reads, dressed/undressed lifecycle,
digital-product-passport scans, and an `ActiveRobotGarment` view. Factory:
`createGarmentEventHandlers`.

### 10.5 `customer-events`

`CUSTOMER_EVENT_TYPES` (3 events): `customer_approach`, `customer_engage`,
`customer_depart`. `CustomerInteractionMode` tracks the type of interaction
currently in progress: `display_mode` · `engaged_pose` · `voice_interaction`.
`CustomerEventHandlers` produces `CustomerPoseCommand` /
`CustomerHeadTurnCommand` outputs, manages a `CustomerVoiceSession` via a
`CustomerVoiceInteractionAdapter`, and tracks `CustomerInteractionMetrics`.
Factory: `createCustomerEventHandlers`.

---

## 11. Persistence (`@galatea/database`)

Five PostgreSQL-backed store packages, each purpose-built for its data access
pattern. Each package exports DDL types, a `create*SchemaSql(options)` function
that generates `CREATE TABLE` / `CREATE INDEX` SQL, `build*SqlTemplate(...)`
functions for parameterised queries, and a store class that runs against an
injected client. Injecting the client (rather than creating it internally) makes
each store testable without a live database.

### 11.1 `event-store`

The event store is append-only by design. No event can be modified after it is
written — this is a hard architectural requirement for safety audit compliance.
The `PostgresEventStore` class enforces this at the application level; the
`CREATE TABLE` DDL removes update and delete privileges.

`EventDomain`: `safety` · `incident` · `operator_action` · `ota_update` ·
`operational`. `EventSeverity`: `info` · `warning` · `critical`. Types:
`OperationalEventRecord`, `AppendOperationalEventInput`,
`OperationalEventFilter`, `EventIntegrityIssue`, `EventIntegrityReport`,
`EventStoreSchemaSql`, `EventStoreSchemaOptions`, `EventStoreOptions`.
`createEventStoreSchemaSql`, `buildEventAppendSqlTemplate`,
`buildEventQuerySqlTemplate`, and the `PostgresEventStore` class implement the
append-only event log with integrity verification.

### 11.2 `garment-store`

`GarmentCategory` (enum), `GarmentWearSource`: `rfid` · `nfc` · `manual`;
`FitQuality`: `excellent` · `good` · `adjustment_required` · `poor`. Records:
`GarmentCatalogRecord`, `GarmentRfidMappingRecord`, `GarmentDppCacheRecord`,
`GarmentWearHistoryRecord`, `GarmentFitDataRecord`. `PostgresGarmentStore`
persists the garment catalog, RFID mappings, digital-product-passport cache,
wear history, and fit data, with matching schema / upsert / insert SQL builders.

### 11.3 `pose-store`

The pose store supports both vector similarity search (to find poses similar to
a given joint configuration) and full-text search (to find poses by name or
tag). These two access patterns require different index types in PostgreSQL.

`GALATEA_POSE_JOINT_IDS` / `GALATEA_POSE_DOF` fix the pose vector dimensions.
`PoseCategory` (enum), `PoseRecord`, `PoseUpsertInput`, `PoseFilter`,
`PoseSimilaritySearchOptions` / `PoseSimilaritySearchResult`,
`PoseTextSearchOptions` / `PoseTextSearchResult`. Helpers
`createJointAngleVectorFromMap` / `createJointAngleMapFromVector` convert
between joint maps and dense vectors. `PostgresPoseStore` supports vector
similarity search and full-text search over the named-pose library.

### 11.4 `show-store`

`ShowExecutionOutcome` (enum) records whether a show completed, was aborted, or
degraded. Records: `ShowDefinitionRecord`, `ShowDefinitionVersionRecord`,
`ShowExecutionRecord`. `PostgresShowStore` persists show definitions, their
version history, and execution records, with `recordShowExecution` /
`finalizeShowExecution` inputs.

### 11.5 `telemetry-store`

The telemetry store uses TimescaleDB hypertables to handle the high write rate
of joint-state data (up to 1 kHz × 52 joints per robot). The hypertable
partitions data by time automatically, and the `1m`/`1h` continuous aggregates
enable efficient dashboard queries without scanning raw data.

`TimescaleTelemetryStore` ingests `JointStateTelemetrySampleInput`,
`BatteryTelemetrySampleInput`, and `EnvironmentalTelemetrySampleInput`; rows are
`JointStateTelemetryRow` etc. `TelemetryAggregateResolution` is `1m` or `1h`,
producing `*TelemetryAggregateRow`s built on `NumericAggregateStats`.
`DEFAULT_TELEMETRY_RETENTION_POLICY` and `DEFAULT_TELEMETRY_SAMPLING_PROFILE`
configure retention and sampling; `createTimescaleTelemetrySchemaSql` emits the
hypertable schema and a retention sweep returns `TelemetryRetentionSweepResult`.
Time constants: `MINUTE_MS`, `HOUR_MS`, `DAY_MS`.

---

## 12. SDKs (`@galatea/sdk`)

The SDK layer provides typed client surfaces that compose the in-memory engines
for external consumers. There are four SDK packages: the TypeScript client, the
show-authoring SDK, the analytics SDK, and the Python client.

### 12.1 TypeScript client (`@galatea/sdk`, `src/client-ts/client.ts`)

`GalateaClient` (factory `createGalateaClient`) composes three sub-clients over
a `GalateaClientBackend`. The backend is pluggable, but the default
`InMemoryGalateaClientBackend` wires all sub-clients to the in-memory engines
for development and testing.

- `fleet: FleetClient` — `registerTenant`, `registerRobot`, `provisionRobot`,
  `listRobots`, `ingestStatus`, `getDashboard`, `getStatus`, `sendCommand`,
  `acknowledgeCommand`, `listCommands`, `readEventStream`,
  `subscribeRobotStateUpdates`.
- `shows: ShowsClient` — `createShow`, `listShows`, `getShow`, `editShow`,
  scheduler-robot-state upsert/list, `scheduleShow`, `listSchedules`,
  `startShow`, `stopShow`, `startDueSchedules`, `stopScheduledShow`.
- `analytics: AnalyticsClient` — nests `engagement`, `heatmaps`, `revenue`
  clients.

`InMemoryGalateaClientBackend` wires the client to `FleetOrchestratorService`,
`ShowDesignerApiEngine`, `ShowSchedulerEngine`, `EngagementTracker`,
`HeatmapEngine`, and `RevenueAttributionEngine`. There is **no HTTP transport,
no `client.control`, and no IK/telemetry endpoint** — the SDK drives the
in-memory engines directly. `subscribeRobotStateUpdates` polls the
orchestrator's event stream (`pollIntervalMs` ≥ 50, default 500) and emits
`FleetRobotStatusUpdate`s.

### 12.2 Show SDK (`@galatea/sdk/show-sdk`, `src/show-sdk.ts`)

The show SDK provides a fluent builder API that hides the complexity of the
`ShowDocument` schema behind a step-by-step authoring surface. After building a
draft, `validateDraft` runs a comprehensive set of checks before the show can be
deployed.

`ShowAuthoringSdk` (factory `createShowAuthoringSdk`) provides a fluent
`ShowAuthoringBuilder` (`addPathTrack`, `addPoseTrack`, `addPivotTrack`,
`addFormationMarker`, `addFormationFromTemplate`, `addMusicSyncPoint`,
`addMusicSyncPointsFromAnalysis`, `addLightingCue`, `addOutfitChangeTrigger`,
`addMetadataPatch`, `buildDraft`). `validateDraft` returns a
`ShowValidationReport` (deployability, issues, metrics, optional timing summary)
— it checks track waypoint/pose/pivot requirements, formation robot proximity,
path-intersection risk, and runs the choreography timing engine against a
one-microsecond synchronisation target. `deployDraft` validates then persists
via the show designer, throwing `ShowDraftValidationError` on non-deployable
drafts unless `allowUnsafeDeployment` is set. `MusicSyncExtractionStrategy`:
`downbeats` · `phrase_boundaries` · `every_n_beats`.

### 12.3 Analytics SDK (`@galatea/sdk/analytics-sdk`)

The analytics SDK lets consumers define custom events and metrics beyond the
built-in engagement, heatmap, and revenue analytics. It also provides dashboard
widget definitions that feed the `reporting-dashboard` module.

Custom-event tracking and dashboards: `CustomEventSchema`,
`TrackCustomEventInput`, `CustomEventRecord`, metric definitions
(`AggregateMetricDefinition`, `RatioMetricDefinition`), metric evaluation
(`MetricQueryInput`, `MetricPoint`, `MetricEvaluationResult`), and widget
creation inputs (`CreateKpiWidgetInput`, `CreateTimeseriesWidgetInput`,
`CreateLeaderboardWidgetInput`).

### 12.4 Python client (`sdk/client-python`)

The Python client is the primary integration point for ML engineering workflows.
It mirrors the TypeScript SDK's fleet/shows/analytics surface and adds an
`MLOpsClient` for training pipeline and model management operations.

Package `galatea-client-sdk` (PyPI name; Python ≥ 3.9, hatchling build,
`uv.lock`). `galatea_client` exports `GalateaClient`, `create_client`,
`InMemoryGalateaBackend`, and the sub-clients `FleetClient`, `ShowsClient`,
`AnalyticsClient`, `EngagementAnalyticsClient`, `HeatmapAnalyticsClient`,
`RevenueAnalyticsClient`, **`MLOpsClient`**, plus `StartDueSchedulesResult` and
`StopScheduledShowResult`.

---

## 13. Firmware and Hardware Abstraction (Rust manifests)

`@galatea/firmware` and `@galatea/hardware-abstraction` occupy a unique position
in the domain: they contain **no TypeScript implementation logic**. Every source
file is a `*-rust-manifest.ts` that exports a typed manifest describing a
planned Rust crate. The manifest includes the crate path, target MCU/runtime,
capabilities, and supported peripherals. A `get*Manifest()` accessor returns the
manifest for programmatic use (e.g., for OTA deployment tooling).

This approach means the TypeScript domain has a typed, version-controlled
description of every firmware component, even before the Rust crates are built.
The `@galatea/hardware-abstraction` TypeScript packages in the other libraries
(kinematics, locomotion, etc.) use these manifests as their description of the
hardware they interface with.

### 13.1 `@galatea/firmware`

Eight modules: `motor-drivers`, `sensor-interfaces`, `safety-controller`,
`power-management`, `comms-bus`, `rtos-runtime`, `bootloader`, `board-support`.
As an example, `FOC_RUST_DRIVER_MANIFEST` (`foc-rust-driver-manifest.ts`)
specifies: `cratePath: 'libs/galatea/firmware/src/motor-drivers/rust-foc'`,
`targetMcu: 'STM32H7'`, `runtime: 'no_std'`, `controlLoopFrequencyHz: 40_000`, a
capability list (Clarke/Park transforms, SVPWM, PI current regulators, parameter
identification, CAN-FD telemetry), and
`encoderSupport: ['absolute-19bit', 'incremental']`. The sensor-interface
manifests target named devices (`bno085`, `mini45`, `tactile-skin`,
`foot-pressure`, `vl53l5cx`).

### 13.2 `@galatea/hardware-abstraction`

Nine manifest modules: `joint-interface`, `actuator-profiles`, `sensor-fusion`,
`body-morphing`, `face-system`, `hand-system`, `thermal-management`,
`rfid-reader`, `tactile-skin`.

---

## 14. Other Library Surfaces

This section documents the module structure for the libraries not covered in
detail above.

### 14.1 `@galatea/communication`

Six modules, each with **both** a TypeScript implementation and a Rust manifest:
`ethercat-master`, `canfd-interface`, `dds-bridge`, `wifi-mesh`,
`cloud-connector`, `ptp-sync`.

### 14.2 `@galatea/locomotion`

The largest module by file count: **22 sub-modules**. Eight classic locomotion
controllers, each with a Rust manifest — `gait-planner`, `balance-controller`,
`footstep-planner`, `push-recovery`, `stair-navigation`, `step-controller`,
`walking-styles`, `terrain-adaptive-foot-placement`. The remaining 14 are
manifest-free procedural-animation modules: `procedural-walk-cycle`,
`procedural-quadruped-locomotion`, `procedural-arthropod-locomotion`,
`procedural-snake-locomotion`, `procedural-fish-swimming`,
`procedural-bird-flight`, `procedural-appendage-animation`,
`procedural-reach-and-grab`, `procedural-head-look-at`, `procedural-lip-sync`,
`procedural-emotion-blending`, `secondary-motion`, `wind-reactive-fabric-hair`,
and `control-rig-integration`.

### 14.3 `@galatea/whole-body-control`

Six controllers, each with a Rust manifest: `task-space-controller`,
`impedance-controller`, `admittance-controller`, `postural-controller`,
`center-of-mass`, `momentum-controller`. The task-space controller models
`BalanceTaskSpec`, `LocomotionTaskSpec`, `HandPositionTaskSpec`, `GazeTaskSpec`,
`PostureTaskSpec` and exposes `computeDynamicallyConsistentPseudoInverse`.

### 14.4 `@galatea/pose-engine`

Eight modules, each with a Rust manifest: `pose-library` (with a separate
`pose-import-pipeline`), `pose-validation`, `transition-planner`,
`pose-optimizer`, `breathing-simulator`, `micro-movement-gen`,
`contrapposto-solver`, `hand-pose-library`.

### 14.5 `@galatea/perception`

Nine modules (TypeScript implementations): `person-detection`,
`audience-awareness`, `garment-recognition`, `fit-analysis`,
`obstacle-detection`, `depth-processing`, `slam`, `visual-servoing`,
`camera-only-perception`. `PersonDetectionEngine` produces anonymous person
detections / tracks (`PersonCategory`: `child` · `adult` · `unknown`), anonymous
trajectories, and a performance report.

### 14.6 `@galatea/ai`

Sixteen modules: `vla-runtime` (with `vla-finetuning-pipeline`),
`behavioral-engine`, `natural-motion-gen`, `customer-engagement`,
`llm-interaction`, `emotion-expression`, `fashion-trend-ai`,
`attention-prediction`, `reinforcement-learning`, `quiet-locomotion`,
`end-to-end-control` (with `reflex-vla-runtime`), `large-behavior-model` (with
`lbm-evaluation-suite`), `motor-cortex-policy`, `teleoperation`
(`vr-teleoperation-runtime`, `sensor-suit-integration`), `data-collection`
(`training-data-management`), `training-infrastructure`
(`simulation-farm-management`, `training-pipeline-orchestration`). The VLA
runtime supports `VlaModelBackend` (`onnx` · `tensorrt`) and `VlaModelPrecision`
(`fp32` · `fp16` · `int8`).

### 14.7 `@galatea/garment-management`

Eight modules: `cloth-manipulation`, `digital-product-passport`,
`fabric-safety`, `fit-validation`, `outfit-tracking`, `quick-change`
(`quick-change-protocol`), `size-adaptation`, `wardrobe-scheduler`.
`OutfitTrackingSystem` records `OutfitEventType` (`garment_dressed` ·
`garment_undressed` · `garment_swapped`) events against an RFID-scanned
inventory.

### 14.8 `@galatea/simulation`

Eight modules: `physics-engine`, `cloth-simulator`, `digital-twin`,
`show-preview`, `rl-training-env`, `wear-simulator`, `virtual-showroom`,
`scenario-tester`.

### 14.9 `@galatea/analytics`

Seven modules: `ab-testing`, `engagement-tracker`, `heatmap-engine`,
`inventory-bridge`, `pos-integration`, `reporting-dashboard`,
`revenue-attribution`.

### 14.10 `@galatea/inclusivity`

Four sub-packages: `accessibility`, `body-profiles`, `cultural-config`,
`multilingual`. `body-profiles` defines `BodyShape`, `GenderPresentation`
(`feminine` · `masculine` · `androgynous`), `SizeSystem` (`womens_us` ·
`mens_alpha` · `custom`), the `WOMENS_US_SIZES` / `MENS_ALPHA_SIZES` scales,
`BodyDimensionsCm`, `MovementAdaptationConstraints`, and `BodyProfile`.

---

## 15. V2 Vehicle-As-Articulated-Body Modeling Surface

The V2 game project's racing ecosystem reuses Galatea's articulated-body
kinematics to model racing vehicles and their drivers. The
`@v2/racing-ecosystem-bridge` service (in the V2 monorepo, not in
`libs/galatea/`) consumes `@galatea/kinematics` and
`@galatea/whole-body-control` as one of its source-of-truth packages; Galatea
itself has no dependency on V2.

The bridge treats the car-plus-driver rig as a **vehicle-as-articulated-body**:
its `modelingSurface` is literally the string `'vehicle-as-articulated-body'`.
It calls `createGalateaRigidBodyDynamicsModel()` from `@galatea/kinematics` to
build the mass matrix and gravity-compensation torques over the driver's
`JointAnglesRad`, and `runCenterOfMassTracker` from
`@galatea/whole-body-control` to track the rig's center of mass against its
support polygon. From those it derives a driver-articulation summary that feeds
the racing cook, raising `galatea-driver-articulation-unstable` when the center
of mass leaves the support polygon and `galatea-driver-torque-budget-high` when
peak gravity torque exceeds the configured budget.

This is an **authoring / content-cook surface only**. The bridge rejects any RPC
made from a live race frame and carries `mayInfluenceRollback: false`, so the
Galatea articulation model is used to author and validate vehicles offline and
never participates in deterministic per-frame race simulation. See
`V2/docs/integration/racing-ecosystem-bridge.md`;
`V2/ue/Tools/check-v2-racing-ecosystem-bridge.py` enforces the wiring.

_Grounding: `apps/v2/racing-ecosystem-bridge/src/racing-ecosystem-bridge.ts`;
`libs/galatea/kinematics/`, `libs/galatea/whole-body-control/`._

---

## 16. Technology Stack

The table below summarizes the technology choices at each layer of the domain.
These choices reflect the domain's dual requirement of high-level TypeScript
orchestration and low-level real-time Rust control.

| Layer              | Technology                                                              |
| ------------------ | ----------------------------------------------------------------------- |
| Platform language  | TypeScript (Node.js, ESM)                                               |
| Real-time firmware | Rust crates (described by `*-rust-manifest.ts`; `no_std`, STM32H7)      |
| Validation         | Zod (`@galatea/core` schemas)                                           |
| Operational store  | PostgreSQL (`event-store`, `garment-store`, `pose-store`, `show-store`) |
| Telemetry store    | TimescaleDB hypertables (`telemetry-store`)                             |
| Messaging config   | Redis, NATS JetStream, MQTT (config schema only)                        |
| Python SDK         | Python ≥ 3.9, hatchling, `uv`                                           |
| Build              | Nx with `@nx/js:tsc`                                                    |
| Test               | Vitest (`@nx/vite:test`); `pytest` for the Python client                |
| Project tags       | `scope:galatea`, `type:lib`, `layer:domain`, plus `galatea:<module>`    |

---

## 17. Acceptance Criteria

These criteria define what must be true for the Galatea domain to be considered
correctly implemented. They are written as verifiable, concrete checks rather
than aspirational goals.

1. `@galatea/core` exports the Zod-validated `RobotState`, `Pose`, `Trajectory`,
   `MotionPrimitive`, and `ChoreographyScript` schemas with `MIN_ROBOT_DOF = 52`
   enforced, plus the full physical-constant and safety-threshold tables.
2. `solveWholeBodyInverseKinematics` resolves prioritised `end_effector` /
   `center_of_mass` / `gaze` / `posture` tasks, reports per-task convergence and
   degradation, and respects joint-limit, velocity, and self-collision
   constraints.
3. `Iso13482ComplianceEngine` maintains a HAZOP register with ISO 12100 S×P×E
   risk scoring and produces a Markdown compliance audit document.
4. `ShowDesignerApiEngine` applies all 16 `ShowDesignerOperation` types under
   optimistic-concurrency (`baseRevision`) and records a `ShowVersionRecord` per
   edit; `ShowAuthoringSdk.validateDraft` enforces the one-microsecond
   timing-synchronisation target.
5. `FleetOrchestratorService` registers tenants/robots, ingests status,
   dispatches the five `RemoteCommandType` commands, and exposes a replayable
   `FleetEvent` stream.
6. Each `@galatea/event-handlers` package exposes a frozen event-type constant,
   a stateful handler engine, and a filterable event history.
7. Each `@galatea/database` package generates valid `CREATE TABLE`/`INDEX` SQL
   and a store class that runs parameterised queries against an injected client.
8. `GalateaClient` (TypeScript) and `galatea_client.GalateaClient` (Python)
   expose `fleet`, `shows`, and `analytics` over an in-memory backend.
9. Every package builds with `@nx/js:tsc`, type-checks with `npx tsc --noEmit`,
   and passes its Vitest suite (`npx vitest run`).
