From c3147a8830ac7efa0f0306bd00aa970418d2f202 Mon Sep 17 00:00:00 2001 From: ruvnet Date: Sat, 15 Aug 2026 21:30:19 +0000 Subject: [PATCH] deploy: 1d50518a70254660006911f37aede77fed142d43 --- ...ust-physics-constrained-pose-refinement.md | 364 ++++++++++++++++++ api-docs/adr/README.md | 1 + .../benchmarks/physics-pose-refinement.md | 71 ++++ .../schemas/pose-observation-v2.schema.json | 38 ++ .../schemas/pose-refinement-v1.schema.json | 36 ++ 5 files changed, 510 insertions(+) create mode 100644 api-docs/adr/ADR-323-native-rust-physics-constrained-pose-refinement.md create mode 100644 api-docs/benchmarks/physics-pose-refinement.md create mode 100644 api-docs/schemas/pose-observation-v2.schema.json create mode 100644 api-docs/schemas/pose-refinement-v1.schema.json diff --git a/api-docs/adr/ADR-323-native-rust-physics-constrained-pose-refinement.md b/api-docs/adr/ADR-323-native-rust-physics-constrained-pose-refinement.md new file mode 100644 index 00000000..dbc014e1 --- /dev/null +++ b/api-docs/adr/ADR-323-native-rust-physics-constrained-pose-refinement.md @@ -0,0 +1,364 @@ +# ADR-323: Native Rust physics-constrained pose refinement + +- **Status**: Proposed +- **Date**: 2026-08-15 +- **Deciders**: ruv +- **Owners**: RuView perception and edge runtime maintainers +- **Tags**: pose, physics, rust, uncertainty, provenance, abstention, edge +- **Numbering note**: ADR-323 is the next free number in the authoring checkout. Re-run the ADR index/collision check immediately before merge and rename if needed. +- **Extends**: ADR-020, ADR-027, ADR-079, ADR-101, ADR-135, ADR-145, ADR-150, ADR-273, ADR-279, ADR-282, ADR-295, ADR-296, ADR-297, ADR-298, ADR-302, ADR-303, ADR-304, ADR-305, ADR-306 +- **Supersedes**: None + +## Executive decision + +RuView will add a clean-room native Rust boundary between RF pose inference and +semantic publication. It will preserve the immutable RF observation, publish a +physics assessment, optionally produce a bounded corrected candidate, and +abstain when required evidence is absent. It must never increase observational +confidence merely because a pose is physically plausible. + +Three independently gated layers are adopted: + +1. A deterministic kinematic auditor and bounded covariance-weighted projector + using Rust and `nalgebra`. +2. An optional articulated-body dynamics auditor using `rapier3d`. +3. A later optional supervised residual model using Burn. + +The first production milestone is deterministic audit. It is not a GRIP port, +not PPO, and not evidence that the current pose observer is production-ready. + +## Context + +ADR-101's committed Cog emits 17 COCO keypoints as normalized 2D coordinates. +Its model has no per-joint uncertainty head and publishes a constant confidence. +The sensing server also contains renderer-oriented EMA and bone clamping. These +surfaces cannot establish metric 3D physics and can make weak evidence look +more convincing. + +Pose output can violate bone length, floor, velocity, acceleration, and temporal +continuity constraints. Downstream consumers also cannot reliably distinguish +observed coordinates from derived correction. The rejected premise is: +"physically plausible means more likely correct." Plausibility is only a prior; +many incorrect poses are plausible. + +GRIP is architectural inspiration for an observer/controller split, but it +observes four wearable IMUs and pressure insoles and drives a simulator. RuView +observes RF, so GRIP weights are not input-compatible. External code, weights, +simulators, and datasets require independent license review and never enter the +runtime dependency graph by implication. + +## Outcome and actors + +For every accepted person track/timestamp, the engine returns exactly one +`PoseRefinementV1`, including off, timeout, rejection, and abstention paths: + +- immutable `PoseObservationV2` content hash; +- constraint residuals and quality disposition; +- an optional bounded candidate and an explicit `selected` bit; +- a typed reason when correction is unavailable; +- model, calibration, configuration, and optional learned-artifact provenance. + +The RF observer owns observations and calibrated uncertainty; tracking owns +identity stability; physics owns assessment/correction only; the sensing server +owns deadlines, modes, publication, and rollback; the evidence engine owns +release evaluation; clients choose raw/both/refined without silent fallback. + +## Input and coordinate contract + +Metric correction requires a monotonic nanosecond timestamp, session-scoped +track ID, sequence and sensor epoch, 17 ordered COCO joints in metric X/Y/Z, +per-joint positive-semidefinite covariance calibrated on held-out data, a +versioned right-handed Z-up room frame, a normalized upward floor plane, model +and calibration hashes, ADR-302 trust state, and authenticated/replay-protected +source provenance. + +`Image2d` observations may be audited for image-plane ratios and continuity but +must never enter 3D projection/dynamics or be called physically corrected. +Unknown trust, missing calibration, missing uncertainty, stale/non-monotonic +input, non-finite values, invalid covariance, excessive tracks, and room-bound +violations fail to raw output with a typed reason. + +## Public contracts + +`wifi-densepose-core` owns `PoseObservationV2` and `PoseRefinementV1`; no +duplicate server/Cog contract is permitted. Public output remains COCO17. The +engine derives pelvis and thorax virtually and never labels them observed. + +The raw content hash is deterministic and excludes its own hash field. The +idempotency key is `(sensor_epoch, sequence, track_id, raw_hash, config_hash)`. +An exact duplicate returns the cached result; same sequence with different +content is a replay rejection. + +Contact is `hypothesis` unless a measured sensor and its provenance say +otherwise. Raw, derived, hypothesis, and unknown labels must survive every +projection. + +## Confidence invariant + +For upstream calibrated confidence `c_obs`, normalized residual `r`, and +normalized intervention `i`: + +```text +c_physics = exp(-(beta_r * r + beta_i * i)) +c_effective = min(c_obs, c_obs * c_physics) +0 <= c_effective <= c_obs <= 1 +``` + +Only a separately witnessed multimodal fusion contract may increase fused +confidence. + +## Deterministic projector + +The default `kinematic` feature has no Rapier, Burn, ONNX, libtorch, Python, +CUDA, or network dependency. Per bounded iteration it: + +1. projects observed parent/child distances toward anonymous track-scoped + bone-length posteriors; +2. applies broad joint/trunk validity checks without an upright prior; +3. bounds temporal motion and resets derivatives after gaps; +4. resolves floor penetration only, allowing seated, kneeling, prone, child- + scale, mobility-aid, and genuine-fall poses; +5. recomputes residuals and stops below epsilon. + +Initial operator-owned caps are four iterations (hard maximum eight), 0.20 m +single-joint correction, 0.10 m root correction, 250 ms derivative gap, 500 ms +track reset, ten known joints, a 100 m metric room bound, a separate 16,384 +image-coordinate audit bound, and a 5 ms one-track Pi 5 p95 gate. Keeping image +and metric bounds separate prevents legitimate pixel observations from +weakening the physical room bound. A candidate over either correction cap is +discarded in full. + +Bone posteriors are initialized only from high-confidence frames, anonymous, +memory-only, track-scoped, and deleted on expiry. Persistent personalization is +outside this ADR and requires consent/retention/deletion governance. + +## Optional dynamics and learned layers + +`dynamics` adds a process-owned Rapier humanoid and begins audit-only. Network +input may never provide Rapier snapshots, bodies, constraints, solver limits, +or arbitrary geometry. Dynamics approval is independent of kinematic approval. + +`learned` uses first-party Burn 0.21 core/NN components without `burn-tch` +because this workspace already has a different native libtorch link. +`learned-cpu` adds the ndarray backend. The implemented two-layer GRU uses a +20-frame history and width 128 to predict bounded residuals, uncertainty, +foot-contact hypotheses, and abstention. Verified model records can be loaded +from bytes and executed natively; no trained artifact is shipped or approved. +The resolved Burn/CubeCL graph declares Rust 1.92, while the workspace file +pins Rust 1.89 and the authoring host provides Rust 1.91.1. +`--ignore-rust-version` is diagnostic evidence only: learned activation remains +blocked until an approved Rust 1.92 release-toolchain change builds it without +that override. Residuals are hard-clipped to deterministic caps and cannot +bypass validation or confidence monotonicity. PPO is deferred until measured +evidence identifies a failure supervised residual learning cannot address. + +## Feature boundary + +```text +default = kinematic +dynamics = rapier3d +learned = burn-core + burn-nn +learned-cpu = learned + burn-ndarray +learned-train = learned + burn-train +learned-wgpu = learned-train + burn-wgpu +learned-cuda = learned-train + burn-cuda +deterministic = rapier3d?/enhanced-determinism +``` + +The lockfile is release authority. The learned feature currently requires the +toolchain supported by Burn/CubeCL's resolved graph; this does not change the +default edge build. + +## Runtime modes and API + +Rollout is `OFF -> AUDIT -> SHADOW_CORRECT -> OPT_IN_CORRECT -> DEFAULT_CORRECT`. +Evidence permits forward transitions; any regression returns immediately to +audit/off. Correct selection additionally requires authenticated sensor +identity and replay protection from ADR-305. High model confidence cannot +override missing source authentication. + +Existing pose fields stay unchanged and raw remains the migration default: + +```text +GET /api/v1/pose/current?view=raw +GET /api/v1/pose/current?view=both +GET /api/v1/pose/current?view=refined +``` + +Refined-only returns HTTP 409 with `pose_refined_unavailable` when no selected +candidate exists. It never silently returns raw labeled refined. + +## Security, privacy, and availability + +All frames, model output, geometry, and pre-verification artifacts are +untrusted. Calibration/config/model artifacts become trusted only after signed, +hash-addressed verification and atomic activation. Runtime inference performs +no model retrieval or other network access. + +Fixed arrays/caps, bounded iterations, a maximum track count, room geometry +limits, deadlines, and track expiry constrain denial of service. Timeout drops +partial refinement, never raw publication. Backpressure retains the newest raw +frame per track, drops intermediate refinement work, resets derivatives after +250 ms, and never extrapolates beyond 500 ms. + +Metrics contain only allowlisted aggregate scalars: mode/disposition/reason, +stage latency, iterations, maximum correction, residuals, confidence delta, +track resets, invalid input, timeout, and raw/refined divergence. They exclude +joint arrays, body dimensions, room coordinates, CSI, and persistent person +identifiers. Bone/gait state is memory-only and excluded from logs. + +Refined output is not a sole medical, emergency, industrial-safety, or +autonomous-control source. A real fall is valid state and must never be made +upright to stabilize a simulator. + +## Threat model summary + +| Threat | Primary control | Residual risk | +|---|---|---| +| Spoofed/replayed sensor | ADR-305 identity, MAC, sequence and replay window; correction gate | Compromised legitimate sensor | +| Altered model/floor/config | Signed hashes, authenticated configuration, atomic activation | Authorized unsafe configuration | +| Poisoned data/splits | Immutable manifests, strict split validator, witnessed benchmarks | Subtle label poisoning | +| Operator repudiation | Append-only witnessed transition with actor/old/new hash/reason | Compromised signer | +| Biometric/log leakage | Track-local retention and fixed metric allowlist | Aggregate inference | +| Track/geometry CPU flood | Authentication, cardinality/geometry/allocation/deadline caps | Valid dense-scene overload | +| Remote mode escalation | Capability-scoped local control plane, deny by default | Compromised operator capability | +| Derived output relabeled observed | Required schema/provenance and signed event envelope | Malicious downstream stripping | + +The implementation review records commit, lockfile hash, Rust toolchain, +scanner versions, and advisory-feed timestamp. + +## Evidence protocol + +Evidence levels are L0 deterministic synthetic, L1 public measured replay, L2 +controlled RuView RF plus optical truth, L3 subject/room/hardware/session- +disjoint RuView, L4 privacy-safe shadow fleet aggregates, and L5 independent +vertical validation outside this ADR. + +No sequence, contiguous take, subject, room, or calibration session may cross +train/test for the generalization gate. Preprocessing, body priors, and +uncertainty calibration fit training data only. Reports include raw observer, +renderer smoothing, audit, deterministic correction, dynamics audit, and +learned residual on identical observations, plus empty-room, prone/fall, +missing-joint, and OOD subsets. + +Primary metrics are 3D MPJPE, declared-threshold PCK, per-joint error, foot +slide, floor penetration, jerk, uncertainty calibration, abstention coverage, +and selective risk. Learned runs use at least five fixed seeds and report mean, +median, standard deviation, and 95% bootstrap intervals. All frames count; +selective metrics report risk and coverage. + +## Acceptance gates + +- **G0 contract**: real metric 3D/covariance output, round-trip raw hash, + versioned frame/floor, 2D compatibility, non-stub observer, ADR-298 artifact + sanity, and the ADR-079 PCK@20 >=35% gate or adopted successor. The current + committed Cog does not pass G0, so correction remains unavailable. +- **G1 deterministic audit**: property/fuzz tests, deterministic hashes per + platform class, 24-hour accelerated replay without panic/growth, Pi 5 p95 + <=5 ms, and universal confidence monotonicity. +- **G2 shadow correction**: strict-disjoint measured median MPJPE improvement + >=10% with positive 95% CI lower bound; foot slide >=30% and jerk >=25% + better; no joint median >5 mm worse; fall/prone sensitivity change <=2 pp; + >=95% corrections below 0.10 m; every correction above 0.20 m abstains. +- **G3 opt-in**: >=30 subjects, 10 rooms, 3 hardware configurations, and 3 + independent sessions/room; UNKNOWN never selected; confidence monotonic; + live disable; REST/WebSocket/MQTT/Home Assistant/replay compatibility. +- **G4 default visualization only**: 30 shadow days under 0.1% timeout/internal + error, no open severity 1/2 incidents, and gates still valid for current + model/calibration. + +Dynamics and learned engines each repeat G2-G4; approval is not inherited. + +## Testing and completion evidence + +Unit/property/fuzz/integration/security coverage maps to requirements R1-R13: +raw hash, confidence, modes, malformed/stale/frame/covariance input, caps and +deadlines, provenance, dependency graph, pose diversity/fall preservation, +strict splits, fail-to-raw faults, no network capability, and authenticated +source/replay selection. + +Release commands include focused core/physics tests, default/dynamics/learned +feature checks, format/clippy, benches, `cargo deny`, `cargo audit`, strict split +verification, and golden replay verification. Completion also requires JSON +schemas, measured Pi 5/x86 rows, strict manifest hashes, raw/refined metrics, +SBOM/license report, rollback drill, and residual-risk owners. Missing measured +or operational evidence leaves status Proposed and runtime in audit. + +## Rollback + +Rollback is an authenticated mode transition to audit/off, not a binary +downgrade. Stop selection immediately, keep raw publication and disposition +records, discard track state, and retain only aggregate incident metrics plus +signed configuration history. Failed artifact activation leaves the previous +engine atomically active. Additive schemas remain; refined-only callers receive +the typed unavailable response. + +## Consequences + +### Positive + +- Explicit anti-hallucination and provenance boundary after RF inference. +- Reusable native Rust consistency primitive with measurable abstention. +- Python/CUDA remain absent from the production default. +- Cross-modal teacher data remains possible without wearable runtime inputs. + +### Negative + +- Full value requires a real metric 3D observer and calibrated uncertainty. +- Stateful tracks add latency/memory; optional backends add supply-chain surface. +- A constrained but wrong pose can look more credible. +- Strict data collection costs more than the software implementation. + +### Neutral + +- This ADR does not improve RF observability or current weight evidence. +- Existing 2D consumers continue to function. + +## Implementation phases + +P0 contracts/schemas; P1 deterministic audit; P2 bounded shadow correction; P3 +server/Cog publication and evidence ledger; P4 Rapier audit; P5 Burn residual +training/inference. Code may land ahead of evidence, but runtime authority +advances only through the gates above. + +## Implementation status at proposal + +- P0-P3 are implemented on this branch: canonical contracts, strict schemas, + deterministic audit/projection, authenticated correction receipts, + idempotency, bounded track state, latest-frame backpressure, additive HTTP + and WebSocket publication, live legacy-2D audit, privacy-safe metrics, golden + replay, and strict-split checks. +- P4 is implemented as an optional persistent per-track Rapier dynamics auditor + and remains audit-only pending independent G2-G4 evidence. +- P5 inference architecture, artifact verification, serialization, and native + CPU execution are implemented. Training data, a signed trained artifact, and + G2-G4 accuracy/calibration evidence do not exist, so the layer has no runtime + selection authority. Its resolved Rust 1.92 requirement is also an explicit + activation blocker on the current Rust 1.91.1 release host. +- The live Cog honestly emits `Image2d`, degraded trust, and uncalibrated + uncertainty. It can be audited but cannot be selected for 3D correction. + G0 therefore remains open until an independently released metric-3D observer + with calibrated covariance is integrated. +- Local x86 latency and synthetic contract checks are recorded in the append- + only evidence ledger. Pi 5 measurements, 24-hour replay, 100-million-case + fuzzing, held-out RF/optical accuracy, fleet shadowing, and vertical safety + validation remain release evidence gates rather than software claims. + +## References + +- [GRIP project](https://ryosukehori.github.io/grip-project/) +- [GRIP paper (arXiv:2603.16233)](https://arxiv.org/abs/2603.16233) +- [Rapier documentation](https://docs.rs/rapier3d/) +- [Burn documentation](https://docs.rs/burn/0.21.0/burn/) +- [ADR-020](./ADR-020-rust-ruvector-ai-model-migration.md) +- [ADR-079](./ADR-079-camera-ground-truth-training.md) +- [ADR-101](./ADR-101-pose-estimation-cog.md) +- [ADR-150](./ADR-150-rf-foundation-encoder.md) +- [ADR-273](./ADR-273-unified-rf-spatial-world-model.md) +- [ADR-279](./ADR-279-native-rf-frame-contract.md) +- [ADR-298](./ADR-298-model-release-sanity-gates.md) +- [ADR-302](./ADR-302-out-of-distribution-detection.md) +- [ADR-303](./ADR-303-ground-truth-synchronization.md) +- [ADR-304](./ADR-304-evidence-engine.md) +- [ADR-305](./ADR-305-authenticated-sensor-identity.md) +- [ADR-306](./ADR-306-canonical-spatial-ontology.md) diff --git a/api-docs/adr/README.md b/api-docs/adr/README.md index 30b240f6..2b7a6ff1 100644 --- a/api-docs/adr/README.md +++ b/api-docs/adr/README.md @@ -179,6 +179,7 @@ Statuses: **Proposed** (under discussion), **Accepted** (approved and/or impleme | [ADR-319](ADR-319-witness-chain.md) | Witness chain — staged, signed epistemic envelope | Accepted (phase 1) | | [ADR-320](ADR-320-sensor-hal.md) | RuView sensor HAL — abstract all sensing hardware to one Observation type | Proposed (phase 2) | | [ADR-321](ADR-321-decision-policy-action-authorization.md) | Decision policy — action authorization conditioned on certificate class, freshness, uncertainty, evidence | Accepted (phase 1) | +| [ADR-323](ADR-323-native-rust-physics-constrained-pose-refinement.md) | Native Rust physics-constrained pose refinement | Proposed | --- diff --git a/api-docs/benchmarks/physics-pose-refinement.md b/api-docs/benchmarks/physics-pose-refinement.md new file mode 100644 index 00000000..fa3bf8f6 --- /dev/null +++ b/api-docs/benchmarks/physics-pose-refinement.md @@ -0,0 +1,71 @@ +# Physics pose refinement evidence ledger + +ADR-323 performance and accuracy targets are gates, not measured claims. Append +rows; never replace prior measurements. Every row must identify the repository +commit, lockfile hash, Rust toolchain, target, engine/features, configuration +hash, corpus/split hash, command, sample count, and evidence label. + +## Runtime measurements + +| Date | Commit | Lock SHA-256 | Target/toolchain | Engine/config | Tracks | Samples | p50 | p95 | p99/max | RSS delta | Evidence | Reproducer | +|---|---|---|---|---|---:|---:|---:|---:|---:|---:|---|---| +| 2026-08-15 | `de27336` + uncommitted ADR-323 changes | `552737eab9092b59ea9dd2b2caf68389f0b0966679f0fbb33ff2b1b3d42e2668` | Windows x86_64, Intel Core Ultra 9 285H, rustc 1.91.1 | deterministic kinematic shadow, config `ef3cf581f75124c1d45a8d6bedcef32e4d1bacb39ee0dfcd4e520171fda2d8cf` | 1 | 20,000 | 0.0080 ms | 0.0097 ms | 0.0195/0.5465 ms | not measured | **MEASURED**, local host only; not Pi 5 evidence | `cargo run --release -p wifi-densepose-physics --example latency_probe -- 20000` | +| 2026-08-15 | `de27336` + uncommitted ADR-323 changes | `552737eab9092b59ea9dd2b2caf68389f0b0966679f0fbb33ff2b1b3d42e2668` | Windows x86_64, Intel Core Ultra 9 285H, rustc 1.91.1 | deterministic kinematic shadow after final local optimization, same config | 1 | 20,000 | 0.0075 ms | 0.0084 ms | 0.0117/0.1579 ms | not measured | **MEASURED**, local host only; not Pi 5 evidence | same release probe command | +| 2026-08-15 | `de27336` + uncommitted ADR-323 changes | `552737eab9092b59ea9dd2b2caf68389f0b0966679f0fbb33ff2b1b3d42e2668` | Windows x86_64, Intel Core Ultra 9 285H, rustc 1.91.1 | final deterministic kinematic shadow, config `a44dc696234f31eda54cd4b436bc2d2c69b9638565b729ac9f07435cedfd0dcc` | 1 | 20,000 | 0.0071 ms | 0.0084 ms | 0.0147/1.5994 ms | not measured | **MEASURED**, local host only; not Pi 5 evidence | same release probe command | + +The probe measures a warm, one-track `PhysicsEngine::process` call. It excludes +transport, publication, resident-memory delta, dynamics, and learned inference. +It is not evidence for the Pi 5 gate. + +Criterion separately measured `kinematic_one_track` at +`[11.911, 12.757, 14.069] us` across 100 samples (approximately 369,000 timed +iterations). That benchmark includes observation construction and canonical +hashing in the timed routine and uses fresh engine state; it is **MEASURED** on +the same local host and is not a percentile or Pi 5 claim. + +## Accuracy measurements + +| Date | Commit | Corpus/split | Variant | Coverage | MPJPE | PCK threshold/result | Foot slide | Jerk | Fall/prone delta | Evidence | +|---|---|---|---|---:|---:|---|---:|---:|---:|---| + +No measured accuracy evidence has been recorded. The deterministic tests are +L0/SYNTHETIC contract evidence only and cannot satisfy G2. + +## Validation and supply-chain record + +- The default dependency graph is checked to exclude Burn, Rapier, Tch, and + ONNX Runtime. Dynamics and learned backends remain opt-in. +- Burn CPU serialization/inference tests pass on the authoring host only with + Cargo's `--ignore-rust-version`; the resolved CubeCL graph requires Rust 1.92. + The workspace file pins Rust 1.89 and the host provides Rust 1.91.1. This is + diagnostic, not release approval. +- `cargo audit 0.22.1` used RustSec database commit + `69f93cf294852cfa9b53751f4ca86de3283dd290` (feed timestamp 2026-08-12). + ADR-323 updates remove resolved advisories in `event-listener`, `rkyv`, and + `wasmtime`. The workspace still has five advisories in pre-existing + `quick-xml` and `rsa` dependency paths; the default physics graph contains + none of them. The optional Burn training graph includes yanked `spin 0.9.8`. +- `cargo-deny` is not installed on the authoring host, so the required license + and policy gate is not claimed complete. +- Strict Clippy passes with warnings denied for core/physics default and + dynamics builds, the diagnostic learned-CPU build, and the Cog itself with + dependency linting excluded. Focused core, physics, dynamics, learned, Cog, + sensing-server adapter/live-audit/HTTP, schema, golden, strict-split, + feature-boundary, and fuzz-build checks pass. +- The repository-wide rustfmt gate is already red across unrelated crates. The + sensing-server library has existing warning debt, and unscoped Cog Clippy is + blocked by existing `wifi-densepose-ruvector` warnings. The prescribed + `cargo test --workspace --no-default-features` did not reach a terminal result + in either a 904-second cold or 604-second warm serial run on this Windows + host. None of these broader gates is represented as green. +- The standalone fuzz lock SHA-256 is + `d386c4edb130bb6b2d1a4ef77334c78e25e0695e90a9d97c01284876acb8c2c6`. + +## Required commands + +```text +cargo bench -p wifi-densepose-physics +node scripts/pose-physics/verify-feature-boundary.mjs +bash scripts/verify-pose-physics-splits.sh +bash scripts/replay-pose-physics-golden.sh +``` diff --git a/api-docs/schemas/pose-observation-v2.schema.json b/api-docs/schemas/pose-observation-v2.schema.json new file mode 100644 index 00000000..dc470319 --- /dev/null +++ b/api-docs/schemas/pose-observation-v2.schema.json @@ -0,0 +1,38 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://ruview.net/schemas/pose-observation-v2.schema.json", + "title": "PoseObservationV2", + "type": "object", + "additionalProperties": false, + "required": ["schema_version", "timestamp_ns", "sensor_epoch", "sequence", "track_id", "frame", "calibration_id", "floor_plane", "model", "source", "trust_state", "dimensionality", "uncertainty_calibrated", "joints", "observer_confidence", "canonical_hash"], + "properties": { + "schema_version": { "const": 2 }, + "timestamp_ns": { "type": "integer", "minimum": 0 }, + "sensor_epoch": { "type": "integer", "minimum": 0 }, + "sequence": { "type": "integer", "minimum": 0 }, + "track_id": { "$ref": "#/$defs/string_id" }, + "frame": { "$ref": "#/$defs/frame" }, + "calibration_id": { "$ref": "#/$defs/string_id" }, + "floor_plane": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/floor" }] }, + "model": { "$ref": "#/$defs/model" }, + "source": { "$ref": "#/$defs/source" }, + "trust_state": { "enum": ["KNOWN", "DEGRADED", "UNKNOWN"] }, + "dimensionality": { "enum": ["image2d", "metric3d"] }, + "uncertainty_calibrated": { "type": "boolean" }, + "joints": { "type": "array", "minItems": 17, "maxItems": 17, "items": { "$ref": "#/$defs/joint" } }, + "observer_confidence": { "$ref": "#/$defs/probability" }, + "canonical_hash": { "$ref": "#/$defs/hash" } + }, + "$defs": { + "probability": { "type": "number", "minimum": 0, "maximum": 1 }, + "hash": { "type": "array", "minItems": 32, "maxItems": 32, "items": { "type": "integer", "minimum": 0, "maximum": 255 } }, + "string_id": { "type": "string", "minLength": 1, "maxLength": 128 }, + "vec3": { "type": "array", "minItems": 3, "maxItems": 3, "items": { "type": "number" } }, + "frame": { "type": "object", "additionalProperties": false, "required": ["name", "version", "metric", "right_handed", "z_up"], "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 128 }, "version": { "type": "integer", "minimum": 1 }, "metric": { "type": "boolean" }, "right_handed": { "type": "boolean" }, "z_up": { "type": "boolean" } } }, + "floor": { "type": "object", "additionalProperties": false, "required": ["normal", "offset_m"], "properties": { "normal": { "$ref": "#/$defs/vec3" }, "offset_m": { "type": "number" } } }, + "model": { "type": "object", "additionalProperties": false, "required": ["id", "artifact_hash"], "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 128 }, "artifact_hash": { "$ref": "#/$defs/hash" } } }, + "source": { "type": "object", "additionalProperties": false, "required": ["sensor_id", "authenticated", "replay_protected"], "properties": { "sensor_id": { "type": "string", "minLength": 1, "maxLength": 128 }, "authenticated": { "type": "boolean" }, "replay_protected": { "type": "boolean" } } }, + "covariance": { "type": "object", "additionalProperties": false, "required": ["xx", "xy", "xz", "yy", "yz", "zz"], "properties": { "xx": { "type": "number", "minimum": 0 }, "xy": { "type": "number" }, "xz": { "type": "number" }, "yy": { "type": "number", "minimum": 0 }, "yz": { "type": "number" }, "zz": { "type": "number", "minimum": 0 } } }, + "joint": { "type": "object", "additionalProperties": false, "required": ["kind", "position_m", "covariance_m2", "confidence", "visibility"], "properties": { "kind": { "enum": ["nose", "left_eye", "right_eye", "left_ear", "right_ear", "left_shoulder", "right_shoulder", "left_elbow", "right_elbow", "left_wrist", "right_wrist", "left_hip", "right_hip", "left_knee", "right_knee", "left_ankle", "right_ankle"] }, "position_m": { "$ref": "#/$defs/vec3" }, "covariance_m2": { "$ref": "#/$defs/covariance" }, "confidence": { "$ref": "#/$defs/probability" }, "visibility": { "enum": ["visible", "occluded", "unknown"] } } } + } +} diff --git a/api-docs/schemas/pose-refinement-v1.schema.json b/api-docs/schemas/pose-refinement-v1.schema.json new file mode 100644 index 00000000..99c94630 --- /dev/null +++ b/api-docs/schemas/pose-refinement-v1.schema.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://ruview.net/schemas/pose-refinement-v1.schema.json", + "title": "PoseRefinementV1", + "type": "object", + "additionalProperties": false, + "required": ["schema_version", "raw_observation_hash", "mode", "disposition", "selected", "refined_joints_m", "physics_confidence", "effective_confidence", "intervention", "residuals", "refined_residuals", "contact_hypotheses", "dynamics", "provenance", "reason", "canonical_hash"], + "properties": { + "schema_version": { "const": 1 }, + "raw_observation_hash": { "$ref": "#/$defs/hash" }, + "mode": { "enum": ["off", "audit", "shadow_correct", "opt_in_correct", "default_correct"] }, + "disposition": { "enum": ["bypassed", "audited2d", "audited", "shadowed", "corrected", "abstained", "rejected"] }, + "selected": { "type": "boolean" }, + "refined_joints_m": { "oneOf": [{ "type": "null" }, { "type": "array", "minItems": 17, "maxItems": 17, "items": { "$ref": "#/$defs/vec3" } }] }, + "physics_confidence": { "$ref": "#/$defs/probability" }, + "effective_confidence": { "$ref": "#/$defs/probability" }, + "intervention": { "$ref": "#/$defs/intervention" }, + "residuals": { "$ref": "#/$defs/residuals" }, + "refined_residuals": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/residuals" }] }, + "contact_hypotheses": { "type": "array", "minItems": 2, "maxItems": 2, "items": { "$ref": "#/$defs/contact" } }, + "dynamics": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/dynamics" }] }, + "provenance": { "$ref": "#/$defs/provenance" }, + "reason": { "enum": [null, "mode_off", "unsupported_schema", "hash_mismatch", "invalid_number", "invalid_covariance", "stale_input", "coordinate_frame_mismatch", "calibration_unavailable", "uncertainty_uncalibrated", "ood_unknown", "source_unauthenticated", "replay_protection_unavailable", "correction_not_authorized", "replay_rejected", "non_monotonic_input", "too_few_known_joints", "correction_too_large", "deadline_exceeded", "track_capacity", "internal_error"] }, + "canonical_hash": { "$ref": "#/$defs/hash" } + }, + "$defs": { + "probability": { "type": "number", "minimum": 0, "maximum": 1 }, + "hash": { "type": "array", "minItems": 32, "maxItems": 32, "items": { "type": "integer", "minimum": 0, "maximum": 255 } }, + "vec3": { "type": "array", "minItems": 3, "maxItems": 3, "items": { "type": "number" } }, + "intervention": { "type": "object", "additionalProperties": false, "required": ["max_joint_correction_m", "root_correction_m", "corrected_joint_count", "solver_iterations", "elapsed_us"], "properties": { "max_joint_correction_m": { "type": "number", "minimum": 0 }, "root_correction_m": { "type": "number", "minimum": 0 }, "corrected_joint_count": { "type": "integer", "minimum": 0, "maximum": 17 }, "solver_iterations": { "type": "integer", "minimum": 0, "maximum": 8 }, "elapsed_us": { "type": "integer", "minimum": 0 } } }, + "residuals": { "type": "object", "additionalProperties": false, "required": ["bone_m", "joint_limit_rad", "velocity_mps", "acceleration_mps2", "temporal_jerk", "floor_penetration_m", "contact_m", "collision_m", "normalized_total"], "properties": { "bone_m": { "type": "number", "minimum": 0 }, "joint_limit_rad": { "type": "number", "minimum": 0 }, "velocity_mps": { "type": "number", "minimum": 0 }, "acceleration_mps2": { "type": "number", "minimum": 0 }, "temporal_jerk": { "type": "number", "minimum": 0 }, "floor_penetration_m": { "type": "number", "minimum": 0 }, "contact_m": { "type": "number", "minimum": 0 }, "collision_m": { "type": "number", "minimum": 0 }, "normalized_total": { "type": "number", "minimum": 0 } } }, + "contact": { "type": "object", "additionalProperties": false, "required": ["state", "probability"], "properties": { "state": { "enum": ["hypothesis", "measured", "unknown"] }, "probability": { "$ref": "#/$defs/probability" } } }, + "dynamics": { "type": "object", "additionalProperties": false, "required": ["stable", "segment_count", "joint_count", "contact_count", "substeps", "tracking_error_m", "joint_anchor_error_m", "floor_penetration_m", "control_effort"], "properties": { "stable": { "type": "boolean" }, "segment_count": { "type": "integer", "minimum": 0, "maximum": 255 }, "joint_count": { "type": "integer", "minimum": 0, "maximum": 255 }, "contact_count": { "type": "integer", "minimum": 0, "maximum": 65535 }, "substeps": { "type": "integer", "minimum": 1, "maximum": 8 }, "tracking_error_m": { "type": "number", "minimum": 0 }, "joint_anchor_error_m": { "type": "number", "minimum": 0 }, "floor_penetration_m": { "type": "number", "minimum": 0 }, "control_effort": { "type": "number", "minimum": 0 } } }, + "provenance": { "type": "object", "additionalProperties": false, "required": ["engine", "engine_version", "config_hash", "rf_model_hash", "calibration_id", "learned_artifact_hash"], "properties": { "engine": { "type": "string", "minLength": 1, "maxLength": 128 }, "engine_version": { "type": "string", "minLength": 1, "maxLength": 64 }, "config_hash": { "$ref": "#/$defs/hash" }, "rf_model_hash": { "$ref": "#/$defs/hash" }, "calibration_id": { "type": "string", "minLength": 1, "maxLength": 128 }, "learned_artifact_hash": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/hash" }] } } } + } +}