Metadata-Version: 2.5
Name: nia-safety
Version: 0.1.0
Summary: Nia: supervisory safety engine for machines that decide for themselves.
Author: Openwist
License: Apache-2.0
License-File: LICENSE
License-File: NOTICE.md
Requires-Python: >=3.11
Requires-Dist: cryptography>=42
Requires-Dist: pydantic>=2
Requires-Dist: pyyaml>=6
Requires-Dist: typer>=0.9
Provides-Extra: advisor
Requires-Dist: openai>=1.40; extra == 'advisor'
Provides-Extra: dev
Requires-Dist: hypothesis>=6; extra == 'dev'
Requires-Dist: mypy>=1.13; extra == 'dev'
Requires-Dist: pillow>=10; extra == 'dev'
Requires-Dist: pytest-benchmark>=4; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff>=0.8; extra == 'dev'
Requires-Dist: types-pyyaml; extra == 'dev'
Provides-Extra: viz
Requires-Dist: pillow>=10; extra == 'viz'
Description-Content-Type: text/markdown

# Nia

**A supervisory safety layer for machines that decide for themselves.** Nia sits between a learned policy and the robot. It checks what the machine is about to do, and what state it is really in, against explicit rules. Under tighten-only authority it can pass the action, substitute a safe fallback, or end the run. Every decision becomes tamper-evident evidence.

