# Brigid Domain — Architecture

> Industrial Automation Intelligence bounded context (`libs/brigid/*`,
> `apps/brigid/*`; TODO Phase 59). Architectural overview: layered package
> structure, the shared `@brigid/core` type system, the engineering and
> condition-monitoring algorithms in the capability libraries, the Hono API
> surface, persistence design, and the cross-domain boundary — with honest
> implemented-vs-planned status.

---

Brigid is the industrial-automation bounded context for the Oshun platform. It
provides the type system, engineering calculations, condition-monitoring and AI
algorithms, persistence schema, and application surfaces for factory automation,
industrial energy, maintenance, robotics, process industries, OT cybersecurity,
and the technical workforce — the full stack from plant-floor sensor to
operational dashboard.

The domain exists because industrial operations generate a category of data and
decision-making fundamentally different from commerce, content, or finance:
physical safety constraints, deterministic control paths, OT-grade cybersecurity
requirements, multi-site equipment hierarchies, and calibration records that
must survive regulatory audit. Brigid keeps all of that logic in one place so
that partner domains (Asase, Freya, Cybele, Saraswati, Maat) can consume plant
intelligence without re-implementing it.

Brigid is an **implemented TypeScript workspace** — 238 source files across 24
library packages (`libs/brigid/*`) and five application services
(`apps/brigid/*`), all `@brigid/*`-scoped. There are **zero Rust or Python files
in the domain today**: the polyglot stack the package README aspires to (Rust
edge control, Python ML, Kafka/MQTT/OPC-UA transport, WASM HMI) is roadmap, not
code. Everything described below as "implemented" is real, runnable TypeScript;
everything else is explicitly labelled `(planned)`.

## Workspace Shape

Libraries live under `libs/brigid/` in four bands — foundation, capability
domains, vertical-industry libraries, and support modules. Application services
live under `apps/brigid/` and expose those libraries as operational workflows.

```text
apps/brigid/
  api/          ← Hono HTTP / SSE / WebSocket surface  (@brigid/api)
  factory-os/   ← factory operations dashboard         (@brigid/factory-os)
  energy/       ← energy management system             (@brigid/energy-ms)
  maintenance/  ← maintenance management               (@brigid/maintenance-ms)
  training/     ← training academy / LMS               (@brigid/training-lms)

libs/brigid/
  core/  db/  cross-domain/  sota-enhancements/         ← foundation
  factory/  machines/  ai-industrial/  energy/          ← capability domains
  maintenance/  robotics/  digital-twin/  cybersecurity/
  weighing/  supply-chain/  training/  materials/
  market-intel/  financials/
  mining/  oil-gas/  packaging/  agricultural-mech/      ← verticals
  water/  hvac/
```

Note three app package names differ from their directory names:
`apps/brigid/energy` is `@brigid/energy-ms`, `apps/brigid/maintenance` is
`@brigid/maintenance-ms`, `apps/brigid/training` is `@brigid/training-lms` — and
`@brigid/energy-ms` (app) is distinct from `@brigid/energy` (library).

## Architectural Layers

Brigid is organised in layers, each depending only on the layers below it.

**Foundation** — `@brigid/core` is the shared vocabulary. Its barrel
(`libs/brigid/core/src/index.ts`) re-exports nine modules: `equipment`,
`maintenance`, `energy`, `robotics`, `security`, `business`, `units`,
`validators`, `standards`, plus `schemas`. The type system is aligned to ISA-95,
IEC 61131-3, ISO 12100, IEC 61511, IEC 62443, ISA-18.2 and ISA-101. Identifiers
are plain `string` fields (`equipmentId`, `sensorId`, `workOrderId`) — there are
no branded ID types. `@brigid/db` is the Drizzle ORM schema for a dedicated
PostgreSQL database (TimescaleDB + pgvector). `@brigid/cross-domain` is the only
sanctioned exit point, and `@brigid/sota-enhancements` carries forward-looking
modules (edge AI, 5G remote ops, AR/VR, generative AI, RL, federated learning,
digital thread/quantum) over the same foundation contracts.

**Capability domains** — each library owns one industrial concern while sharing
the foundation contracts: `@brigid/factory` (line design + control-system
integration), `@brigid/machines` (phase-gate machine build),
`@brigid/ai-industrial` (vision, predictive maintenance, optimisation),
`@brigid/energy`, `@brigid/maintenance`, `@brigid/robotics`,
`@brigid/digital-twin`, `@brigid/cybersecurity`, `@brigid/weighing`,
`@brigid/supply-chain`, `@brigid/training`, `@brigid/materials`,
`@brigid/market-intel`, `@brigid/financials`.

**Vertical industries** — `@brigid/mining`, `@brigid/oil-gas`,
`@brigid/packaging`, `@brigid/agricultural-mech`, `@brigid/water`,
`@brigid/hvac` add domain-specific concepts on top of the core types and the
maintenance lifecycle; they extend, never replace, the shared foundation.

**Applications** — the five `apps/brigid/*` services compose libraries into
deployable workflows; the `api` service is the integration point for external
callers and partner domains.

## The Foundation in Depth

### `@brigid/core` — type system, schemas, validators, standards

`equipment.ts` defines the ISA-95 asset ladder (`EquipmentLevel`:
`enterprise → site → area → production_line → work_cell → equipment_unit → control_module`),
the base `Equipment` record, and specialisations (`Machine`, `Sensor`,
`Actuator`, `PLC`, `SCADASystem`/`SCADAPoint`, `HMITerminal`, `ControlLoop`,
`ProductionLine`, `SafetySystem`/`SafetyInstrumentedFunction`).
`maintenance.ts`, `energy.ts`, `robotics.ts`, `security.ts`, and `business.ts`
cover the work-order/calibration/spare-part, energy-asset, robot/twin,
OT-security/ training, and BOM/production/quality/market models respectively.

`schemas.ts` is where the contracts become enforceable. It ships Zod schemas
that reject malformed payloads at ingestion, and crucially encode **domain
invariants as refinements**, not just shapes:

- `OEEMetricsSchema` refines `oee === availability × performance × quality`
  (within 0.001) — an OEE record that violates the identity cannot be stored.
- `SensorSchema.tag` is regex-validated against the ISA-5.1 instrument-tag
  pattern (`/^[A-Z]{1,4}-\d{3,4}([A-Z])?$/`, e.g. `TT-101`), and
  `rangeMax > rangeMin` is refined.