Built by [Openwist](https://openwist.com) during the Meta Global AI Developer Hackathon (Startup track, 26 October to 4 November 2026).

> **Status: hackathon build, simulation only.** Nia is not a certified safety function and makes no claim of compliance with any standard or regulation. Results below come from a toy environment; results on Meta Motivo are pending (see [Evidence](#evidence)).

> **Test subject and third-party notice.** The humanoid controller in the demo is **Meta Motivo** and the environment is **HumEnv**, both by Meta (FAIR), used under their licence (CC BY-NC 4.0, non-commercial). They are not part of Nia, are not distributed with it, and were not built by us. Nia contains no Motivo code or weights; the glue code that connects Nia to Motivo lives in `examples/motivo/` and requires you to install Motivo yourself. Nia is not affiliated with or endorsed by Meta. Everything in `src/nia/` was written during the hackathon window.

## In 30 seconds

- **What it is:** a software layer between a learned robot policy and the robot that checks mode, state, commands and data against rules, and can only make the machine safer (pass, substitute a fallback, or hand over). It writes signed, tamper-evident evidence.
- **What it caught (toy environment, 100 held-out runs each):** after a declared-standby mismatch the robot was stopped in 1.8 s, where without Nia it kept walking for 8.2 s until it reached its target; contact after a sensor dropout fell from 84% to 0%; falls after an untrusted unsafe command fell from 100% to 0%; overhead 0.19 ms p99 per step in nominal runs (H-07 first run; 0.16-0.26 ms across scenarios; 0.46 ms re-measured in the second run).
- **What it did not catch (first run):** 4% of policy-fault runs still fall; the second run with TOY-ACT-02 brings H-06 to 0% (see Evidence).
- **What is still pending:** results on Meta Motivo (the humanoid test subject). The glue is written and tested against a fake humanoid; the real run is the next step.
- **Watch it:** `video/Nia_demo_3min_narrated.mp4` (3 minutes, synthetic voice-over; silent cut: `video/Nia_demo_3min.mp4`; built from the real traces, no scripted values).

## Install

```powershell
pip install nia-safety
```

Release 0.1.0 is live at https://pypi.org/project/nia-safety/.

## Verify it yourself

```powershell
pip install -e ".[dev]"
python scripts/dev.py check                     # lint, types, 175 tests
nia eval scenarios/toy --seeds 100-199 --out results/check --split evaluation
nia report results/check                        # compare with results/evaluation/SUMMARY.md
nia keygen --out ..\nia-keys                    # keep keys outside the repo
nia verify-log <an evidence log> --pubkey ..\nia-keys\nia_ed25519.pub   # edit one byte and run it again
```

## Status

| Area | Status |
|---|---|
| Rule engine, wrapper, evidence log, evaluation, advisor, videos | Built and tested (toy environment, fake client, fake humanoid) |
| Held-out toy evaluation | Run once; results in `results/evaluation/` |
| Meta Motivo runs (calibration, held-out evaluation, frames) | Written, **not yet run on the real model** |
| Muse advisor on a real model | Written and tested with a fake client; real run pending |
| ROS 2 and OPC UA adapters, compiled core, signed rule packs | Designed, not built (`docs/SCALE_PATHWAY.md`) |

## Why

Hardware safety (scanners, safety controllers, e-stops) is mature at the edge of a robot. What is under-served is the layer above it: is the machine's declared mode the same as what it is doing, who authorised that bypass, did someone change the logic, what happens when a learned policy or a command from an untrusted source asks for something unsafe, and can anyone reconstruct what happened afterwards? Public accounts of recent industrial incidents often point to mode, bypass and change problems rather than missing distance sensors (allegations in several cases; see `docs/ARCHITECTURE.md`, section 2). Nia makes that layer software with its own rules, tests and evidence.

## How it works

```mermaid
flowchart LR
  PM["Prompt manager (operator, planner, untrusted)"] -->|"command request"| W
  PO["Policy: act(obs)"] -->|"proposed action"| W
  subgraph W["NiaGymWrapper"]
    X["Extractor: raw state to signals"] --> S["SafetyState"] --> R["Rules + arbiter"] --> E["Enforcer"]
    R --> L["Evidence log"]
  end
  E -->|"action or fallback action"| ENV["Environment / robot"]
  ENV -->|"observation"| PO
  ENV -->|"raw state"| X
  L -.->|"read later"| AD["Muse advisor (off the loop)"]
```

| Outcome | What the wrapper does |
|---|---|
| ALLOW, ALERT | Pass the policy's action (ALERT also notifies) |
| HOLD | Substitute the fallback action until the clear condition holds (hysteresis) |
| VETO | Reject a command request |
| SAFE_STOP | Fallback and latch until an authorised release |
| HANDOVER | End the episode for a human |

Principles: **tighten-only** (it can only make things safer), **unknown is conservative** (stale or missing data counts against the machine), **no model in the real-time path** (models live in `src/nia/advisor`, off the loop), **evidence by default**, **humans approve rule changes**.

## What is in the repository

| Path | Contents |
|---|---|
| `src/nia/core` | State estimator with three-valued logic, bounded rule engine, arbiter, evidence log |
| `src/nia/adapters/gym_wrapper.py` | The wrapper that makes Nia the top layer over any Gymnasium-style environment |
| `src/nia/evaluation` | Scenario files, injectors, metrics, statistics, runner (A, B, C configurations), video compositor |
| `src/nia/advisor`, `src/nia/lifecycle` | Muse advisor: cited incident reports, rule proposals, regression that blocks harmful proposals |
| `profiles/`, `scenarios/` | Machine profiles with rule packs (`toy`, `humanoid_motivo`, `robot_cell`) and scenarios |
| `examples/motivo` | Glue for Meta Motivo (optional, separate environment) |
| `results/` | Result files, summaries and videos produced by the code above |

## Quickstart (no Motivo needed)

```powershell
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -e ".[dev]"
python scripts/dev.py check                                   # lint, types, tests
nia eval scenarios/toy --seeds 0-19 --out results/tuning --split tuning
nia report results/tuning
nia decide --profile profiles/robot_cell --state examples/state_sim01_dry_run_motion.json --now-ms 1000
```

Evidence log tools: `nia keygen --out <folder outside the repo>`, `nia verify-log <log> --pubkey <key>`. Videos: `pip install -e ".[viz]"`, install ffmpeg, then `nia compose --left <trace B> --right <trace C> --out video.mp4`.

## Evidence

**Toy environment, held-out seeds 100 to 199, run once after thresholds were committed** (`results/evaluation/`, medians; A = policy alone, B = plus a simple reactive proximity stop, C = plus Nia). The toy environment is a point robot with a first-order velocity response; it validates the machinery and is **not** evidence about Motivo.

| Scenario | B (reactive stop) | C (with Nia) |
|---|---|---|
| H-01 declared standby while the policy keeps walking | keeps walking; halts only at its target after 8.2 s | stopped after 1.75 s |
| H-02 person on the path: closest approach | 0.37 m | 0.68 m |
| H-04 sensor dropout near a person: collisions | 84% | 0% |
| H-05 untrusted command asks for an unsafe speed: falls | 100% | 0% |
| H-06 policy fault (violent commands): falls | 96% | 4% |
| H-07 nominal pass at a distance: episodes with an intervention | n/a | 0% (progress 12.3 m vs 12.3 m alone) |

Nia overhead in the toy runs (config C medians from `results/evaluation/H-*.json`): step-time median 0.09 ms and p99 0.19 ms in the nominal scenario H-07; p99 medians range 0.16 to 0.26 ms across scenarios (Python, one laptop-class CPU; a target to re-measure on your hardware). Re-measured on the second machine (`results/evaluation_v2/`): H-07 p99 0.46 ms.

What the runs also showed, honestly:
- **Not every fault is caught.** In H-06, 4% of runs still fall: abrupt command reversals that stay under the magnitude cap. A rate-of-change rule is the next fix.
- **Stopping is not free.** A hold keeps the robot from moving closer, but it stops short of the task. In H-02 both B and C end short of the target by design.
- **Tests found a real design bug.** Judging only current speed let the robot creep back toward the person after each hold; the extractor now judges the speed the policy is *asking for*.
- **Second evaluation done.** A fresh held-out run after TOY-ACT-02 (`results/evaluation_v2/`, same seeds 100 to 199) moved H-06 falls from 4% to 0% with H-07 still at 0% episodes with an intervention. At H-05 the rule now shows 100% episodes with an intervention (one brief hold on the turnaround after the accepted operator command) while unsafe commands executed stay at zero. The demo video shows the first run.

**Meta Motivo results: pending.** The calibration and held-out evaluation for the humanoid are run with `examples/motivo` following `docs/EXPERIMENT_PROTOCOL.md`; this section will be updated with numbers from `results/motivo/` only.

Videos built from real run traces are in `results/evaluation/videos/`. Every value on screen is read from the traces.

## Integration and scale pathway

Nia is designed to plug into existing and future robots in stages: shadow (read-only), alert, gate, and safety-linked (a stop request into certified hardware), with the same engine and an open profile, rule and evidence format. Press reports (May 2026) say Meta wants to do for humanoid robots what Android did for phones; an ecosystem like that needs a vendor-neutral supervisory layer that third-party builders and assessors can inspect. Nia is built to be that layer. We are not affiliated with Meta and this is design intent, not an endorsement. See `docs/SCALE_PATHWAY.md` for adapters, the open spec, the roadmap and how to contribute.

## Limitations

- Simulation only; no real robot has been controlled. Thresholds are placeholders until calibrated and need independent safety assessment before any real use.
- The Python core suits supervisory rates (roughly 10 to 50 Hz); hard real-time protection stays with certified controllers. A compiled port verified against shared conformance tests is on the roadmap.
- Meta Motivo is a non-commercial research model used as a test subject only.
- Nia does not replace certified hardware safety, standards, regulation or certification.

## Licence and provenance

Licence: Apache-2.0 (see `LICENSE`). Provenance and third-party notices: `NOTICE.md`.