- `CalibrationRecordSchema.measurementPoints` requires `.min(3)` ("At least 3
  calibration points required (ISO 17025)").
- `ProductionOrderSchema` refines `plannedEndDate >= plannedStartDate`;
  `BatteryBankSchema` refines `usableCapacity <= nominalCapacity`.

`validators.ts` is genuinely physics-based, not generic CRUD. It implements
`validatePressureDrop` (Darcy-Weisbach with a Churchill/Haaland friction factor
and laminar/transition/turbulent branching off the Reynolds number),
`validateHeatTransfer` (counter-current LMTD duty), `validateElectricalLoad`
(three-phase full-load current, NEMA voltage-imbalance derating, Ghana-ECG
power-factor penalty), and `validateStructuralStress` (σ = F/A against
yield/safety-factor). The data-quality half flags rather than drops bad
telemetry: `checkSensorRange`, `checkRateOfChange`, `checkStuckValue`,
`checkSpike` (modified Z-score over median absolute deviation), composed by
`assessDataQuality` into a `good | suspect | bad` verdict with diagnostic flags.

`standards.ts` is a real reference registry — `IEC_STANDARDS`, `ISO_STANDARDS`,
`ANSI_ISA_STANDARDS`, `NFPA_STANDARDS`, `API_STANDARDS`, `ASME_STANDARDS`, plus
`GHANA_REGULATIONS` — keyed and queryable via `getApplicableStandards(domain)`.

### `@brigid/db` — persistence schema

`libs/brigid/db/src/schema.ts` defines the Drizzle tables and PostgreSQL enums
(`brigid_equipment_status`, `brigid_equipment_level`,
`brigid_work_order_status`, `brigid_energy_source_type`, `brigid_robot_type`,
`brigid_security_level`, `brigid_certificate_status`,
`brigid_production_order_status`, `brigid_alarm_priority`, and the two
maintenance enums). Worth noting: the persisted `brigid_work_order_status` enum
is the 13-value core lifecycle **minus `pending_approval`** — the
application/type layer carries one more state than the column. Tables cover
sites → factories → areas → lines → work-cells, equipment,
sensors/actuators/PLCs, work orders, spare parts, energy systems (solar arrays,
battery banks), water plants, robots/cells/programs, digital twins, security
assessments + vulnerabilities, training programs + certifications, materials
batches, and calibration records, wired with `relations(...)`.

Four tables are time-series: `brigid_sensor_telemetry` (each row carries
`value`, `unit`, a `quality` flag, `rawValue`, `source`),
`brigid_water_quality_readings`, `brigid_oee_records`, and
`brigid_condition_readings`. These are declared as plain tables in Drizzle, then
**converted to TimescaleDB hypertables via raw SQL in `migrations.ts`**
(`CREATE EXTENSION timescaledb; SELECT create_hypertable(...)`). The same file
enables `vector` and adds an `embedding vector(1536)` column with an `ivfflat`
cosine index to `brigid_ai_embeddings` — pgvector isn't expressible through
`drizzle-orm/pg-core` directly, so it lives in the migration.

## Capability Algorithms

The capability libraries are where the domain depth lives. A representative
sample, each grounded in real exported functions:

- **`@brigid/factory`** — `factory/src/production.ts` implements
  `calculateTaktTime`, `balanceLine` (work-content distribution against takt),
  `sizeBuffer`, `calculateOEE` (six-big-loss decomposition),
  `analyzeBottleneck`, `scheduleJobs` (FIFO/SPT/EDD/CR/SLACK and a genetic
  dispatcher), `runDESSimulation` (discrete- event line model), and
  `optimizeLayout` (A/E/I/O/U/X relationship-code SLP). `factory/src/safety.ts`
  is functional-safety engineering: `performLOPA` (layer-of-protection analysis
  to a residual SIL), `calculateSIFPFDavg` across voting architectures
  (`1oo1`…`2oo3`), `designSIF`, `generateProofTestProcedure`,
  `generateESDMatrix`, and `assessMachineRisk` (ISO 13849 S/F/P risk graph).
  `factory/src/scada.ts` carries an `AlarmManagementSystem` class (ISA-18.2
  alarm state machine and flood/KPI analysis) and ISA-101 HMI screen/faceplate
  generation.
- **`@brigid/ai-industrial`** — `ai-industrial/src/predictive-maint.ts` is not a
  wrapper: it ships a radix-2 Cooley-Tukey FFT, bearing fault-frequency
  calculation (BPFO/BPFI/BSF/FTF), ISO 10816 RMS-velocity severity
  classification, an `OilAnalysisPredictor` (ASTM D-series thresholds), a
  `MotorCurrentSignatureAnalyzer` (broken-rotor-bar sidebands, eccentricity,
  RSH), a `RemainingUsefulLifeEstimator` with three real models (Wiener
  first-passage, Paris-law crack growth, Weibull survival), an `AnomalyScorer`
  (Mahalanobis distance with Gauss-Jordan covariance inversion + CUSUM), and a
  `ThermalImagingAnalyzer` (BFS connected-component hotspot detection + OLS
  trend projection). Sibling modules cover computer vision, process
  optimisation, robotics AI, and edge AI.
- **`@brigid/maintenance`** — `maintenance/src/kpi-analytics.ts` computes
  MTBF/MTTR and availability, benchmarks them, builds Pareto downtime
  breakdowns, ages the work-order backlog, and scores maintenance maturity.
  `maintenance/src/spare-parts.ts` implements `calculateEOQ` (with
  `inverseNormalCDF`/`normalCDF` for service-level safety stock), VED and ABC
  classification, reorder evaluation, and part interchangeability.
- **`@brigid/energy`** — `energy/src/solar.ts` is Ghana-specific: a
  `GHANA_MONTHLY_PSH` irradiance table, `SolarIrradianceAnalyzer`,
  `sizePVSystem`, `configureStrings`, `modelPVPerformance`,
  `analyzeShadingLoss`, and technology-keyed degradation forecasting. BESS,
  grid-hybrid, and power-quality modules sit alongside.
- **`@brigid/robotics`** — `robotics/src/robot-safety.ts` implements a
  `SafetyZoneCalculator` (ISO/TS 15066 speed-and-separation distances), a
  `RobotRiskAssessment` (ISO 13849), a `CollisionDetectionSimulator`
  (AABB/sphere), a `RobotEnergyMonitor`, a `MultiRobotCoordinator`, and an HRI
  workspace designer.

## Component and Data Flow

The path from raw sensor reading to operational decision, and out to partner
domains, runs through the layers as follows:

```mermaid
flowchart TD
  subgraph Edge[Plant floor]
    SENS[Sensors / PLC / SCADA]
  end
  subgraph App[apps/brigid]
    API[@brigid/api Hono\nREST + SSE + WS]
    FOS[factory-os]
    EMS[energy-ms]
    MMS[maintenance-ms]
    LMS[training-lms]
  end
  subgraph Core[Foundation libs/brigid]
    CORE[@brigid/core\nschemas + validators + standards]
    DB[(@brigid/db\nPostgres + TimescaleDB + pgvector)]
  end
  subgraph Cap[Capability + vertical libs]
    AI[@brigid/ai-industrial]
    MAINT[@brigid/maintenance]
    FAC[@brigid/factory]
    ENE[@brigid/energy]
  end
  XD[@brigid/cross-domain\nadapters + Zod contracts]
  CONS[Asase · Freya · Cybele · Saraswati · Maat]

  SENS -->|telemetry batch / WS| API
  API -->|validate + enrich| CORE
  CORE -->|persist| DB
  API --> FOS & EMS & MMS & LMS
  DB --> AI & MAINT & FAC & ENE
  AI -->|RUL / anomaly| MAINT
  MAINT -->|predictive work order| API
  FAC -->|OEE / alarms| API
  ENE -->|dispatch plan| EMS
  API --> XD --> CONS
  CONS -->|provision / maintenance request| XD --> API
```

1. Telemetry arrives as REST batches; PLC/SCADA events arrive over the factory
   WebSocket. `@brigid/core` validates and enriches with industrial semantics
   (ISA-5.1 tags, OEE identity, data-quality flags) before anything is stored.
2. Relational records go to PostgreSQL tables; high-volume streams go to
   TimescaleDB hypertables, keeping ingestion off the transactional path.
3. AI and vertical libraries consume stored telemetry to produce predictions,
   maintenance recommendations, and production decisions.
4. App services expose approved state to dashboards and partner domains —
   partner domains always through `@brigid/cross-domain`, never via direct
   library imports.

## Application Surface

`apps/brigid/api/src/app.ts` builds a Hono application: `secureHeaders`, CORS,
`logger`, `prettyJSON`, a 100-req/min rate limiter on `/api/*`, and an
**optional** JWT middleware that populates an auth context if a `Bearer` token
is present (protected handlers call `requireRole()`; absent/invalid tokens leave
the context unset and are rejected downstream). Health lives at `/health` and
`/ready`; the functional API mounts at `/api/v1` with route groups `equipment`,
`telemetry`, `maintenance`, `energy`, `ai`, `training`, and `cross-domain`.

`telemetry.ts` accepts batches of ≤1000 readings, validates each, and keeps them
**sorted by timestamp** (so out-of-order arrivals are inserted in time order,
not rejected), returning `202` when any reading is accepted. `cross-domain.ts`
exposes `equipment-provision` and `maintenance-request` POSTs that append
`CrossDomainEvent`s (`EQUIPMENT_PROVISION_REQUESTED`,
`CROSS_DOMAIN_MAINTENANCE_REQUEST`) to a queue replayed over the
`GET /api/v1/cross-domain/telemetry/subscribe` SSE stream. `websocket.ts`
defines the `FactoryWSMessageType` union (`SCADA_UPDATE`, `ALARM_ACTIVE`,
`ALARM_CLEARED`, `OEE_UPDATE`, `ASSET_STATUS_CHANGE`, `WORK_ORDER_UPDATE`, plus
`SUBSCRIBE`/`UNSUBSCRIBE`/`PING`/`PONG`) and a `createWebSocketHandler()`.

**Two honest caveats at the app layer.** First, the route handlers persist into
**in-memory `Map` structures** (`telemetryStore`, `provisionRequests`,
`eventQueue`) — the `@brigid/db` schema is the persistence _target_, but the API
routes are not yet wired to it. Second, the `/ws/factory` route currently
returns connection metadata (and `426 Upgrade Required` on a raw upgrade); a
real WebSocket needs the `@hono/node-ws` adapter (`createNodeWebSocket`), which
the app does not yet mount. Both are real seams, honestly reported rather than
faked.

## Persistence

Brigid's design uses four storage technologies, each matched to an access
pattern: **PostgreSQL** for domain records, work orders, financials, and audit
history; **TimescaleDB** hypertables for telemetry and condition streams;
**Redis** for caches and hot dashboard state; and **object storage** for CAD
files, inspection media, robot programs (`program_url` is a MinIO reference),
and reports. The schema and migrations are implemented; the runtime wiring from
the app layer is the in-memory caveat above.

## Cross-Domain Boundary

`@brigid/cross-domain` is the single integration seam. Its barrel
(`cross-domain/src/index.ts`) exports five adapter families —
`asase-integration.ts`, `freya-integration.ts`, `cybele-integration.ts`,
`saraswati-integration.ts`, `maat-integration.ts` — each mapping Brigid DTOs
into a consumer-facing shape (e.g. Asase gets
food-processing/cold-chain/mechanization line designs; Maat gets
OEE/utilisation/RUL/energy analytics). `cross-domain/src/api-contracts.ts` holds
the Zod request/response schemas (`BrigidEquipmentProvisioningRequest/Response`,
`BrigidEnergyIntegrationRequest`, `BrigidMaintenanceServiceRequest/Response`,
`BrigidTelemetryEvent`, `BrigidTrainingEnrolmentRequest`,
`BrigidCertificationRecord`), all keyed by a `requestingDomain` enum of
`asase | freya | cybele | saraswati | maat`. The `libs/brigid` README also names
a `@contracts/brigid` package; the authoritative implemented contracts are the
ones in `@brigid/cross-domain`.

The boundary lets Brigid refactor its internal model without breaking consumers,
and stops consumers depending on Brigid internals. Brigid **owns** the
engineering control systems; consumers own their product economics — Cybele the
built environment, Saraswati the technology products, Asase agricultural
economics, Freya brand and design, Maat organisation-wide rollups.

## Invariants, Failure Modes, and Extension Points

**Invariants** (enforced in code, not aspiration): OEE must equal availability ×
performance × quality; sensor tags must match the ISA-5.1 pattern; calibration
records need ≥3 measurement points; production end-dates must not precede
start-dates; usable battery capacity must not exceed nominal. These live as Zod
refinements in `core/src/schemas.ts` and fail loudly on violation.

**Safety and audit invariants** (design-level, partly type-backed): workflows
touching safety-critical assets (robot cells, safety-instrumented functions,
control paths) carry deterministic fail-safe state —
`SafetySystem.failSafeAction` and `bypassProcedure` exist precisely to record
it; `@brigid/factory`'s LOPA/SIF functions compute the protection layers and
PFDavg that back it. Calibration and maintenance records are intended to be
immutable after signoff, with corrections as append-only events.

**Failure modes a maintainer must respect:** telemetry ingestion tolerates
out-of-order and degraded-quality data (flagged, not dropped); the data-quality
validators classify rather than discard; the OEE/calibration schemas reject
inconsistent records outright rather than coercing them. Singular covariance in
the `AnomalyScorer` falls back to identity rather than producing NaNs. The app's
in-memory stores mean state is process-local and non-durable until the DB wiring
lands — do not treat the API as a system of record yet.

**Extension points:** a new vertical is a new `libs/brigid/<name>` package that
imports `@brigid/core` and the maintenance lifecycle and adds only its specific
types; a new shared concept is a type + Zod schema in `@brigid/core` (high blast
radius — every library imports core); a new external consumer is a new
`*-integration.ts` adapter plus contract schema in `@brigid/cross-domain`; a new
API capability is a route group mounted under `/api/v1` in `app.ts`; forward-
looking capabilities land in `@brigid/sota-enhancements` over the same
contracts.

## Status Summary

**Implemented:** the `@brigid/core` type system, Zod schemas with domain
invariants, physics and data-quality validators, and standards registry; the
`@brigid/db` Drizzle schema + TimescaleDB/pgvector migrations; the capability
algorithms across factory, ai-industrial, maintenance, energy, robotics, and the
verticals; the `@brigid/cross-domain` adapters and contracts; the Hono API with
REST routes, the SSE cross-domain stream, and the WebSocket message model.

**Planned / not yet wired:** API persistence (routes use in-memory `Map`s; the
DB is the target); the live WebSocket upgrade (`@hono/node-ws` adapter not
mounted); a published platform-event catalog and the Kafka/MQTT/OPC-UA
transport; and the Rust/Python/WASM components named in the README. These are
labelled as seams here rather than presented as done.

## Verification Expectations

Changes run the affected packages' Vitest suites, type checks, linting, and
contract checks, plus integration tests for affected app services. Industrial-
safety, OT-cybersecurity, and control-path changes additionally require focused
tests around validation, deterministic fallback behaviour, audit events, and
permission boundaries — the areas where a silent error becomes a physical one.
