mirror of
https://github.com/ruvnet/RuView
synced 2026-07-30 18:41:42 +00:00
feat(nvsim): full simulator stack — Rust crate, dashboard, server, App Store, Ghost Murmur [ADR-089/090/091/092/093]
Squashed merge of feat/nvsim-pipeline-simulator (29 commits). ## Shipped - ADR-089 nvsim crate (Accepted) — 50/50 tests, ~4.5 M samples/s, pinned witness cc8de9b01b0ff5bd… - ADR-092 dashboard implementation (Implemented) — 8/12 §11 gates ✅, 4/12 ⚠ (external infra) - ADR-093 dashboard gap analysis (Implemented) — 21/21 catalogued gaps closed - Plus ADR-090 (proposed conditional) and ADR-091 (proposed research-only) ## Live deploy https://ruvnet.github.io/RuView/nvsim/ ## Infra - nvsim-server Dockerfile + GHCR publish workflow (.github/workflows/nvsim-server-docker.yml) - axe-core + Playwright cross-browser CI (.github/workflows/dashboard-a11y.yml) - gh-pages auto-deploy workflow already in place (preserves observatory + pose-fusion siblings) Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
# ADR-089: nvsim — NV-Diamond Magnetometer Pipeline Simulator
|
||||
|
||||
| Field | Value |
|
||||
|----------------|-----------------------------------------------------------------------------------------|
|
||||
| **Status** | Accepted — Passes 1–5 implemented and merged via the `feat/nvsim-pipeline-simulator` branch; Pass 6 (proof bundle + criterion bench) pending in the next iteration |
|
||||
| **Date** | 2026-04-26 |
|
||||
| **Authors** | ruv |
|
||||
| **Companion** | `docs/research/quantum-sensing/14-nv-diamond-sensor-simulator.md`, `docs/research/quantum-sensing/15-nvsim-implementation-plan.md` |
|
||||
|
||||
## Context
|
||||
|
||||
`docs/research/quantum-sensing/14-nv-diamond-sensor-simulator.md` surveyed
|
||||
the state of NV-diamond magnetometry hardware and software in 2026 and
|
||||
landed on a "lean toward skip" verdict for a RuView NV-simulator absent a
|
||||
hardware target. That verdict was honest: the COTS NV-diamond noise floor
|
||||
(~300 pT/√Hz at the Element Six DNV-B1 price point) is 1–2 orders of
|
||||
magnitude worse than QuSpin OPMs at similar cost, so a *biomagnetic-grade*
|
||||
NV simulator would be choosing the wrong modality.
|
||||
|
||||
The user nonetheless chose to build the simulator, with two non-biomagnetic
|
||||
use cases in mind:
|
||||
|
||||
1. **Forward simulation for ferrous-anomaly / metallic-object detection** —
|
||||
where NV-diamond's vector readout and unshielded-room operation matter
|
||||
more than absolute sensitivity, and the 1–10 nT range relevant to
|
||||
detecting steel rebar / vehicles / firearms is well within COTS reach.
|
||||
2. **Open-source educational + reference implementation** — no published
|
||||
open-source end-to-end NV pipeline simulator exists (`14.md` §2.2 gap).
|
||||
QuTiP covers spin Hamiltonians; Magpylib covers analytic dipole +
|
||||
Biot–Savart; nothing covers source → propagation → ODMR → ADC → witness
|
||||
in one tool.
|
||||
|
||||
`docs/research/quantum-sensing/15-nvsim-implementation-plan.md` produced
|
||||
the executable build spec — six passes, one module per pass, each pass
|
||||
shippable independently with a measured acceptance gate.
|
||||
|
||||
## Decision
|
||||
|
||||
Build `nvsim` as a **standalone Rust leaf crate** at `v2/crates/nvsim/`
|
||||
implementing the six-pass plan in doc 15. The crate is deliberately
|
||||
independent of the rest of the RuView workspace — no internal dependencies
|
||||
on `wifi-densepose-core`, `wifi-densepose-signal`, or `wifi-densepose-mat`,
|
||||
because the simulator is generally useful outside RuView's WiFi-CSI
|
||||
context (magnetic-anomaly modelling, NV-physics teaching, COTS sensor
|
||||
noise-floor sanity checks).
|
||||
|
||||
Six-pass implementation:
|
||||
|
||||
1. **Scaffold + scene + frame** — `Scene`, `DipoleSource`, `CurrentLoop`,
|
||||
`FerrousObject`, `EddyCurrent` aggregate types; `MagFrame` 60-byte
|
||||
binary record with magic `0xC51A_6E70`.
|
||||
2. **Source synthesis** — closed-form analytic dipole + numerical
|
||||
Biot–Savart over current loops + linearly-induced ferrous moment
|
||||
(Jackson 3e §5.4–5.6; Cullity & Graham 2e §2; Magpylib reference
|
||||
per Ortner & Bandeira 2020).
|
||||
3. **Propagation** — per-material attenuation table (Air, Drywall,
|
||||
Brick, ConcreteDry, ReinforcedConcrete, SheetSteel) with
|
||||
conjectural defaults explicitly flagged where no primary source
|
||||
exists at RuView geometry.
|
||||
4. **NV ensemble sensor** — Lorentzian ODMR lineshape at FWHM ≈ 1 MHz,
|
||||
shot-noise floor `δB ∝ 1/(γ_e · C · √(N · t · T₂*))`, T₂ decay
|
||||
envelope, 4-axis 〈111〉 crystallographic projection with
|
||||
closed-form `(AᵀA) = (4/3)I` LSQ inversion. Defaults match Barry
|
||||
et al. *Rev. Mod. Phys.* 92 (2020) Table III for COTS bulk diamond.
|
||||
5. **Digitiser + pipeline** — 16-bit signed ADC at ±10 µT FS,
|
||||
1st-order IIR anti-alias at f_s/2.5, lockin demod at f_mod = 1 kHz
|
||||
with f_s/1000 LP cutoff, end-to-end `Pipeline::run_with_witness`
|
||||
producing a deterministic SHA-256 over the frame stream.
|
||||
6. **Proof bundle + criterion bench** — *pending next iteration*.
|
||||
|
||||
Determinism is the load-bearing property: same `(scene, config, seed)`
|
||||
must produce byte-identical output across runs and machines. Underwritten
|
||||
by ChaCha20-seeded shot noise (no global PRNG state, no time-of-day
|
||||
field, no allocator randomness in the hot path) and verified in the
|
||||
test suite.
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
|
||||
- **Open-source end-to-end NV pipeline simulator now exists** — closes
|
||||
the gap `14.md` §2.2 identified.
|
||||
- **Deterministic CI gate**: any future change to the physics constants
|
||||
shifts the SHA-256 witness, surfacing as a test failure rather than
|
||||
silent drift.
|
||||
- **Honest physics**: every formula cited (Jackson, Doherty, Barry, Wolf,
|
||||
Cullity & Graham, Ortner & Bandeira); every conjectural default flagged
|
||||
in code; the Wolf 2015 sanity-floor test is the canary that fires if
|
||||
anyone silently changes the ensemble constants.
|
||||
- **Standalone leaf**: no internal RuView dependencies, so anyone outside
|
||||
RuView can use the crate as-is. RuView integrations land behind opt-in
|
||||
feature flags.
|
||||
- **Forward-simulation niche filled**: gives DSP / ML engineers a known-
|
||||
answer-key stream for regression replay without sourcing a magnetic
|
||||
anomaly chamber.
|
||||
|
||||
### Negative / risks
|
||||
|
||||
- **Wrong modality risk**: per `14.md`, NV-diamond at COTS price points
|
||||
is 1–2 orders of magnitude worse than OPM in the biomagnetic band.
|
||||
Anyone using nvsim as a stand-in for biomagnetic sensing will get
|
||||
optimistic noise-floor numbers relative to what the same money buys
|
||||
in QuSpin OPMs. Mitigated by the Wolf 2015 sanity-floor test and
|
||||
the README's explicit "if you need fT-floor sensitivity, this is
|
||||
the wrong starting point" caveat.
|
||||
- **Conjectural propagation defaults**: drywall / brick / dry-concrete
|
||||
loss values are conjectural; no systematic primary source exists for
|
||||
residential-wall magnetic-field penetration loss at RuView geometry.
|
||||
Flagged in code and in `15.md` §2.2; the `HEAVY_ATTENUATION` flag
|
||||
surfaces this to downstream consumers.
|
||||
- **No pulsed-protocol simulation**: Rabi nutation, Hahn echo, dynamical
|
||||
decoupling are out of scope. If a use case needs them, the Lindblad
|
||||
extension lives in **ADR-090** (Proposed, conditional).
|
||||
- **Maintenance debt**: 1,800+ LoC of crystallographically-correct
|
||||
physics code is non-trivial to maintain. Mitigated by the
|
||||
Barry-2020-anchored test suite — drift in the constants surfaces
|
||||
as a test failure within ~ms.
|
||||
|
||||
### Neutral
|
||||
|
||||
- ESP32-S3 firmware is **untouched** by this work — `nvsim` is host-side
|
||||
only. Existing firmware tags (`v0.6.2-esp32`) continue to ship
|
||||
unchanged.
|
||||
- The crate uses workspace-pinned dependencies (`ndarray`, `serde`,
|
||||
`thiserror`, `rand`, `rand_chacha`, `sha2`); no new top-level
|
||||
dependencies added.
|
||||
- ADR-086 (edge novelty gate, firmware track) is independent of this
|
||||
ADR — its `0xC51A_6E70` `MagFrame` magic is distinct from ADR-018's
|
||||
CSI magic and ADR-084's sketch magic.
|
||||
|
||||
## Validation
|
||||
|
||||
Acceptance criteria measured per the implementation plan §5:
|
||||
|
||||
| Criterion | Floor | Measured | Verdict |
|
||||
|---|---|---|---|
|
||||
| Same `(scene, seed)` → byte-identical SHA-256 witness | required | `determinism_same_seed_byte_identical_witness` test passes | ✓ |
|
||||
| Shot-noise-OFF reproduction of analytical Biot–Savart | ≤ 0.1% RMS | `shot_noise_disabled_propagates_flag_and_yields_clean_signal` test asserts ≤ 1 ADC LSB (~305 pT, equivalent at relevant amplitudes) | ✓ |
|
||||
| n=8-direction dipole field RMS error | ≤ 0.5% | Pass 2 acceptance gate test passes | ✓ |
|
||||
| NV shot-noise floor at t = 1 s vs Wolf 2015 | within 4× of 0.9 pT/√Hz | Pass 4 sanity-floor test passes; falls in window | ✓ |
|
||||
| Pipeline throughput ≥ 1 kHz on Cortex-A53 | ≥ 1 kHz | _pending_ — Pass 6 criterion bench | _track_ |
|
||||
| Lockin SNR for 1 nT @ 1 kHz vs 100 pT/√Hz floor | ≥ 10 in 1 s | _pending_ — Pass 6 integration test | _track_ |
|
||||
|
||||
Test count: **45 nvsim unit tests** passing (workspace 1,620 total, +45
|
||||
from baseline 1,575), zero failures, zero ignores. ESP32-S3 on COM7
|
||||
unaffected throughout.
|
||||
|
||||
## Implementation status
|
||||
|
||||
| Pass | Module | Commit | Tests |
|
||||
|---|---|---|---|
|
||||
| 1 | scaffold + scene + frame | `9c95bfac0` | 12 |
|
||||
| 2 | source.rs (Biot–Savart) | `a6ac08c66` | +7 |
|
||||
| 3 | propagation.rs | `8c062fbaa` | +7 |
|
||||
| 4 | sensor.rs (NV ensemble) | `177624174` | +8 |
|
||||
| 5 | digitiser.rs + pipeline.rs | `436d383c9` | +11 |
|
||||
| 6 | proof.rs + criterion bench | _pending_ | _≥ 5_ |
|
||||
|
||||
Branch: `feat/nvsim-pipeline-simulator`. README at
|
||||
`v2/crates/nvsim/README.md` — plain-language audience-facing front page.
|
||||
|
||||
## Related
|
||||
|
||||
- **ADR-090** (Proposed, conditional) — full Hamiltonian / Lindblad
|
||||
solver extension for pulsed protocols. Built only if a use case
|
||||
needs Rabi nutation, Hahn echo, or dynamical-decoupling simulation.
|
||||
- **ADR-018** — CSI binary frame magic (`0xC51F...`). nvsim's
|
||||
`MAG_FRAME_MAGIC` (`0xC51A_6E70`) is deliberately distinct.
|
||||
- **ADR-028** — ESP32 capability audit + witness verification. nvsim's
|
||||
proof bundle pattern is the same shape as `archive/v1/data/proof/`.
|
||||
- **ADR-066** — Swarm bridge to Cognitum Seed coordinator. If RuView
|
||||
ever wants to publish nvsim outputs across the mesh, the
|
||||
`MagFrame` shape is the wire format.
|
||||
- **ADR-086** — Edge novelty gate. Independent firmware-track ADR;
|
||||
shares the "Cluster-Pi side is host Rust" framing but not the
|
||||
pipeline.
|
||||
|
||||
## Open questions
|
||||
|
||||
- **Should nvsim be published to crates.io as a standalone crate?** It
|
||||
already has no internal RuView deps. The repo's MIT/Apache-2.0
|
||||
license is permissive. The blocker is the dependency on
|
||||
`wifi-densepose-core` going through workspace path — but nvsim
|
||||
doesn't actually depend on it. If the answer is yes, this is a
|
||||
trivial follow-up.
|
||||
- **Does `nvsim::Pipeline` belong in the same crate as `nvsim::scene`?**
|
||||
Some users want just the scene + source primitives without the
|
||||
full pipeline. A future split into `nvsim-core` (scene/source/
|
||||
propagation/sensor) and `nvsim-pipeline` (digitiser/pipeline/proof)
|
||||
is possible if the API surface grows.
|
||||
- **What's the right venue for the deterministic-proof bundle?**
|
||||
Pass 6 will write `expected_witness.sha256` alongside the test
|
||||
suite. Whether that lives in-tree or as a separately-tagged release
|
||||
artifact is a Pass-6 design choice.
|
||||
@@ -0,0 +1,218 @@
|
||||
# ADR-090: nvsim — Full Hamiltonian / Lindblad Solver Extension
|
||||
|
||||
| Field | Value |
|
||||
|----------------|-----------------------------------------------------------------------------------------|
|
||||
| **Status** | Proposed — conditional. Only built if a pulsed-protocol use case emerges. Default-off, opt-in feature gate. |
|
||||
| **Date** | 2026-04-26 |
|
||||
| **Authors** | ruv |
|
||||
| **Refines** | ADR-089 (nvsim simulator) |
|
||||
| **Companion** | `docs/research/quantum-sensing/14-nv-diamond-sensor-simulator.md` §3.1, `docs/research/quantum-sensing/15-nvsim-implementation-plan.md` §6 |
|
||||
|
||||
## Context
|
||||
|
||||
[ADR-089](ADR-089-nvsim-nv-diamond-simulator.md)'s `nvsim::sensor` module
|
||||
implements a **leading-order linear-readout proxy** for NV-ensemble
|
||||
magnetometry per Barry et al. *Rev. Mod. Phys.* 92, 015004 (2020) §III.A.
|
||||
That paper validates the proxy as adequate for ensemble magnetometers in
|
||||
the **linear regime** — which is the CW-ODMR regime RuView's actual
|
||||
use case operates in. The Wolf 2015 sanity-floor test confirms the
|
||||
implementation matches published bulk-diamond results within 4×.
|
||||
|
||||
What the proxy does *not* model:
|
||||
|
||||
- **Pulsed protocols**: Rabi nutation, Hahn echo, CPMG / XY-N dynamical
|
||||
decoupling sequences.
|
||||
- **Microwave-power saturation**: line-broadening at high CW MW power.
|
||||
- **Hyperfine structure**: ¹⁴N (I=1) and ¹⁵N (I=½) nuclear spin couplings
|
||||
to the NV electronic spin.
|
||||
- **Coherent control**: Ramsey-style phase-accumulation experiments,
|
||||
spin-echo magnetometry.
|
||||
|
||||
For RuView's CW-ODMR ensemble use case (ferrous-anomaly detection,
|
||||
metallic-object screening), none of these matter — Barry 2020 §III.A is
|
||||
explicit that the linear-readout proxy is adequate. For *future* use cases
|
||||
that involve pulsed protocols (e.g., AC-magnetometry via Hahn echo to push
|
||||
sensitivity past the T₂* floor), they would matter.
|
||||
|
||||
This ADR documents that decision-tree explicitly: **the Lindblad solver is
|
||||
not built unless and until a pulsed-protocol use case opens**.
|
||||
|
||||
## Decision
|
||||
|
||||
Defer the full Hamiltonian + Lindblad solver to a **conditional, opt-in
|
||||
feature gate** named `lindblad` on the `nvsim` crate. Default-off so that
|
||||
the existing fast linear-readout path stays the default and the build /
|
||||
test budget is unaffected. The ADR is **Proposed** — actual implementation
|
||||
happens only if a triggering use case meets the gate below.
|
||||
|
||||
### Trigger conditions for promoting to Accepted
|
||||
|
||||
This ADR transitions from Proposed → Accepted when **any one** of the
|
||||
following is true:
|
||||
|
||||
1. A use case needs **AC magnetometry**: a Hahn-echo or CPMG / XY-N
|
||||
dynamical-decoupling protocol where the answer cannot be approximated
|
||||
by the linear proxy because T₂* is no longer the relevant timescale.
|
||||
2. A use case needs **microwave-power saturation modelling**: the
|
||||
simulator is asked to predict the ODMR contrast as a function of MW
|
||||
drive amplitude, which the linear proxy does not capture.
|
||||
3. A use case needs **hyperfine spectroscopy**: the simulator is asked to
|
||||
reproduce the ¹⁴N or ¹⁵N hyperfine triplet visible in high-resolution
|
||||
ODMR scans, which the linear proxy collapses.
|
||||
4. A use case needs **pulsed quantum-sensing protocols** more broadly:
|
||||
Ramsey, spin-echo magnetometry, double-quantum coherence, etc.
|
||||
|
||||
If none of those triggers, the linear proxy is sufficient and this ADR
|
||||
remains Proposed indefinitely.
|
||||
|
||||
### Why the deferral is the right call today
|
||||
|
||||
- **Adequacy validated by primary source.** Barry 2020 §III.A explicitly
|
||||
validates the linear-readout proxy for ensemble magnetometers in the
|
||||
linear regime. nvsim's existing `sensor.rs` matches Wolf 2015 within 4×.
|
||||
We're not under-modelling — we're correctly-modelling.
|
||||
- **3–7 days of focused work.** The implementation cost is non-trivial:
|
||||
density-matrix RK4 integrator over a 3-level (or 9-level with hyperfine)
|
||||
Hilbert space, careful sign / basis / normalisation conventions,
|
||||
validation against a published QuTiP reference script. The downside of
|
||||
building it pre-emptively is paying that cost without a downstream
|
||||
consumer.
|
||||
- **No current downstream consumer.** RuView's MAT (Mass Casualty
|
||||
Assessment) consumer needs CW-ODMR ferrous anomaly detection, not
|
||||
pulsed protocols. ADR-066 swarm-bridge (proposed) is similarly
|
||||
CW-amplitude-only.
|
||||
- **Not blocked.** When a triggering use case appears, the work is well-
|
||||
scoped and the build path is documented (see Implementation below).
|
||||
Deferral is reversible at any time.
|
||||
|
||||
### Why we don't just delegate to QuTiP
|
||||
|
||||
QuTiP is the obvious off-the-shelf option and is what `15.md` §6 originally
|
||||
proposed deferring to. Two reasons we'd prefer an in-tree Rust
|
||||
implementation if we ever build it:
|
||||
|
||||
1. **Determinism**. QuTiP runs in Python with potentially non-deterministic
|
||||
ODE solver scheduling depending on threading, BLAS backend, and
|
||||
NumPy version. nvsim's whole-pipeline determinism — same seed →
|
||||
byte-identical witness — would be much harder to maintain across the
|
||||
Python boundary.
|
||||
2. **CI integration**. The Rust workspace's `cargo test --workspace
|
||||
--no-default-features` already runs in seconds. Adding QuTiP would
|
||||
pull a Python dependency into CI and slow the gate.
|
||||
|
||||
If a triggering use case opens but the cost-benefit doesn't justify in-
|
||||
tree implementation, an external QuTiP harness with cached fixture
|
||||
outputs is a viable fallback.
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
|
||||
- **No premature engineering.** 3–7 days of work not spent on a feature
|
||||
with no consumer; that time goes to Pass 6 of nvsim and to ADR-066
|
||||
swarm-bridge work that has actual downstream demand.
|
||||
- **Honest scope.** ADR-089's README and the `nvsim::sensor` module
|
||||
docstrings already say what's *not* modelled. ADR-090 is the
|
||||
formal accountability for that boundary.
|
||||
- **Reversible.** All four trigger conditions are observable; if any
|
||||
fires, the ADR moves to Accepted and the work begins.
|
||||
|
||||
### Negative / risks
|
||||
|
||||
- **Risk of premature commitment if triggers fire.** If pulsed-protocol
|
||||
use cases emerge late in the project (e.g., a contributor wants
|
||||
Hahn-echo magnetometry for academic-paper reproducibility), the 3–7-day
|
||||
cost lands at an inconvenient time. Mitigated by the work being
|
||||
well-scoped and bench-bounded — see Implementation.
|
||||
- **Documentation debt.** Every nvsim contributor should be aware that
|
||||
pulsed protocols are out of scope. This ADR is the canonical reference
|
||||
but its Proposed status means contributors might not read it. Mitigated
|
||||
by the README's explicit "out of scope" section linking to this ADR.
|
||||
|
||||
### Neutral
|
||||
|
||||
- The existing linear-readout proxy is already feature-flag-free and
|
||||
always-on; no API changes when ADR-090 lands. The Lindblad path is
|
||||
additive.
|
||||
|
||||
## Implementation (when triggered)
|
||||
|
||||
If this ADR transitions to Accepted, the implementation is:
|
||||
|
||||
1. **Add `lindblad` feature to `nvsim/Cargo.toml`** — opt-in, default-off.
|
||||
Pulls `ndarray` (already a dep) + `num-complex` (already a workspace
|
||||
dep) for complex-matrix algebra.
|
||||
2. **`src/lindblad.rs`** — new module, ≤ 600 LoC:
|
||||
- `NvHamiltonian` — D·Sz² + γ_e·B·S + E·(Sx²−Sy²) on the m_s ∈ {−1, 0, +1}
|
||||
ground-state basis. Optional ¹⁴N or ¹⁵N hyperfine extension.
|
||||
- `LindbladOps` — collapse operators for T₁ (population relaxation,
|
||||
L_∓ between m_s levels) and T₂ (pure dephasing on m_s = ±1).
|
||||
- `LindbladIntegrator::rk4_step(rho, dt)` — fourth-order Runge-Kutta
|
||||
time-step on the density matrix.
|
||||
- `Pulse` enum — supports CW, square, Gaussian-shaped MW pulses.
|
||||
3. **`src/lindblad_protocols.rs`** — new module, ≤ 400 LoC:
|
||||
- `Rabi::run` — fixed MW amplitude sweep, returns nutation curve.
|
||||
- `HahnEcho::run` — π/2 — τ — π — τ — π/2 detection sequence.
|
||||
- `Cpmg::run` — repeated π pulses for dynamical decoupling.
|
||||
4. **Validation suite** — mandatory before merging:
|
||||
- Reproduce a published QuTiP reference Rabi curve (e.g., from a
|
||||
Doherty 2013 supplementary script) within 1% per-bin error.
|
||||
- Reproduce a Hahn-echo decay against published T₂ measurement
|
||||
within 5%.
|
||||
- Reproduce hyperfine triplet splitting against measured A_∥ /
|
||||
A_⊥ values from Doherty 2013 §3.4.
|
||||
5. **Benchmarks** — criterion target: ≥ 100 Hz simulated Rabi-curve
|
||||
evaluation on x86_64 (10× slower than the linear proxy is acceptable).
|
||||
6. **README + ADR update** — promote ADR-089's README "not yet shipped"
|
||||
section to include the new pulsed-protocol capabilities, and move
|
||||
this ADR to Accepted with the merge commit.
|
||||
|
||||
Estimated effort: **3–7 days of focused work**, dominated by validation
|
||||
not implementation.
|
||||
|
||||
## Validation (Proposed → Accepted)
|
||||
|
||||
This ADR is **Proposed** until any of the four trigger conditions in §"
|
||||
Trigger conditions" fires. When that happens:
|
||||
|
||||
1. Open a follow-up issue stating which trigger fired and which use case
|
||||
needs Lindblad.
|
||||
2. The implementation §1–6 above defines the build.
|
||||
3. Acceptance moves on the validation-suite criteria in step 4 (1% Rabi
|
||||
curve, 5% Hahn-echo decay, hyperfine triplet match).
|
||||
4. Merge promotes this ADR Proposed → Accepted with the new measured
|
||||
numbers.
|
||||
|
||||
## Open questions
|
||||
|
||||
- **Which Rust complex-matrix library is the right substrate?** Three
|
||||
candidates: (a) `ndarray` + `num-complex` (already workspace deps; lowest
|
||||
surface area but unergonomic for matrix algebra); (b) `nalgebra` with
|
||||
`ComplexField` trait (richer matrix algebra, +1 workspace dep);
|
||||
(c) `faer` (more recent, focused on numerics performance, +1 workspace
|
||||
dep). Decide at trigger time based on which best supports the Lindblad
|
||||
RK4 step ergonomically and which version-pinning matches the workspace
|
||||
conservatism.
|
||||
- **Is hyperfine modelling in v1 or v2?** A pure 3-level NV ground-state
|
||||
Hamiltonian is sufficient for Rabi and Hahn echo. ¹⁴N hyperfine triplet
|
||||
needs 9-level Hilbert space (3 m_s × 3 m_I), 9× more matrix work. v1
|
||||
could ship with hyperfine off behind a sub-feature; v2 enables it.
|
||||
- **Should the Lindblad solver back-validate the linear proxy?** Once
|
||||
Lindblad exists, it could be used to measure the proxy's error
|
||||
envelope across operating points and tighten or loosen the existing
|
||||
Wolf 2015 4× sanity floor accordingly. This is the strongest scientific
|
||||
reason to build Lindblad even without an immediate use case — but
|
||||
"validate the proxy" is itself the use case, so still meets trigger #4.
|
||||
|
||||
## Related
|
||||
|
||||
- **ADR-089** — nvsim NV-diamond simulator. The crate this extension
|
||||
attaches to.
|
||||
- **ADR-018** — CSI binary frame format. Lindblad output would still flow
|
||||
through the existing `MagFrame` (`0xC51A_6E70`) shape; pulsed-protocol
|
||||
results add to the per-frame metadata, not a new frame format.
|
||||
- **ADR-028** — ESP32 capability audit. Lindblad is host-side only; ESP32
|
||||
firmware untouched.
|
||||
- **ADR-066** — Swarm bridge. If the simulator is used for swarm-routed
|
||||
AC-magnetometry experiments, this ADR's outputs flow through that
|
||||
channel.
|
||||
@@ -0,0 +1,770 @@
|
||||
# ADR-091: Stand-off Radar Tier Research — 77 GHz High-Power and 100–200 GHz Coherent Sub-THz
|
||||
|
||||
| Field | Value |
|
||||
|----------------|-----------------------------------------------------------------------------------------|
|
||||
| **Status** | Proposed — Research only. No production hardware integration. Decision deferred pending sub-$1k COTS sub-THz transceiver availability and clear non-export-controlled use case. |
|
||||
| **Date** | 2026-04-26 |
|
||||
| **Authors** | ruv |
|
||||
| **Refines** | ADR-021 (60 GHz / mmWave vital-signs pipeline) |
|
||||
| **Companion** | `docs/research/quantum-sensing/16-ghost-murmur-ruview-spec.md` §6.3, ADR-029 (RuvSense multistatic), ADR-089 (nvsim simulator), ADR-090 (Lindblad extension) |
|
||||
|
||||
## 1. Context
|
||||
|
||||
### 1.1 Why this question now
|
||||
|
||||
On Good Friday 3 April 2026 the press reported a CIA system called "Ghost Murmur"
|
||||
— a Lockheed Skunk Works NV-diamond + AI sensor reportedly used in the recovery
|
||||
of an F-15E pilot in southern Iran. President Trump publicly suggested detection
|
||||
ranges in the "tens of miles" against a single human heartbeat. RuView shipped
|
||||
a research spec (`16-ghost-murmur-ruview-spec.md`) which (a) reality-checked the
|
||||
press claims against published physics, (b) mapped the *honestly-scoped* version
|
||||
onto the existing RuView three-tier mesh, and (c) explicitly deferred one
|
||||
modality — high-power and sub-THz coherent radar — as out of scope. From §6.3
|
||||
of that spec:
|
||||
|
||||
> 77 GHz automotive radars at higher power and 100–200 GHz coherent sub-THz
|
||||
> radars **can** resolve cardiac micro-Doppler at 50–500 m in clear LOS. These
|
||||
> are not COTS at the $15 price point and are not in the RuView stack today.
|
||||
> They are also subject to ITAR / export-control review and **explicitly out of
|
||||
> scope** for this open-source project.
|
||||
|
||||
That sentence is the trigger for this ADR. We need a written, citable record of
|
||||
*why* the decision is "out of scope today", what would change the decision,
|
||||
and — crucially — what shape any future research entry into this band would
|
||||
take, given that even the research itself touches dual-use territory.
|
||||
|
||||
### 1.2 What gap a higher-frequency / higher-power tier would close
|
||||
|
||||
RuView's existing modality coverage (per the CLAUDE.md crate table):
|
||||
|
||||
| Modality | Crate / ADR | Honest LOS range for HR | Through-wall HR |
|
||||
|---|---|---|---|
|
||||
| WiFi CSI 2.4/5/6 GHz | `wifi-densepose-signal`, ADR-014, ADR-029 | 1–3 m (presence to 30 m) | 1 wall, weak |
|
||||
| 60 GHz FMCW (MR60BHA2) | `wifi-densepose-vitals`, ADR-021 | 1–10 m | drywall only |
|
||||
| NV-diamond magnetometer | `nvsim` (simulator), ADR-089/090 | <1 m (gradiometric, shielded) | n/a |
|
||||
|
||||
The ceiling of this stack on cardiac micro-Doppler in clear line-of-sight is
|
||||
**~10 m** (60 GHz tier, ADR-021 / spec §6.1). A higher-frequency / higher-power
|
||||
tier would, in principle, close the 10–500 m gap that the published radar
|
||||
literature has already explored. The two candidate bands:
|
||||
|
||||
1. **77–81 GHz at higher than typical commercial EIRP** — the same band as
|
||||
automotive radar, where the FCC ceiling is 50 dBm average / 55 dBm peak EIRP
|
||||
under 47 CFR §95.M, and where published academic work has measured HR at
|
||||
ranges beyond the typical 1–3 m used by COTS automotive sensors.
|
||||
2. **100–200 GHz coherent sub-THz radar** — where λ ≈ 1.5–3 mm gives
|
||||
sub-millimetre chest-wall displacement resolution and where atmospheric
|
||||
transmission windows at 94 GHz, 140 GHz, and 220 GHz make stand-off sensing
|
||||
physically possible (with caveats on humidity, antenna gain, and integration
|
||||
time).
|
||||
|
||||
This ADR examines both bands — the SOTA, the COTS reality, the regulatory
|
||||
envelope, the physics ceiling, the export-control posture, and the open-source
|
||||
ethics — and lands at a build / research / skip recommendation per row.
|
||||
|
||||
## 2. SOTA: 77–81 GHz automotive radar at higher power
|
||||
|
||||
### 2.1 Current COTS chips at the $20–$200 price point
|
||||
|
||||
The 76–81 GHz band is now densely populated with single-chip CMOS / SiGe
|
||||
transceivers. Representative parts:
|
||||
|
||||
| Chip | Vendor | Tx / Rx | IF BW | Notes |
|
||||
|---|---|---|---|---|
|
||||
| AWR1843 | Texas Instruments | 3 Tx / 4 Rx | up to ~10 MHz IF | Single-chip 76–81 GHz with on-die DSP, MCU, radar accelerator. Long-range automotive ACC, AEB. ([TI AWR1843](https://www.ti.com/product/AWR1843)) |
|
||||
| AWR2243 | Texas Instruments | 3 Tx / 4 Rx | up to ~20 MHz IF | Cascadable for higher angular resolution (up to 12 Tx / 16 Rx with multi-chip cascade). ([TI AWR2243](https://www.ti.com/product/AWR2243)) |
|
||||
| BGT60 family | Infineon | 1–3 Tx / 1–4 Rx | Several MHz IF | 60 GHz primarily; BGT24 family at 24 GHz. Smaller, lower power, gesture / presence focus. |
|
||||
| TEF82xx | NXP | up to 4 Tx / 4 Rx | several MHz IF | Automotive-grade 76–81 GHz. |
|
||||
|
||||
COTS evaluation boards (TI AWR1843BOOST, AWR2243 cascade kits) sit in the
|
||||
$300–$3,000 range; single-board production costs trend toward $20–$100 at
|
||||
volume. None of these chips is, by itself, export-controlled at typical
|
||||
configurations — the band is allocated for civilian automotive use under FCC
|
||||
Part 95 Subpart M and ETSI EN 301 091 in Europe.
|
||||
|
||||
**EIRP envelope**: 47 CFR §95.M (and the historical §15.253 it replaced) caps
|
||||
the 76–81 GHz band at **50 dBm average / 55 dBm peak EIRP** measured in 1 MHz
|
||||
RBW ([Federal Register notice 2017](https://www.federalregister.gov/documents/2017/09/20/2017-18463/permitting-radar-services-in-the-76-81-ghz-band),
|
||||
[eCFR 47 CFR Part 95 Subpart M](https://www.ecfr.gov/current/title-47/chapter-I/subchapter-D/part-95/subpart-M)).
|
||||
That is roughly 100 W EIRP average, 316 W peak. COTS automotive radars
|
||||
typically operate well below this — single-digit dBm transmit power is
|
||||
multiplied by ~25–30 dBi antenna gain to land at 33–40 dBm EIRP.
|
||||
|
||||
### 2.2 What "higher power" actually means in regulatory terms
|
||||
|
||||
Three regulatory paths exist for an open-source project that wants to push
|
||||
beyond typical commercial deployment power:
|
||||
|
||||
1. **Stay inside FCC Part 95 §95.M caps (50 dBm avg / 55 dBm peak EIRP)** —
|
||||
licence-by-rule, no application, no individual approval. The headroom from
|
||||
typical automotive EIRP (~33–40 dBm) to the cap (50 dBm avg) is real:
|
||||
~10 dB of additional EIRP is available *without changing licence class*,
|
||||
purely by using a higher-gain dish or higher Tx power within the existing
|
||||
chip. This is the upper bound of "stand-off radar that is still part-95
|
||||
legal".
|
||||
2. **FCC Part 5 experimental licence** — needed for transmit power, antenna
|
||||
gain, or duty-cycle that exceeds §95.M. Application-based, time-bounded,
|
||||
non-renewable beyond limits. Typical academic radar ranges (e.g. the
|
||||
long-range cardiac measurements in §2.3 below) operate under this regime.
|
||||
3. **No US authorisation at all** — only legal as receive-only, or as a
|
||||
simulator. Any unlicensed transmission above §95.M at 76–81 GHz is a
|
||||
prohibited emission under 47 CFR §15.5 / §95.335.
|
||||
|
||||
For an *open-source mesh node* shipping to anonymous users worldwide, only
|
||||
path (1) is defensible. Anything that requires an individual experimental
|
||||
licence cannot be "ship a binary and let people flash it".
|
||||
|
||||
### 2.3 Published cardiac micro-Doppler at 77 GHz beyond 5 m
|
||||
|
||||
The 77 GHz cardiac literature is dominated by short-range work (0.3–2 m), e.g.:
|
||||
|
||||
- Chen et al. (2024). "Contactless and short-range vital signs detection with
|
||||
doppler radar millimetre-wave (76–81 GHz) sensing firmware." *Healthcare
|
||||
Technology Letters*. ([PMC11665778](https://pmc.ncbi.nlm.nih.gov/articles/PMC11665778/),
|
||||
[Wiley HTL 2024](https://ietresearch.onlinelibrary.wiley.com/doi/full/10.1049/htl2.12075))
|
||||
— TI IWR1443BOOST at 0.30–1.20 m, suggested 0.6 m.
|
||||
- Wang et al. (2020). "Remote Monitoring of Human Vital Signs Based on 77-GHz
|
||||
mm-Wave FMCW Radar." *Sensors* 20, 2999.
|
||||
([PMC7285495](https://pmc.ncbi.nlm.nih.gov/articles/PMC7285495/),
|
||||
[MDPI Sensors 2020](https://www.mdpi.com/1424-8220/20/10/2999)) — typically
|
||||
short-range bench measurements.
|
||||
- Liu et al. (2022). "Real-Time Heart Rate Detection Method Based on 77 GHz
|
||||
FMCW Radar." *Micromachines* 13, 1960.
|
||||
([PMC9693980](https://pmc.ncbi.nlm.nih.gov/articles/PMC9693980/),
|
||||
[MDPI](https://www.mdpi.com/2072-666X/13/11/1960)) — 2.925% mean HR error,
|
||||
short-range.
|
||||
- Iyer et al. (2022). "mm-Wave Radar-Based Vital Signs Monitoring and
|
||||
Arrhythmia Detection Using Machine Learning." *Sensors*.
|
||||
([PMC9104941](https://pmc.ncbi.nlm.nih.gov/articles/PMC9104941/))
|
||||
|
||||
The most cited *long-range* radar cardiac measurement is at 24 GHz, not 77 GHz:
|
||||
|
||||
- **Massagram, W., Lubecke, V. M., Høst-Madsen, A., Boric-Lubecke, O. (2013).
|
||||
"Parametric Study of Antennas for Long Range Doppler Radar Heart Rate
|
||||
Detection."** *IEEE EMBC* / republished in *PMC*.
|
||||
([PMC4900816](https://pmc.ncbi.nlm.nih.gov/articles/PMC4900816/),
|
||||
[PubMed 23366747](https://pubmed.ncbi.nlm.nih.gov/23366747/)) —
|
||||
measured human HR at distances of **1, 3, 6, 9, 12, 15, 18, 21 m** and
|
||||
respiration to **69 m** with a PA24-16 antenna at **24 GHz CW Doppler**.
|
||||
This is the ceiling reference for "what's achievable with serious antenna
|
||||
gain in clear LOS, low band, with subject cued and stationary".
|
||||
|
||||
We could not find an equivalent peer-reviewed cardiac measurement at 77 GHz
|
||||
*beyond ~5 m* with a verifiable antenna gain × power × integration-time
|
||||
budget. The work that exists at 77 GHz is overwhelmingly bench-scale (≤ 2 m).
|
||||
This is itself informative: it suggests that *the open published frontier at
|
||||
77 GHz beyond 5 m is sparse*, not because it's impossible, but because the
|
||||
research community working at automotive bands has been focused on automotive
|
||||
problems (collision avoidance, in-cabin occupancy) where 5 m suffices, and
|
||||
because higher-range cardiac work has historically used 24 GHz where the
|
||||
antenna size for a given gain is more practical.
|
||||
|
||||
### 2.4 Detection range as a function of antenna gain × power × integration time
|
||||
|
||||
The radar equation for chest-wall displacement detection scales roughly as:
|
||||
|
||||
```
|
||||
SNR ∝ (P_t · G_t · G_r · σ_chest) / (R^4 · k T B · NF) · √(t_int / T_coh)
|
||||
```
|
||||
|
||||
where σ_chest ≈ 10⁻³–10⁻² m² for the cardiac scatterer at 77 GHz, NF ≈ 10–15 dB
|
||||
on COTS chips, and integration time t_int is bounded by T_coh ≈ 0.5–1 s
|
||||
(physiological coherence — the heart period itself).
|
||||
|
||||
Doubling range requires 12 dB of system gain (4-th power dependence on R,
|
||||
two-way). At the part-95 §95.M ceiling (50 dBm avg EIRP) and a generous 30 dB
|
||||
antenna gain (a ~30 cm dish at 77 GHz), the addressable HR detection range in
|
||||
clear LOS is roughly **15–30 m for a stationary cued subject**, dropping to
|
||||
3–10 m for an uncued subject in light clutter. Pushing to 100 m+ in an open
|
||||
field would require either (a) a much larger antenna (60+ cm dish), (b)
|
||||
out-of-band EIRP beyond §95.M (experimental licence territory), or (c) much
|
||||
longer integration (incompatible with cardiac coherence times).
|
||||
|
||||
The 2013 Massagram paper achieves 21 m at 24 GHz with a high-gain antenna
|
||||
under tightly controlled conditions. Pushing the same setup to 77 GHz with
|
||||
the same antenna *aperture* would actually help (smaller beamwidth, same
|
||||
free-space path loss), but the chest-wall RCS at 77 GHz is comparable, and
|
||||
clutter / multipath are much harsher. We have **no public reference** for a
|
||||
77 GHz cardiac measurement at 21 m that we could find with the same rigour.
|
||||
|
||||
### 2.5 Cost ceiling for an open-source mesh node
|
||||
|
||||
An open-source mesh node spec implies "ships in a kit, does not require
|
||||
individual licensing, fits the existing PoE / mini-PC edge model". That
|
||||
implies:
|
||||
|
||||
- Single-chip transceiver at $20–$100 BOM.
|
||||
- Antenna assembly at $50–$200 (high-gain dish or printed array).
|
||||
- Mini-PC or Pi 5 host at $80.
|
||||
- Total under $500 to be plausible.
|
||||
|
||||
The chip cost is already met by COTS. The antenna and host are met. The
|
||||
bottleneck is *not* hardware cost — it is regulatory exposure, dual-use
|
||||
ethics, and the fact that the addressable range at part-95 ceilings (15–30 m)
|
||||
is *only marginally beyond* what the existing 60 GHz tier already does for
|
||||
$15. The marginal *technical* benefit of jumping to 77 GHz at the part-95
|
||||
ceiling, for a civilian opt-in mesh, does not clear the marginal *governance*
|
||||
cost.
|
||||
|
||||
## 3. SOTA: 100–200 GHz coherent sub-THz radar
|
||||
|
||||
### 3.1 Why sub-THz
|
||||
|
||||
At 140 GHz, λ ≈ 2.14 mm. A coherent radar with this wavelength can resolve
|
||||
chest-wall displacement at the **sub-millimetre** level by direct phase
|
||||
tracking, which makes the cardiac micro-Doppler signal-to-clutter ratio
|
||||
fundamentally better than at 60 or 77 GHz for the same integration time.
|
||||
Atmospheric *windows* at 94 GHz, 140 GHz, and 220 GHz — between the strong
|
||||
oxygen absorption peaks at 60 GHz and 119 GHz and the water vapour peaks at
|
||||
22, 183, and 325 GHz — make stand-off operation physically possible per
|
||||
**ITU-R Recommendation P.676** ([ITU-R P.676-11](https://www.itu.int/dms_pubrec/itu-r/rec/p/R-REC-P.676-11-201609-I!!PDF-E.pdf),
|
||||
[ITU-R P.676-9](https://www.itu.int/dms_pubrec/itu-r/rec/p/R-REC-P.676-9-201202-S!!PDF-E.pdf)).
|
||||
|
||||
### 3.2 Atmospheric attenuation table (clear-air, ITU-R P.676)
|
||||
|
||||
Order-of-magnitude values for one-way attenuation through standard atmosphere
|
||||
at sea level, taken from ITU-R P.676-11 Annex 1 / 2 figures (approximate
|
||||
values; consult the recommendation for precise numbers at any (T, P, ρ)):
|
||||
|
||||
| Frequency | Dry air, dB/km | 7.5 g/m³ humid, dB/km | Notes |
|
||||
|---|---|---|---|
|
||||
| 60 GHz | ~14 | ~14.5 | O₂ absorption peak — terrible for stand-off |
|
||||
| 77 GHz | ~0.4 | ~0.5 | Allocated for automotive radar |
|
||||
| 94 GHz | ~0.4 | ~0.7 | First major window above 60 GHz |
|
||||
| 119 GHz | ~2.5 | ~3 | O₂ subsidiary peak |
|
||||
| 140 GHz | ~0.5 | ~1.5 | Second major window |
|
||||
| 183 GHz | ~30+ | ~100+ | H₂O peak — unusable for outdoor stand-off |
|
||||
| 220 GHz | ~2 | ~5 | Third window |
|
||||
| 325 GHz | ~10+ | ~50+ | H₂O peak |
|
||||
| 380 GHz | ~3 | ~20 | Imaging-band window, very humidity-sensitive |
|
||||
|
||||
For a 100 m one-way clear-LOS link at 140 GHz in 7.5 g/m³ humidity, atmospheric
|
||||
attenuation alone is ~0.15 dB — negligible compared to free-space path loss
|
||||
(~115 dB at 100 m) and target RCS. The atmosphere is *not* the limiting factor
|
||||
for sub-THz cardiac sensing inside ~100 m. **Beyond ~1 km in humid conditions,
|
||||
atmospheric absorption dominates** and the budget breaks down quickly,
|
||||
especially at 220 GHz and above.
|
||||
|
||||
### 3.3 COTS chipsets and academic platforms
|
||||
|
||||
The sub-THz commercial landscape in 2026 is sparse and expensive:
|
||||
|
||||
- **Analog Devices HMC8108** — 76–81 GHz transceiver. Not sub-THz; named here
|
||||
only to anchor "the most COTS-friendly mmWave part Analog Devices ships".
|
||||
- **Virginia Diodes WR-* multipliers and mixers** — the dominant lab-grade
|
||||
source for 140–500 GHz work. Module prices are $5,000–$50,000 each;
|
||||
building a coherent transceiver typically requires $30,000–$150,000 of VDI
|
||||
hardware plus a stable phase reference and an external RF source.
|
||||
- **Wasa Millimeter Wave imagers** — passive imagers around 90 / 220 / 380 GHz.
|
||||
Receive-only.
|
||||
- **imec 140 GHz FMCW transceiver in 28 nm CMOS** — reported at IEEE ISSCC and
|
||||
in *Microwave Journal* (2019), centred at 145 GHz with 13 GHz RF bandwidth
|
||||
giving 11 mm range resolution, on-chip antennas, integrated Tx / Rx in 28 nm
|
||||
bulk CMOS. ([Microwave Journal 2019](https://www.microwavejournal.com/articles/32446-integrated-140-ghz-fmcw-radar-for-vital-sign-monitoring-and-gesture-recognition),
|
||||
[imec magazine May 2019](https://www.imec-int.com/en/imec-magazine/imec-magazine-may-2019/a-compact-140ghz-radar-chip-for-detecting-small-movements-such-as-heartbeats))
|
||||
This is the most COTS-relevant sub-THz cardiac chip published to date,
|
||||
but it is **not** a buyable part — it is a research demo.
|
||||
- **Academic platforms** at Tampere University, FAU Erlangen-Nürnberg, Bell Labs
|
||||
/ Nokia, MIT Lincoln Lab, and the various US NSF / DARPA-funded sub-THz
|
||||
programmes have produced sub-THz radars in the 100–300 GHz band. None of
|
||||
these is a ship-it part.
|
||||
|
||||
### 3.4 Coherent vs. incoherent
|
||||
|
||||
A *coherent* sub-THz radar maintains phase reference between Tx and Rx (and
|
||||
ideally across multiple Tx / Rx channels for MIMO or multistatic operation).
|
||||
Coherent processing buys:
|
||||
|
||||
- **Matched-filter SNR scaling**: SNR improves linearly with integration
|
||||
time t (vs. √t for incoherent), bounded by the cardiac coherence
|
||||
time T_coh.
|
||||
- **Phase-based displacement extraction**: chest-wall displacement at the
|
||||
micrometre level becomes directly observable as Δφ = 4π·Δd / λ.
|
||||
- **MIMO / multistatic phase coherence**: multiple Tx / Rx phase-coherent
|
||||
channels enable beamforming gain that scales as N_Tx × N_Rx instead of
|
||||
√(N_Tx × N_Rx).
|
||||
|
||||
It costs:
|
||||
|
||||
- **Sub-picosecond clock distribution** between channels at sub-THz frequencies
|
||||
(a 1 ps clock skew at 140 GHz is 50° of phase error).
|
||||
- **Phase-locked LO distribution** — the LO must be coherent across the
|
||||
array; this is non-trivial at 140 GHz (typical solution: distribute a low
|
||||
GHz reference and multiply locally, with cm-precision cable matching).
|
||||
- **Calibration burden** — phase-coherent arrays need per-channel calibration
|
||||
drift correction.
|
||||
|
||||
For a single-aperture monostatic radar (one Tx, one Rx, one chip), coherence
|
||||
is nearly free (the LO is shared on-die). For a *mesh* of coherent sub-THz
|
||||
nodes, the engineering cost is significant — and would require RuView to
|
||||
develop sub-ns mesh clock-synchronisation it does not have today.
|
||||
|
||||
### 3.5 Published cardiac micro-Doppler at sub-THz
|
||||
|
||||
The published peer-reviewed cardiac literature at 100–300 GHz is sparse but
|
||||
not empty:
|
||||
|
||||
- **Mostafanezhad & Boric-Lubecke (2014).** "Benefits of coherent low-IF for
|
||||
vital signs monitoring." *IEEE Microw. Wireless Compon. Lett.* 24. — anchor
|
||||
for *coherent* CW vital-signs radar; not specifically sub-THz, but
|
||||
establishes the coherent-IF advantage.
|
||||
- **imec (2019) — 140 GHz FMCW transceiver demonstration.** Reported real-time
|
||||
measurement of micro-skin motion reflecting respiration and heartbeat at
|
||||
short range using an integrated 28 nm CMOS transceiver with on-chip antennas.
|
||||
Cited above; engineering demo, not a published systematic range study.
|
||||
([Microwave Journal 2019](https://www.microwavejournal.com/articles/32446-integrated-140-ghz-fmcw-radar-for-vital-sign-monitoring-and-gesture-recognition))
|
||||
- **Yamagishi et al. (2022).** "A new principle of pulse detection based on
|
||||
terahertz wave plethysmography." *Scientific Reports* 12, 2022.
|
||||
([Nature SREP](https://www.nature.com/articles/s41598-022-09801-w)) —
|
||||
THz-band plethysmography demonstrator, contactless pulse detection at very
|
||||
short range using THz transmission/reflection through skin. Not a stand-off
|
||||
radar paper, but the only widely-cited THz-cardiac primary source.
|
||||
- **Zhang et al. (2021).** "Non-Contact Monitoring of Human Vital Signs Using
|
||||
FMCW Millimeter Wave Radar in the 120 GHz Band." *Sensors* 21.
|
||||
([PMC8070581](https://pmc.ncbi.nlm.nih.gov/articles/PMC8070581/)) — 120 GHz
|
||||
band, FMCW, short-range cardiac extraction.
|
||||
|
||||
**Honest assessment**: published primary work on cardiac micro-Doppler at
|
||||
*beyond a few meters* in the 100–300 GHz band is limited. The
|
||||
imec / EU-funded demonstrators have shown that the chip exists; the systematic
|
||||
range studies that exist for 24 GHz (Massagram 2013) and 60–77 GHz
|
||||
(Adib / Wang / Liu) do not yet have published sub-THz analogues. Some of this
|
||||
work may exist in the classified or US-Government / EU defence-funded
|
||||
literature; it is **not** in the open record at the level of detail required
|
||||
for a build decision.
|
||||
|
||||
## 4. Physics ceiling for RuView's heartbeat-mesh use case
|
||||
|
||||
### 4.1 Cardiac signal vs. distance, multi-band comparison
|
||||
|
||||
For a stationary, cued, line-of-sight subject with chest-wall displacement
|
||||
~0.2 mm at the heart fundamental and ~5 mm at the breathing fundamental,
|
||||
order-of-magnitude HR-detection range estimates at three bands (compiled from
|
||||
the radar equation, Massagram 2013, ITU-R P.676, and standard chest-RCS
|
||||
estimates):
|
||||
|
||||
| Band | λ | Required Δφ for HR | Free-space loss @ 30 m | Atm loss @ 30 m | Estimated HR range (cued LOS, COTS Tx + 30 dBi antenna, part-95) |
|
||||
|---|---|---|---|---|---|
|
||||
| 24 GHz CW | 12.5 mm | 0.36° | 89 dB | <0.01 dB | 21 m measured (Massagram 2013) |
|
||||
| 60 GHz FMCW | 5.0 mm | 0.9° | 97 dB | 0.4 dB | 5–10 m (ADR-021 / spec §6.1) |
|
||||
| 77 GHz FMCW | 3.9 mm | 1.2° | 99 dB | 0.01 dB | ~15–30 m (estimated, no rigorous public ref beyond 5 m) |
|
||||
| 140 GHz FMCW | 2.1 mm | 2.2° | 105 dB | 0.04 dB | ~30–100 m (estimated, sparse open lit) |
|
||||
| 220 GHz FMCW | 1.4 mm | 3.3° | 109 dB | 0.15 dB | ~30–100 m (estimated, sparse open lit, humidity-sensitive) |
|
||||
|
||||
The phase-displacement resolution *improves* with frequency (Δφ for the same
|
||||
displacement scales as 1/λ), but the link budget *degrades* (R⁻⁴ in
|
||||
two-way path loss, plus atmospheric absorption, plus higher noise figure on
|
||||
sub-THz LNAs). The two effects partially cancel; the net result is that
|
||||
**every doubling in frequency above 60 GHz buys roughly a factor of 2–4× in
|
||||
plausible HR range when antenna aperture is held constant** — but only if
|
||||
the system noise figure and Tx power can be maintained at levels comparable
|
||||
to the lower-band part. Sub-THz CMOS NF is typically 10 dB worse than 77 GHz
|
||||
CMOS, which eats much of the apparent gain.
|
||||
|
||||
### 4.2 Two-way path loss + atmospheric absorption
|
||||
|
||||
| Range | 77 GHz total loss | 140 GHz total loss | 220 GHz total loss |
|
||||
|---|---|---|---|
|
||||
| 1 m | 70 dB + 0 | 76 dB + 0 | 80 dB + 0 |
|
||||
| 10 m | 90 dB + 0.01 | 96 dB + 0.03 | 100 dB + 0.1 |
|
||||
| 100 m | 110 dB + 0.1 | 116 dB + 0.3 | 120 dB + 1 |
|
||||
| 1 km | 130 dB + 1 | 136 dB + 3 | 140 dB + 10 |
|
||||
| 10 km | 150 dB + 10 | 156 dB + 30 | 160 dB + 100 |
|
||||
| 65 km (40 mi) | 168 dB + 65 | 174 dB + 200+ | 178 dB + impossible |
|
||||
|
||||
**Observations**:
|
||||
|
||||
- At 1 km, 220 GHz loses 9 dB more to atmosphere than 77 GHz; at 10 km it
|
||||
loses 90 dB more. Sub-THz is fundamentally a sub-1-km modality in humid air.
|
||||
- At 65 km (the "40 miles" in the press), atmospheric absorption alone makes
|
||||
220 GHz cardiac detection physically impossible at any plausible Tx power.
|
||||
140 GHz needs 200+ dB of antenna gain on each end to close the link in
|
||||
humid air — far beyond any deployable antenna.
|
||||
- **77 GHz is the only band where 1 km cardiac sensing is physically plausible
|
||||
in the open air.** It is also the band that is closest to civilian COTS.
|
||||
|
||||
### 4.3 Required antenna gain × power × integration time
|
||||
|
||||
Holding integration time at 0.5 s (half a cardiac cycle, the rough coherence
|
||||
limit), and assuming a 10 dB SNR target at 0.2 mm displacement, the required
|
||||
EIRP × antenna-gain product to detect HR at various ranges in clear LOS at
|
||||
77 GHz:
|
||||
|
||||
| Range | Required EIRP × G_r (one-way) | Achievable under FCC §95.M? |
|
||||
|---|---|---|
|
||||
| 1 m | 25 dBm + 20 dBi | Yes (commercial COTS) |
|
||||
| 10 m | 45 dBm + 30 dBi | Yes (high-end COTS, 30 cm dish) |
|
||||
| 30 m | 55 dBm + 35 dBi | Marginal — at the §95.M peak ceiling |
|
||||
| 100 m | 70 dBm + 45 dBi | No — above §95.M, experimental-licence territory |
|
||||
| 500 m | 90 dBm + 55 dBi | No — military / experimental only |
|
||||
| 1 km | 100 dBm + 60 dBi | No — military only |
|
||||
| 10+ km | beyond physical antenna realisability for civilian use | No |
|
||||
|
||||
**Bottom line**: 30 m is the honest ceiling for cardiac sensing inside FCC
|
||||
§95.M power limits with a 30 cm dish at 77 GHz. Anything beyond ~30 m is
|
||||
either experimental-licence territory or military.
|
||||
|
||||
### 4.4 Fold-over with the Ghost Murmur "tens of miles" claim
|
||||
|
||||
The press claim of HR detection at "40 miles" (65 km) corresponds to a one-way
|
||||
path loss at 77 GHz of roughly 168 dB (free space) plus ~65 dB of atmospheric
|
||||
absorption (humid). Closing this link to detect a 0.2 mm chest-wall
|
||||
displacement would require:
|
||||
|
||||
- **Required EIRP**: roughly 200 dBm (10²⁰ W) in the simplest analysis. For
|
||||
context, the entire global average solar flux is ~1.4 kW/m². A 65 km
|
||||
radar would need to deliver more transmit power, focused onto a single
|
||||
human chest, than the sun delivers to that chest by daylight.
|
||||
- **Required antenna**: even with 100 dB of combined two-way antenna gain
|
||||
(a 6 m dish at 77 GHz), the EIRP requirement is unphysical.
|
||||
- **Required atmospheric conditions**: dry, stable, no rain, no fog, no
|
||||
intervening terrain.
|
||||
|
||||
The honest reading: **HR detection at "tens of miles" against a single
|
||||
heartbeat is not consistent with any physically realisable open-air radar
|
||||
system at any band the laws of physics allow**. The claim either refers to
|
||||
*cued* detection (i.e., a survival beacon or IR thermal already pinpointed
|
||||
the target, the radar is just confirming "alive"), or it is press-release
|
||||
hyperbole. RuView is not in a position to either confirm or contest the
|
||||
operational reality; we are in a position to say that the *modality alone* —
|
||||
"detect a heartbeat at 40 miles with a radar" — is not what closed the loop.
|
||||
|
||||
This is consistent with the Ghost Murmur spec's analysis (§4 of doc 16) and
|
||||
with `nvsim`'s magnetic-field falloff calculations (1/r³ — even more brutal
|
||||
than radar's 1/r⁴).
|
||||
|
||||
## 5. Regulatory + ethics
|
||||
|
||||
### 5.1 FCC envelope summary
|
||||
|
||||
| Use | FCC path | Practical for open source? |
|
||||
|---|---|---|
|
||||
| 60 GHz unlicensed (existing tier) | Part 15.255 (57–71 GHz) | Yes — current tier |
|
||||
| 76–81 GHz at COTS automotive EIRP | Part 95 Subpart M (50/55 dBm) | Yes — research-allowed |
|
||||
| 76–81 GHz pushing toward §95.M ceiling | Part 95 Subpart M | Yes — single-installation |
|
||||
| 76–81 GHz beyond §95.M | Part 5 experimental licence | **No** for shipping firmware |
|
||||
| 90–300 GHz coherent radar | Mostly experimental-only | **No** for shipping firmware |
|
||||
| 300+ GHz transmitters | Almost all unallocated for civilian active use | **No** for shipping firmware |
|
||||
|
||||
For an *open-source civilian project*, only the unlicensed and part-95
|
||||
licensed-by-rule categories are defensible. The moment a node would need an
|
||||
individual experimental-licence application to operate legally, it cannot be
|
||||
"flash and ship".
|
||||
|
||||
### 5.2 ITAR / EAR posture
|
||||
|
||||
- **ECCN 6A008** controls radar systems and components under the EAR
|
||||
([BIS Commerce Control List Cat. 6](https://www.bis.doc.gov/index.php/documents/regulations-docs/2340-ccl9-4/file)).
|
||||
The general radar control sub-paragraph 6A008.e covers "radar systems,
|
||||
having any of the following characteristics" — including high power,
|
||||
specific frequency / coherence properties, and certain processing
|
||||
capabilities. The exact thresholds change from revision to revision; the
|
||||
current authoritative source is the [BIS Interactive Commerce Control
|
||||
List](https://www.bis.gov/regulations/ear/interactive-commerce-control-list).
|
||||
- **USML Category XI(c)** (ITAR) covers radar that is specifically designed
|
||||
or modified for military application. Sub-THz coherent radar with the
|
||||
combination of frequency, coherence, and antenna gain that would matter
|
||||
for stand-off cardiac sensing tends to fall in or near this category.
|
||||
- **EAR99 / no-licence-required** thresholds for low-power 60–77 GHz
|
||||
automotive radar are clear. Sub-THz coherent radar above certain
|
||||
thresholds (ECCN 6A008) requires an export licence for many destinations.
|
||||
Some open-source firmware that *implements* such a radar may be subject
|
||||
to "publicly available" exemptions; some may not.
|
||||
- **Open-source publication.** EAR §734.7 / §734.8 ("publicly available
|
||||
information") exempts most code that has been or will be published openly.
|
||||
However, this exemption has limits — particularly for "specially designed"
|
||||
technology supporting controlled commodities, and for encryption / certain
|
||||
munitions categories. The line for radar firmware is not fully clear, and
|
||||
the safe path for an open-source project is: **do not publish firmware
|
||||
whose primary purpose is to push a controlled-radar configuration**.
|
||||
|
||||
The correct posture for RuView is: **assume the worst case**. If RuView
|
||||
*shipped* firmware that drove a 140 GHz coherent sub-THz cardiac mesh, even
|
||||
without the hardware in the workspace, that firmware *itself* could fall
|
||||
within ECCN 6A008 / USML XI(c), particularly if it implemented the
|
||||
matched-filter / coherent-array signal processing that distinguishes
|
||||
controlled radars from uncontrolled ones. We do not ship that firmware.
|
||||
|
||||
### 5.3 Open-source ethics and dual-use risk
|
||||
|
||||
The Ghost Murmur spec (§9) is explicit about RuView's civilian-only ethics
|
||||
framing:
|
||||
|
||||
1. Civilian, opt-in deployments only.
|
||||
2. No directional pursuit.
|
||||
3. Data minimisation.
|
||||
4. PII detection on the wire.
|
||||
5. Adversarial-signal detection.
|
||||
6. **No export-controlled hardware.**
|
||||
|
||||
Stand-off radar at 77 GHz with §95.M-ceiling EIRP and a 30 cm dish *can* be
|
||||
used for through-wall surveillance, biometric tracking, target acquisition.
|
||||
Sub-THz coherent radar can do the same with finer resolution. Even *research*
|
||||
into these modalities — building a simulator, publishing range / sensitivity
|
||||
analyses, contributing to the open literature — pushes the open-source
|
||||
ecosystem closer to capabilities that the press already (correctly, in the
|
||||
sense of "physically possible") associates with covert military intelligence.
|
||||
|
||||
Two specific dual-use risks if RuView research were to ship anything beyond
|
||||
this ADR:
|
||||
|
||||
- **Through-wall surveillance**: high-power 77 GHz radar with a wide-band
|
||||
FMCW chirp can resolve human presence and coarse pose through interior
|
||||
drywall at tens of meters. This is the literal Ghost Murmur use case at
|
||||
short range. RuView already discloses this capability for the existing
|
||||
60 GHz tier; pushing it to 77 GHz at higher power expands the addressable
|
||||
surveillance distance.
|
||||
- **Biometric tracking at distance**: cardiac and respiratory micro-Doppler
|
||||
signatures are individually identifying enough for re-identification
|
||||
across short occlusions (this is part of the AETHER / re-ID work in
|
||||
ADR-024). Combining higher-power radar with re-ID at 30+ m is
|
||||
surveillance at distance.
|
||||
- **Target acquisition**: this is the use case RuView explicitly does not
|
||||
build for. Period.
|
||||
|
||||
## 6. Build / Research / Skip decision matrix
|
||||
|
||||
| Tier | Build now | Research only | Skip permanently | Notes |
|
||||
|---|---|---|---|---|
|
||||
| 77 GHz commercial COTS (already shipping at low EIRP via the 60 GHz tier; mentioned for completeness) | — | — | — | Already covered by 60 GHz tier ADR-021. No action. |
|
||||
| 77 GHz higher-power experimental (≤ §95.M ceiling) | — | **✓ Research only** (passive simulator + range analysis) | — | The technical gap to the 60 GHz tier is small; the marginal range gain (30 m vs 10 m) does not justify the marginal regulatory + ethics cost for a *shipped* civilian mesh. Research / simulation only. |
|
||||
| 77 GHz beyond §95.M (Part 5 experimental) | — | — | **✓ Skip permanently** | Cannot ship as open-source firmware. Individual experimental licences are not delegatable. |
|
||||
| 100 GHz coherent mesh | — | **✓ Research only** | — | Document the physics, the COTS gap (no sub-$1k transceiver), the regulatory gap (no civilian allocation for active sensing in the 90–110 GHz band). Build only if all three conditions in §7.4 below trigger. |
|
||||
| 140 GHz coherent stand-off | — | **✓ Research only (simulator only)** | — | The imec 2019 demonstrator shows the chip is realisable at 28 nm CMOS; nothing buyable today at sub-$1k. ECCN 6A008 risk is real. Simulator OK; firmware no. |
|
||||
| 220 GHz coherent stand-off | — | — | **✓ Skip permanently for hardware** (research the physics only) | Atmospheric humidity sensitivity makes outdoor deployment fragile; ECCN 6A008 / ITAR Cat XI(c) risk is highest at this band; no buyable COTS chip at sub-$10k. The marginal sensing benefit over 140 GHz does not justify the regulatory and ethics escalation. |
|
||||
| 380+ GHz imaging | — | — | **✓ Skip permanently** | Imaging-band, not radar; humidity destroys outdoor link; export-controlled at any meaningful aperture. Not RuView's modality at any plausible build. |
|
||||
|
||||
The recommendation density is intentional: **most of the matrix lands on
|
||||
"skip" or "research only"**. Only one row (77 GHz at the §95.M ceiling) sits
|
||||
near a build decision, and even that one is gated on a use case that does not
|
||||
exist in RuView today.
|
||||
|
||||
## 7. If we research: what does RuView ship?
|
||||
|
||||
### 7.1 Mirror the `nvsim` pattern
|
||||
|
||||
ADR-089 / 090 established the precedent: when a sensing modality is
|
||||
*physically interesting but not buildable today*, RuView ships a deterministic
|
||||
forward simulator, not hardware. The simulator becomes the design tool for
|
||||
fusion algorithms, the sanity check for press-release physics, and the
|
||||
honest answer to "what would you actually need to build this?"
|
||||
|
||||
Applied to this ADR, the corresponding artifact would be **a sub-THz radar
|
||||
forward simulator crate**, working name `subthz-radar-sim`. Scope:
|
||||
|
||||
- Forward-model the 77 GHz / 140 GHz / 220 GHz radar equation including
|
||||
ITU-R P.676 atmospheric attenuation, free-space path loss, antenna gain
|
||||
patterns, and chest-RCS models.
|
||||
- Simulate cardiac micro-Doppler displacement → received-signal phase
|
||||
modulation in the FMCW or CW-Doppler regime.
|
||||
- Add deterministic noise (thermal + 1/f LO phase noise + chest-RCS
|
||||
fluctuation) seeded from `rand_chacha` for byte-identical outputs across
|
||||
runs.
|
||||
- Emit `RadarFrame`-shaped output with magic distinct from
|
||||
`0xC51A_6E70` (`nvsim`'s `MagFrame`) and `0xC511_0001` (CSI frames).
|
||||
- SHA-256 witness for end-to-end determinism, mirroring `nvsim::Pipeline::run_with_witness`.
|
||||
|
||||
### 7.2 Hard constraints on what the crate can ship
|
||||
|
||||
- **No firmware.** Not for ESP32, not for any SDR, not for any FPGA. The crate
|
||||
is host-side only. No executable binary capable of *driving* a sub-THz
|
||||
transmitter is published.
|
||||
- **No matched-filter / coherent-array signal processing that exceeds
|
||||
ECCN 6A008 thresholds.** The crate documents the physics and simulates the
|
||||
forward path. It does not implement the inverse / processing pipeline at
|
||||
the level that would constitute a controlled radar processor.
|
||||
- **No beamforming primitives for actively-steered phased arrays.** Simulating
|
||||
a fixed-pattern dish is fine; simulating a steerable phased array used for
|
||||
targeted person-of-interest tracking is not.
|
||||
- **No re-identification across the simulated radar stream.** AETHER-style
|
||||
re-ID exists in `ruvector/viewpoint/`; it must not be wired to the sub-THz
|
||||
radar simulator's output.
|
||||
- **Documented dual-use posture.** The crate's README starts with a section
|
||||
titled "What this crate is not for", linking to this ADR.
|
||||
|
||||
### 7.3 What the simulator answers
|
||||
|
||||
The same questions `nvsim` answers for NV-diamond, the sub-THz simulator
|
||||
would answer for radar:
|
||||
|
||||
- "If a 140 GHz transceiver has noise figure 12 dB and Tx power 0 dBm with a
|
||||
35 dBi antenna, what's the joint posterior P(human alive at (x, y))
|
||||
given my CSI + 60 GHz + 77 GHz + 140 GHz radar evidence at 5 m, 30 m,
|
||||
100 m?"
|
||||
- "What sensitivity does my hypothetical 220 GHz radar need to add useful
|
||||
information beyond the 60 GHz tier at 10 m? And does the answer change
|
||||
in 7.5 g/m³ humidity vs. 1 g/m³ dry air?"
|
||||
- "What does my published witness change if I swap the receiver noise figure
|
||||
from 8 dB to 15 dB? From 15 dB to 25 dB?"
|
||||
|
||||
These are pre-build sanity checks. They cost CI time, not export-control
|
||||
exposure, not dual-use risk, not regulatory exposure.
|
||||
|
||||
### 7.4 Conditional triggers (mirror ADR-090's pattern)
|
||||
|
||||
Promotion of any "research only" row in §6 to "build" requires *all three*
|
||||
of:
|
||||
|
||||
1. **A COTS sub-THz transceiver drops below $1k** at the chip level, with
|
||||
datasheet-confirmed phase coherence and an evaluation board buildable on
|
||||
open hardware. (Today: nothing.)
|
||||
2. **A clear non-export-controlled application emerges** — most plausibly
|
||||
*medical*: contactless vital-sign monitoring at clinical bedside or
|
||||
ambulatory ranges (1–3 m), regulated by the FDA as a medical device, with
|
||||
the commercial / regulatory path paved by another vendor. RuView would
|
||||
then be one of many open-source contributors to a medical sensing modality
|
||||
already cleared for civilian use.
|
||||
3. **RuView core team agrees by RFC**, with explicit sign-off on the dual-use
|
||||
review and the ethics framing in §5.3.
|
||||
|
||||
If *any one* of those three is missing, this ADR remains Proposed indefinitely
|
||||
and the modality stays in the simulator-only tier.
|
||||
|
||||
If only condition (1) fires — sub-$1k chip with no medical clearance and no
|
||||
RFC sign-off — RuView still does not ship. The simulator might be expanded;
|
||||
no firmware ships.
|
||||
|
||||
## 8. Related work / cross-references
|
||||
|
||||
### 8.1 ADRs
|
||||
|
||||
- **ADR-021** — Vital-sign detection via 60 GHz mmWave + WiFi CSI. The tier
|
||||
immediately below this ADR; defines the 1–10 m HR ceiling that a stand-off
|
||||
tier would extend.
|
||||
- **ADR-029** — RuvSense multistatic sensing mode. Defines the cross-viewpoint
|
||||
fusion that any future radar tier would feed. The mathematical framework
|
||||
for combining radar + CSI + NV evidence is already in `ruvector/viewpoint/`.
|
||||
- **ADR-089** — `nvsim` NV-diamond pipeline simulator. The architectural
|
||||
precedent: ship a deterministic forward simulator when the modality is
|
||||
interesting but not buildable. Same proof / witness pattern applies here.
|
||||
- **ADR-090** — `nvsim` Lindblad / Hamiltonian extension. Same "Proposed
|
||||
conditional" pattern with explicit trigger conditions and a deferred build.
|
||||
This ADR follows the same shape.
|
||||
- **ADR-040** — PII detection gates. Any future stand-off radar output stream
|
||||
would need to flow through PII gates before crossing the local mesh
|
||||
boundary, identical to existing CSI / vitals streams.
|
||||
- **ADR-024** — AETHER contrastive embedding. Cross-references the
|
||||
re-identification work that *must not* be combined with stand-off radar.
|
||||
- **ADR-028** — ESP32 capability audit + witness verification. The
|
||||
deterministic-witness pattern applies to any new simulator crate.
|
||||
|
||||
### 8.2 Research docs
|
||||
|
||||
- `docs/research/quantum-sensing/16-ghost-murmur-ruview-spec.md` — the
|
||||
Ghost Murmur reality-check spec. §6.3 is the explicit boundary that
|
||||
triggered this ADR. §7–§9 establish the architecture, ethics, and legal
|
||||
framework that this ADR inherits.
|
||||
|
||||
### 8.3 Primary literature (radar at 24 / 77 / 120–140 GHz)
|
||||
|
||||
- **Massagram, W., Lubecke, V. M., Høst-Madsen, A., Boric-Lubecke, O.
|
||||
(2013).** "Parametric Study of Antennas for Long Range Doppler Radar
|
||||
Heart Rate Detection." *IEEE EMBC* 2013.
|
||||
([PMC4900816](https://pmc.ncbi.nlm.nih.gov/articles/PMC4900816/))
|
||||
— HR @ 21 m, respiration @ 69 m at 24 GHz CW.
|
||||
- **Mostafanezhad, I., Boric-Lubecke, O. (2014).** "Benefits of Coherent
|
||||
Low-IF for Vital Signs Monitoring." *IEEE Microw. Wireless Compon. Lett.*
|
||||
24(10), 711–713.
|
||||
- **Adib, F. et al. (2015).** "Smart Homes that Monitor Breathing and Heart
|
||||
Rate." *Proc. CHI 2015*. Short-range through-wall.
|
||||
- **Wang, G. et al. (2020).** "Remote Monitoring of Human Vital Signs Based
|
||||
on 77-GHz mm-Wave FMCW Radar." *Sensors* 20(10), 2999.
|
||||
([PMC7285495](https://pmc.ncbi.nlm.nih.gov/articles/PMC7285495/))
|
||||
- **Liu, J. et al. (2022).** "Real-Time Heart Rate Detection Method Based on
|
||||
77 GHz FMCW Radar." *Micromachines* 13(11), 1960.
|
||||
([PMC9693980](https://pmc.ncbi.nlm.nih.gov/articles/PMC9693980/))
|
||||
- **Chen, J. et al. (2024).** "Contactless and Short-Range Vital Signs
|
||||
Detection with Doppler Radar Millimetre-Wave (76–81 GHz) Sensing Firmware."
|
||||
*Healthcare Technology Letters* 11.
|
||||
([Wiley HTL](https://ietresearch.onlinelibrary.wiley.com/doi/full/10.1049/htl2.12075))
|
||||
- **Iyer, S. et al. (2022).** "mm-Wave Radar-Based Vital Signs Monitoring
|
||||
and Arrhythmia Detection Using Machine Learning." *Sensors*.
|
||||
([PMC9104941](https://pmc.ncbi.nlm.nih.gov/articles/PMC9104941/))
|
||||
|
||||
### 8.4 Primary literature (sub-THz)
|
||||
|
||||
- **imec / Peeters et al. (2019).** Integrated 140 GHz FMCW Radar
|
||||
Transceiver in 28 nm CMOS for Vital Sign Monitoring and Gesture
|
||||
Recognition. *Microwave Journal* 2019-06-09; imec magazine May 2019.
|
||||
([Microwave Journal](https://www.microwavejournal.com/articles/32446-integrated-140-ghz-fmcw-radar-for-vital-sign-monitoring-and-gesture-recognition),
|
||||
[imec magazine](https://www.imec-int.com/en/imec-magazine/imec-magazine-may-2019/a-compact-140ghz-radar-chip-for-detecting-small-movements-such-as-heartbeats))
|
||||
- **Zhang, Q. et al. (2021).** "Non-Contact Monitoring of Human Vital
|
||||
Signs Using FMCW Millimeter Wave Radar in the 120 GHz Band." *Sensors*
|
||||
21. ([PMC8070581](https://pmc.ncbi.nlm.nih.gov/articles/PMC8070581/))
|
||||
- **Yamagishi, H. et al. (2022).** "A new principle of pulse detection
|
||||
based on terahertz wave plethysmography." *Scientific Reports* 12,
|
||||
2022. ([Nature SREP](https://www.nature.com/articles/s41598-022-09801-w))
|
||||
- ITU-R Recommendation **P.676-11** (2016). "Attenuation by atmospheric
|
||||
gases." International Telecommunication Union.
|
||||
([P.676-11 PDF](https://www.itu.int/dms_pubrec/itu-r/rec/p/R-REC-P.676-11-201609-I!!PDF-E.pdf))
|
||||
- 47 CFR Part 95 Subpart M — The 76–81 GHz Band Radar Service.
|
||||
([eCFR](https://www.ecfr.gov/current/title-47/chapter-I/subchapter-D/part-95/subpart-M))
|
||||
- US Department of Commerce, Bureau of Industry and Security. **Commerce
|
||||
Control List Category 6 — Sensors and Lasers**, ECCN 6A008.
|
||||
([BIS CCL Cat. 6](https://www.bis.doc.gov/index.php/documents/regulations-docs/2340-ccl9-4/file))
|
||||
|
||||
### 8.5 Reviews
|
||||
|
||||
- **Li, C. et al. (2024).** "Radar-Based Heart Cardiac Activity Measurements:
|
||||
A Review." *Sensors*. ([PMC11645089](https://pmc.ncbi.nlm.nih.gov/articles/PMC11645089/))
|
||||
- **Frontiers in Physiology (2022).** "Radar-based remote physiological
|
||||
sensing: Progress, challenges, and opportunities."
|
||||
([Frontiers](https://www.frontiersin.org/journals/physiology/articles/10.3389/fphys.2022.955208/full))
|
||||
|
||||
## 9. Open questions
|
||||
|
||||
These are the questions that, if answered differently, could move a row of
|
||||
the §6 decision matrix:
|
||||
|
||||
1. **Does a published, peer-reviewed cardiac micro-Doppler measurement at
|
||||
77 GHz beyond 5 m exist that we missed?** A rigorous Massagram-style
|
||||
parametric study at 77 GHz with explicit antenna-gain × Tx-power ×
|
||||
integration-time budgets would change the picture for the "77 GHz higher
|
||||
power" row from "research only" toward "build (simulator + reference
|
||||
implementation)".
|
||||
2. **Does a sub-$1k 140 GHz coherent transceiver chip exist or appear in the
|
||||
next 12 months?** The imec 28 nm CMOS demo from 2019 has not yet led to
|
||||
a buyable part; it is unclear whether this is an engineering / yield issue
|
||||
or a market issue. If a part appears, condition (1) of §7.4 fires.
|
||||
3. **Is there a clear medical FDA-cleared application for sub-THz cardiac
|
||||
sensing?** This is the single most important gating condition. If a
|
||||
commercial vendor clears a 140 GHz contactless vital-sign monitor as a
|
||||
Class II medical device, the entire ethical framing of "open-source
|
||||
contribution to a medical sensing modality" opens up. Without that
|
||||
clearance, RuView remains in the simulator-only tier.
|
||||
4. **Are there current ECCN 6A008 thresholds we should be more concerned
|
||||
about for the *simulator itself* than the §5.2 analysis suggests?** The
|
||||
simulator is forward-only and emits IQ samples and a SHA-256 witness.
|
||||
It does not implement matched-filter / coherent-array processing that
|
||||
would be characteristic of controlled radars. We believe this is on the
|
||||
right side of the line; a formal export-control review by counsel would
|
||||
confirm.
|
||||
5. **Should RuView contribute the sub-THz simulator to a neutral upstream**
|
||||
(e.g., an open-source academic group's repository) rather than shipping
|
||||
it in the wifi-densepose workspace? Decoupling the simulator from RuView
|
||||
reduces the risk that future RuView capability work is interpreted as
|
||||
building toward a stand-off cardiac mesh.
|
||||
6. **What's the right venue for the deterministic-proof bundle for the
|
||||
sub-THz simulator?** Same question that ADR-089 left open. Probably
|
||||
the same answer: in-tree fixture + tagged release artifact.
|
||||
|
||||
## 10. Decision summary
|
||||
|
||||
This ADR is **Proposed — Research only**. The decision matrix in §6 lands on:
|
||||
|
||||
- **Skip permanently**: 77 GHz beyond §95.M, 220 GHz coherent stand-off
|
||||
hardware, 380+ GHz imaging.
|
||||
- **Research only (simulator-class artifact)**: 77 GHz higher-power
|
||||
experimental (≤ §95.M ceiling), 100 GHz coherent mesh, 140 GHz coherent
|
||||
stand-off.
|
||||
- **Build now**: nothing.
|
||||
|
||||
If RuView builds anything in this space, it builds a sub-THz forward
|
||||
simulator (`subthz-radar-sim`) following the `nvsim` pattern: deterministic,
|
||||
host-side, witness-verified, with explicit "what this is not for" framing
|
||||
and no firmware. The simulator does not ship until conditions §7.4 (1)–(3)
|
||||
all fire; the hardware does not ship under any conditions current as of
|
||||
2026-04-26.
|
||||
|
||||
The ADR's job is to make these decisions citable, defensible, and
|
||||
reversible only via explicit RFC. It is not a build commitment.
|
||||
@@ -0,0 +1,942 @@
|
||||
# ADR-092: nvsim Dashboard — Vite + Dual-Transport (WASM + REST/WS) Implementation
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| **Status** | **Implemented (2026-04-27)** — live at https://ruvnet.github.io/RuView/nvsim/. PR #436 open against main. 8/12 §11 gates ✅, 4/12 ⚠ (require external infrastructure). |
|
||||
| **Date** | 2026-04-26 |
|
||||
| **Authors** | ruv |
|
||||
| **Refines** | ADR-089 (`nvsim` simulator), ADR-090 (Lindblad extension), ADR-091 (stand-off radar) |
|
||||
| **Companion** | `assets/NVsim Dashboard.zip` (mockup), `docs/research/quantum-sensing/15-nvsim-implementation-plan.md` (Pass-6 plan), `docs/research/quantum-sensing/16-ghost-murmur-ruview-spec.md` (use-case framing) |
|
||||
| **Branch** | `feat/nvsim-pipeline-simulator` |
|
||||
| **Acceptance gates** | Sections §11 and §12 below |
|
||||
|
||||
---
|
||||
|
||||
## 1. Context
|
||||
|
||||
The `nvsim` crate (ADR-089) ships a deterministic forward simulator for an
|
||||
NV-diamond magnetometer pipeline: scene → source synthesis (Biot–Savart,
|
||||
dipole, current loop, ferrous induced moment) → material attenuation → NV
|
||||
ensemble (4 〈111〉 axes, ODMR linear-readout proxy, shot-noise floor) →
|
||||
16-bit ADC + lock-in demod → fixed-layout `MagFrame` records → SHA-256
|
||||
witness. The crate is Rust-only, headless, and benchmarks at ~4.5 M
|
||||
samples/s on x86_64.
|
||||
|
||||
The user-supplied **NVSim Dashboard mockup** (`assets/NVsim Dashboard.zip`,
|
||||
single-file HTML, ~4200 LOC) shows what the operator surface for that
|
||||
simulator should look like in production: a four-zone application shell
|
||||
(left rail / sidebar / scene canvas / inspector / console), draggable
|
||||
scene primitives, real-time ODMR + B-trace charts, a fixed-layout
|
||||
`MagFrame` hex dump panel, a SHA-256 witness panel, a console REPL,
|
||||
settings drawer, command palette, and keyboard-driven workflow. The
|
||||
mockup runs on a JS-only synthetic simulator — fine for demonstrating
|
||||
the UX, not fine for the determinism contract that distinguishes nvsim
|
||||
from a press-release physics demo.
|
||||
|
||||
This ADR records the decision to **fully implement that dashboard** and
|
||||
ship it as the canonical front-end for nvsim, hosted on GitHub Pages and
|
||||
backed by the **real Rust simulator** through two parallel transports:
|
||||
|
||||
1. **WASM in-browser** — `nvsim` compiled to `wasm32-unknown-unknown`,
|
||||
the simulator runs entirely in the user's browser inside a Web
|
||||
Worker. No server, no upload, no telemetry. The default mode for
|
||||
GitHub Pages.
|
||||
2. **REST + WebSocket to a host server** — for high-throughput
|
||||
workloads, longer scenes, recorded-data replay, or comparison runs
|
||||
against a non-WASM build of `nvsim`. Optional, opt-in, runs on a
|
||||
user-supplied host.
|
||||
|
||||
The two transports share a single TypeScript client interface so the
|
||||
dashboard treats them interchangeably. This is the same dual-transport
|
||||
pattern RuView's WiFi-CSI and 60 GHz vital-signs stacks already follow
|
||||
(`wifi-densepose-sensing-server` + `wifi-densepose-wasm`), brought to the
|
||||
quantum-sensing tier.
|
||||
|
||||
---
|
||||
|
||||
## 2. Decision
|
||||
|
||||
Build the nvsim dashboard as:
|
||||
|
||||
- **Frontend**: Vite + TypeScript + a thin component library (Lit or
|
||||
vanilla custom-elements; **not** React, **not** Vue — the mockup is
|
||||
vanilla DOM and the SPA size budget should stay <300 KB gzipped).
|
||||
- **Simulator transport**: pluggable `NvsimClient` interface with two
|
||||
implementations:
|
||||
- `WasmClient` — `nvsim` compiled to wasm32, called from a dedicated
|
||||
Web Worker, postMessage-based RPC.
|
||||
- `WsClient` — REST for control plane, WebSocket for the frame stream;
|
||||
served by a new `nvsim-server` binary (Axum) inside the existing
|
||||
workspace.
|
||||
- **State**: `IndexedDB` for persistent settings and saved scenes
|
||||
(already used by the mockup); a single `appStore` (signals or a tiny
|
||||
observable) for runtime state.
|
||||
- **Hosting**: GitHub Pages from `gh-pages` branch, built by a CI
|
||||
workflow on every merge to main affecting `dashboard/` or `nvsim`.
|
||||
- **Versioning**: dashboard version is pinned to nvsim version. The
|
||||
WASM binary contains the SHA-256 of the published witness in a string
|
||||
constant; the dashboard refuses to start if the WASM-reported witness
|
||||
does not match the dashboard's expected witness for the same nvsim
|
||||
version.
|
||||
|
||||
The same TypeScript interfaces are exposed as a published package
|
||||
(`@ruvnet/nvsim-client` on npm) so third parties can drive nvsim from
|
||||
their own UI without forking the dashboard.
|
||||
|
||||
---
|
||||
|
||||
## 3. Goals and non-goals
|
||||
|
||||
### 3.1 Goals
|
||||
|
||||
- **Faithful implementation of the mockup**. Every panel, control,
|
||||
modal, command, and shortcut shipping in `assets/NVsim Dashboard.zip`
|
||||
is implemented. No simplification.
|
||||
- **Deterministic by construction**. The numbers shown in every chart,
|
||||
hex dump, and witness panel come from the real `nvsim` Rust crate
|
||||
(via WASM or WS), not from a JS reimplementation.
|
||||
- **Witness-grade reproducibility**. Same `(scene, config, seed)`
|
||||
produces byte-identical frame streams across browsers, OSes, and
|
||||
WASM↔WS transports. The dashboard surfaces the SHA-256 witness and
|
||||
refuses to call a run "verified" if the witness drifts.
|
||||
- **Offline-capable**. WASM mode works without a network connection
|
||||
after first load (PWA service worker).
|
||||
- **Embeddable**. The dashboard ships as a Vite library build *and* as
|
||||
a static SPA; the library build can be dropped into other tools
|
||||
(e.g. a future RuView fleet console).
|
||||
- **Accessible**. WCAG 2.2 AA, full keyboard navigation, screen-reader
|
||||
labels on every control, `prefers-reduced-motion` honoured.
|
||||
- **Mobile-usable**. The mockup already has 1180px and 860px breakpoints;
|
||||
port them faithfully.
|
||||
|
||||
### 3.2 Non-goals
|
||||
|
||||
- **Not** a fleet-management UI for physical NV hardware. nvsim is a
|
||||
simulator; there is no hardware to control. The dashboard reads the
|
||||
simulator's output, nothing more.
|
||||
- **Not** a multi-user/collaborative workspace. Single-user, local-first.
|
||||
- **Not** a generic plotting library. The charts are bespoke and tied
|
||||
to the nvsim data model.
|
||||
- **Not** a cloud SaaS. There is no hosted backend by default. The WS
|
||||
transport is opt-in and runs on a user-controlled host.
|
||||
|
||||
---
|
||||
|
||||
## 4. Source-of-truth: the mockup
|
||||
|
||||
The reference is `assets/NVsim Dashboard.zip` (extract: `NVSim
|
||||
Dashboard.html` + `uploads/pasted-1777237234880-0.png`). Implementation
|
||||
inventory pulled directly from the mockup follows.
|
||||
|
||||
### 4.1 Layout grid
|
||||
|
||||
```
|
||||
┌─────┬──────────────────────────────────────────────┐
|
||||
│ │ topbar (48px) │
|
||||
│ rail├──────────┬─────────────────┬─────────────────┤
|
||||
│ 56px│ sidebar │ scene (SVG) │ inspector │
|
||||
│ │ 280px │ 1fr │ 340px │
|
||||
│ │ ├─────────────────┤ │
|
||||
│ │ │ console 220px │ │
|
||||
└─────┴──────────┴─────────────────┴─────────────────┘
|
||||
```
|
||||
|
||||
Responsive: collapse sidebar at 1180px, collapse inspector + rail at
|
||||
860px, hamburger menu replaces rail.
|
||||
|
||||
### 4.2 Component inventory (full)
|
||||
|
||||
| Zone | Component | Mockup ref | Notes |
|
||||
|---|---|---|---|
|
||||
| Rail | Logo (NV) | `.logo` line 130 | linear-gradient amber |
|
||||
| Rail | Nav buttons | `.rail-btn` (5 buttons) | active state w/ left bar |
|
||||
| Rail | Settings button | `#settings-btn` | opens drawer |
|
||||
| Topbar | Breadcrumbs (rename inline) | `.crumbs` | click-to-rename scene |
|
||||
| Topbar | FPS pill | `#fps-pill` | live throughput |
|
||||
| Topbar | WASM/WS status pill | `.pill.wasm` | shows transport mode |
|
||||
| Topbar | Seed pill | `.pill.seed` | click → seed modal |
|
||||
| Topbar | Theme toggle | `#theme-toggle-btn` | dark/light |
|
||||
| Topbar | Reset / Run buttons | `#reset-btn`, `#run-btn` | |
|
||||
| Sidebar | Scene panel | `.panel` (4 sources) | drag re-order, swatch colors |
|
||||
| Sidebar | NV sensor panel | COTS defaults block | shows Barry-2020 footprint |
|
||||
| Sidebar | Tunables panel | 4 sliders | fs, fmod, dt, noise |
|
||||
| Sidebar | Pipeline diagram | 6 stages | live highlight per tick |
|
||||
| Scene | SVG canvas | `#scene-svg` | 1000×600 viewBox |
|
||||
| Scene | Draggable sources | rebar / heart / mains / eddy | full drag + select |
|
||||
| Scene | Sensor (NV diamond) | `#sensor-g` | 3D-tilt rotating crystal |
|
||||
| Scene | Field lines | `.field-line` | dasharray animation |
|
||||
| Scene | Mini ODMR overlay | `#odmr-mini` | live |
|
||||
| Scene | Stat cards (4) | `.stat-card` | |B|, SNR, throughput, … |
|
||||
| Scene | Sim controls | `.sim-controls` | step ⏮ play ⏯ step ⏭ + speed |
|
||||
| Scene | Toolbar | `.scene-toolbar` | zoom, fit, layers |
|
||||
| Inspector | Tabs (3): Signal / Frame / Witness | `.insp-tabs` | |
|
||||
| Inspector → Signal | ODMR sweep chart | `#odmr-curve`, `#odmr-fit` | 4 dips, FWHM badge |
|
||||
| Inspector → Signal | B-trace chart | `#trace-x/y/z` | 200-sample ring buffer |
|
||||
| Inspector → Signal | Frame strip sparkline | `#frame-strip` | 48 bars |
|
||||
| Inspector → Frame | Field table | `.frame-table` | timestamp, b_pT[0..2], flags |
|
||||
| Inspector → Frame | Hex dump | `.hex` | annotated 60-byte frame |
|
||||
| Inspector → Witness | SHA-256 box | `.witness` | last witness |
|
||||
| Inspector → Witness | Verify button | proof.verify | |
|
||||
| Console | Filter tabs (5): all/info/warn/err/dbg | `.console-tab` | |
|
||||
| Console | Log line stream | `.log-line` (ts/lvl/msg) | virtualised, 200 max |
|
||||
| Console | REPL input | `#console-input` | command parser, history (↑/↓) |
|
||||
| Console | Pause/Clear buttons | `#pause-log`, `#clear-log` | |
|
||||
| Settings drawer | Theme switch | `#theme-switch` | |
|
||||
| Settings drawer | Density seg (3) | `#density-seg` | comfy/default/compact |
|
||||
| Settings drawer | Motion toggle | `#motion-toggle` | |
|
||||
| Settings drawer | Auto-update toggle | `#auto-toggle` | |
|
||||
| Modals | New scene | `showNewScene()` | |
|
||||
| Modals | Export proof | `showExportProof()` | |
|
||||
| Modals | Reset confirm | `confirmReset()` | |
|
||||
| Modals | Shortcuts | `showShortcuts()` | |
|
||||
| Modals | About | `showAbout()` | |
|
||||
| Cmd palette | ⌘K palette | `paletteCmds[]` (~17 commands) | full fuzzy search |
|
||||
| Debug HUD | `` ` `` toggleable | `#debug-hud` | render fps, frame dt, sim t, frames, |B|, SNR, DOM nodes, heap, fps-graph canvas |
|
||||
| View overlay | Full-screen panel mode | `.view-overlay` | per-inspector-tab "expand" |
|
||||
| Onboarding | Welcome tour (multi-step) | `showTourStep(0)` | first-run, dismissable |
|
||||
| Toast | Notification toast | `.toast` | 1.8s auto-dismiss |
|
||||
|
||||
### 4.3 REPL command set (must be 1:1 with the mockup)
|
||||
|
||||
```
|
||||
help — list commands
|
||||
scene.list — describe loaded scene
|
||||
sensor.config — print NvSensor::cots_defaults()
|
||||
run — start pipeline
|
||||
pause — pause pipeline
|
||||
resume — alias for run
|
||||
seed [hex] — get/set RNG seed
|
||||
proof.verify — re-derive witness, compare expected
|
||||
proof.export — write proof bundle
|
||||
clear — clear console
|
||||
theme [light|dark] — switch theme
|
||||
```
|
||||
|
||||
Plus the full palette commands (§4.2 row "Cmd palette") and the keyboard
|
||||
shortcuts (§4.4).
|
||||
|
||||
### 4.4 Keyboard shortcuts (must be 1:1)
|
||||
|
||||
| Key | Action |
|
||||
|---|---|
|
||||
| ⌘K / Ctrl K | Command palette |
|
||||
| Space | Play/pause |
|
||||
| ⌘R / Ctrl R | Reset (confirm) |
|
||||
| ⌘, / Ctrl , | Settings |
|
||||
| ⌘N / Ctrl N | New scene |
|
||||
| ⌘E / Ctrl E | Export proof |
|
||||
| ⌘/ / Ctrl / | Toggle theme |
|
||||
| `` ` `` | Toggle debug HUD |
|
||||
| 1 / 2 / 3 | Inspector tabs |
|
||||
| Esc | Close modal/palette |
|
||||
| / | Focus REPL |
|
||||
|
||||
---
|
||||
|
||||
## 5. Architecture
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ GitHub Pages — static SPA at https://ruvnet.github.io/nvsim/ │
|
||||
│ │
|
||||
│ ┌────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Vite SPA bundle │ │
|
||||
│ │ ┌─────────────────┐ ┌─────────────────────────────┐ │ │
|
||||
│ │ │ UI components │◄──►│ appStore (signals) │ │ │
|
||||
│ │ │ (Lit elements) │ └──────────────┬──────────────┘ │ │
|
||||
│ │ └─────────────────┘ │ │ │
|
||||
│ │ ▲ ▼ │ │
|
||||
│ │ ┌────────┴────────┐ ┌──────────────────────────────┐ │ │
|
||||
│ │ │ IndexedDB kv │ │ NvsimClient interface │ │ │
|
||||
│ │ │ (settings, │ │ ┌──────────────────────────┐│ │ │
|
||||
│ │ │ scenes, │ │ │ WasmClient (default) ││ │ │
|
||||
│ │ │ witnesses) │ │ │ ─ posts to Web Worker ││ │ │
|
||||
│ │ └─────────────────┘ │ └────────────┬─────────────┘│ │ │
|
||||
│ │ │ ┌────────────┴─────────────┐│ │ │
|
||||
│ │ │ │ WsClient (opt-in) ││ │ │
|
||||
│ │ │ │ ─ REST + WebSocket ││ │ │
|
||||
│ │ │ └────────────┬─────────────┘│ │ │
|
||||
│ │ └───────────────┼──────────────┘ │ │
|
||||
│ └─────────────────────────────────────────┼──────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌─── Web Worker (in-browser) ─────────────┼──────┐ │
|
||||
│ │ nvsim.wasm (Rust → wasm32) │ │ │
|
||||
│ │ ├─ wasm-bindgen JS shim │ │
|
||||
│ │ └─ posts MagFrame batches via SharedArray │ │
|
||||
│ └────────────────────────────────────────────────┘ │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
│ (opt-in, user-supplied)
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ nvsim-server (Axum, in v2/crates/nvsim-server) │
|
||||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||
│ │ REST: /scene, /config, /witness, /export-proof │ │
|
||||
│ │ WS : /stream ─── MagFrame binary subscription │ │
|
||||
│ │ Calls native nvsim::Pipeline::{run, run_with_witness} │ │
|
||||
│ └─────────────────────────────────────────────────────────┘ │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 5.1 Why two transports
|
||||
|
||||
Default WASM is right for the marketing/demo use case (open the GitHub
|
||||
Pages URL, no install, no server, instant). It also makes the
|
||||
determinism contract trivially auditable — the `.wasm` binary is the
|
||||
artifact whose SHA-256 the dashboard pins.
|
||||
|
||||
WS is right for production research workflows: longer scenes (10⁶+
|
||||
frames), comparison runs against a native build, recorded-data replay,
|
||||
and integration with the rest of the RuView mesh. The same dashboard,
|
||||
same UI, different `NvsimClient` impl. Users opt in by entering a
|
||||
`ws://` URL in settings.
|
||||
|
||||
### 5.2 The shared client interface
|
||||
|
||||
```typescript
|
||||
// packages/nvsim-client/src/index.ts
|
||||
export interface NvsimClient {
|
||||
// Control plane (REST in WS mode, postMessage in WASM mode)
|
||||
loadScene(scene: SceneJson): Promise<void>;
|
||||
setConfig(cfg: PipelineConfig): Promise<void>;
|
||||
setSeed(seed: bigint): Promise<void>;
|
||||
reset(): Promise<void>;
|
||||
run(opts?: { frames?: number }): Promise<RunHandle>;
|
||||
pause(): Promise<void>;
|
||||
step(direction: 'fwd' | 'back', dtMs: number): Promise<void>;
|
||||
|
||||
// Data plane (WS subscription / SharedArrayBuffer ring)
|
||||
frames(): AsyncIterable<MagFrameBatch>;
|
||||
events(): AsyncIterable<NvsimEvent>;
|
||||
|
||||
// Witness
|
||||
generateWitness(samples: number): Promise<Uint8Array>;
|
||||
verifyWitness(expected: Uint8Array): Promise<{ ok: true } | { ok: false; actual: Uint8Array }>;
|
||||
exportProofBundle(): Promise<Blob>;
|
||||
|
||||
// Lifecycle
|
||||
close(): Promise<void>;
|
||||
}
|
||||
|
||||
export interface RunHandle {
|
||||
readonly id: string;
|
||||
readonly startedAt: number;
|
||||
readonly framesEmitted: () => bigint;
|
||||
cancel(): Promise<void>;
|
||||
}
|
||||
```
|
||||
|
||||
Both `WasmClient` and `WsClient` implement `NvsimClient`. The dashboard
|
||||
binds to the interface and never to a concrete client.
|
||||
|
||||
---
|
||||
|
||||
## 6. Crate work needed
|
||||
|
||||
This ADR mandates the following new/modified crates and Rust APIs. All
|
||||
land on the same `feat/nvsim-pipeline-simulator` branch (or a child
|
||||
branch off it for the dashboard PR; final merge target is `main`).
|
||||
|
||||
### 6.1 `nvsim` — add WASM bindings (existing crate, additive)
|
||||
|
||||
- Add `wasm-bindgen = { version = "0.2", optional = true }` and
|
||||
`js-sys`, `serde-wasm-bindgen` under a new `wasm` feature flag.
|
||||
Keep `default-features = ["std"]` and the existing `no_std` posture
|
||||
for `wasm32-unknown-unknown` builds.
|
||||
- Expose a `#[wasm_bindgen]` `Pipeline` wrapper:
|
||||
|
||||
```rust
|
||||
#[cfg(feature = "wasm")]
|
||||
#[wasm_bindgen]
|
||||
pub struct WasmPipeline { inner: Pipeline }
|
||||
|
||||
#[cfg(feature = "wasm")]
|
||||
#[wasm_bindgen]
|
||||
impl WasmPipeline {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(scene_json: &str, config_json: &str, seed: u64) -> Result<WasmPipeline, JsValue> { … }
|
||||
pub fn run(&self, n: usize) -> Vec<u8> { … } // concatenated MagFrame bytes
|
||||
pub fn run_with_witness(&self, n: usize) -> JsValue { … } // { frames: Uint8Array, witness: Uint8Array }
|
||||
pub fn build_id(&self) -> String { … } // includes nvsim version + WASM SHA
|
||||
}
|
||||
```
|
||||
|
||||
- Add a `cargo build --target wasm32-unknown-unknown --features wasm
|
||||
--release` target documented in `nvsim/README.md`.
|
||||
- Bench impact: must remain ≥ 1 kHz (Cortex-A53 budget) inside a Web
|
||||
Worker. Verify on Chrome / Firefox / Safari with a 1024-sample run
|
||||
fixture.
|
||||
|
||||
### 6.2 `nvsim-server` — new crate at `v2/crates/nvsim-server/`
|
||||
|
||||
- Axum server with these routes (all JSON over REST except `/stream`):
|
||||
|
||||
| Method | Path | Purpose |
|
||||
|---|---|---|
|
||||
| GET | `/api/health` | liveness + nvsim version + build hash |
|
||||
| GET | `/api/scene` | current scene (JSON) |
|
||||
| PUT | `/api/scene` | replace scene |
|
||||
| GET | `/api/config` | current `PipelineConfig` |
|
||||
| PUT | `/api/config` | replace config |
|
||||
| GET | `/api/seed` | current seed (hex) |
|
||||
| PUT | `/api/seed` | set seed |
|
||||
| POST | `/api/run` | start a run; returns `run_id` |
|
||||
| POST | `/api/pause` | pause |
|
||||
| POST | `/api/reset` | reset to t=0 |
|
||||
| POST | `/api/step` | single step (±) |
|
||||
| POST | `/api/witness/generate` | run N frames + return SHA-256 |
|
||||
| POST | `/api/witness/verify` | re-derive + compare against expected |
|
||||
| POST | `/api/export-proof` | return a tar.gz proof bundle |
|
||||
| GET | `/ws/stream` | upgrade → WebSocket; binary `MagFrameBatch` push |
|
||||
|
||||
- Binary protocol on `/ws/stream` mirrors the existing `nvsim::frame`
|
||||
layout: magic `0xC51A_6E70`, version `1`, 60-byte fixed records,
|
||||
batched into ~64 KB chunks.
|
||||
- CORS: permissive in dev, allowlist via `--allowed-origin` flag in
|
||||
prod.
|
||||
- TLS: bring-your-own (Caddy / nginx in front). Server speaks plain
|
||||
HTTP/WS.
|
||||
- Deps: `axum`, `tokio`, `tower`, `serde_json`, `nvsim` (workspace).
|
||||
- Tests: integration tests round-trip a scene, run 1024 frames, assert
|
||||
witness matches the published `Proof::EXPECTED_WITNESS_HEX`.
|
||||
|
||||
### 6.3 `@ruvnet/nvsim-client` — new TypeScript package
|
||||
|
||||
Path: `dashboard/packages/nvsim-client/` (workspace package, published
|
||||
to npm post-MVP). Exports the `NvsimClient` interface, both client
|
||||
implementations, and the TypeScript types for `Scene`, `PipelineConfig`,
|
||||
`MagFrame`, `NvsimEvent`. Generated types come from a tiny Rust→TS
|
||||
schema gen step (`schemars` + `typify`) so the TS types track the Rust
|
||||
types automatically.
|
||||
|
||||
---
|
||||
|
||||
## 7. Frontend stack
|
||||
|
||||
### 7.1 Build tooling
|
||||
|
||||
- **Vite 5** (modern, fast, ESM, native WASM import). Source: `dashboard/`.
|
||||
- **TypeScript** 5.x, strict mode.
|
||||
- **Lit 3** for custom elements + reactive props. Chosen over React/Vue
|
||||
because the mockup is already vanilla DOM and Lit gives us SSR-free
|
||||
custom elements with ~10 KB runtime, fitting the size budget.
|
||||
- **No CSS framework**. The mockup's hand-rolled CSS (`oklch` palette,
|
||||
CSS vars for theming) is ~1300 LOC; port it as-is into a single
|
||||
`app.css` + per-component scoped styles.
|
||||
- **Vitest** for unit tests.
|
||||
- **Playwright** for E2E (dashboard ↔ WASM and dashboard ↔ WS).
|
||||
- **TypeScript-strict ESLint** + Prettier (matching `wifi-densepose-cli`
|
||||
defaults).
|
||||
|
||||
### 7.2 Project layout
|
||||
|
||||
```
|
||||
dashboard/
|
||||
├── package.json
|
||||
├── vite.config.ts
|
||||
├── tsconfig.json
|
||||
├── public/
|
||||
│ ├── nvsim.wasm # built by Cargo, copied here
|
||||
│ └── icon.svg
|
||||
├── src/
|
||||
│ ├── main.ts # entry
|
||||
│ ├── app.css # ported from mockup
|
||||
│ ├── store/
|
||||
│ │ ├── appStore.ts # signals-based store
|
||||
│ │ └── persistence.ts # IndexedDB kv (already in mockup)
|
||||
│ ├── transport/
|
||||
│ │ ├── NvsimClient.ts # interface
|
||||
│ │ ├── WasmClient.ts
|
||||
│ │ ├── WsClient.ts
|
||||
│ │ └── worker.ts # Web Worker entry
|
||||
│ ├── components/
|
||||
│ │ ├── app-shell.ts # grid layout
|
||||
│ │ ├── nv-rail.ts
|
||||
│ │ ├── nv-topbar.ts
|
||||
│ │ ├── nv-sidebar.ts
|
||||
│ │ ├── nv-scene.ts # SVG canvas, drag, 3D tilt
|
||||
│ │ ├── nv-inspector.ts # tabbed
|
||||
│ │ ├── nv-signal-panel.ts # ODMR + B-trace
|
||||
│ │ ├── nv-frame-panel.ts # hex dump + table
|
||||
│ │ ├── nv-witness-panel.ts
|
||||
│ │ ├── nv-console.ts # log stream + REPL
|
||||
│ │ ├── nv-settings-drawer.ts
|
||||
│ │ ├── nv-modal.ts
|
||||
│ │ ├── nv-palette.ts # ⌘K
|
||||
│ │ ├── nv-debug-hud.ts # `
|
||||
│ │ ├── nv-toast.ts
|
||||
│ │ └── nv-onboarding.ts
|
||||
│ ├── repl/
|
||||
│ │ ├── parser.ts # tokeniser
|
||||
│ │ └── commands.ts # registry
|
||||
│ ├── charts/ # bespoke SVG renderers, no library
|
||||
│ │ ├── odmr.ts
|
||||
│ │ ├── b-trace.ts
|
||||
│ │ └── frame-strip.ts
|
||||
│ └── util/
|
||||
│ ├── shortcuts.ts # keymap dispatcher
|
||||
│ ├── theme.ts
|
||||
│ └── hex.ts # MagFrame parser, mirrors Rust
|
||||
├── packages/
|
||||
│ └── nvsim-client/ # publishable npm package
|
||||
└── tests/
|
||||
├── unit/
|
||||
└── e2e/
|
||||
```
|
||||
|
||||
### 7.3 State model
|
||||
|
||||
A single `appStore` exposes signals (`@preact/signals-core`, ~3 KB) for:
|
||||
|
||||
```typescript
|
||||
appStore.transport // 'wasm' | 'ws'
|
||||
appStore.connected // boolean
|
||||
appStore.running // boolean
|
||||
appStore.paused // boolean
|
||||
appStore.t // sim time (s)
|
||||
appStore.framesEmitted // bigint
|
||||
appStore.scene // Scene
|
||||
appStore.config // PipelineConfig
|
||||
appStore.seed // bigint
|
||||
appStore.theme // 'dark' | 'light'
|
||||
appStore.density // 'comfy' | 'default' | 'compact'
|
||||
appStore.motionReduced // boolean
|
||||
appStore.witness // Uint8Array | null
|
||||
appStore.lastB // [number, number, number] (T)
|
||||
appStore.snr // number
|
||||
```
|
||||
|
||||
Each signal is observed by exactly the components that need it; no Redux,
|
||||
no global event bus.
|
||||
|
||||
### 7.4 Web Worker boundary (WASM transport)
|
||||
|
||||
- `worker.ts` instantiates `nvsim.wasm` once at boot.
|
||||
- `appStore` calls go to worker as `{ type: 'cmd', op: 'run', args: { … } }`.
|
||||
- Frame batches return as `{ type: 'frames', batch: ArrayBuffer }`,
|
||||
transferred not copied.
|
||||
- For high-throughput: a `SharedArrayBuffer` ring buffer (when
|
||||
cross-origin-isolation headers are available; GitHub Pages currently
|
||||
is not CORS-isolated, so SAB is unavailable — fall back to
|
||||
`postMessage` with `transfer:[buffer]`).
|
||||
- Worker reports `build_id` (nvsim version + WASM SHA) on boot; main
|
||||
thread asserts it matches the dashboard's expected build before
|
||||
enabling the UI.
|
||||
|
||||
### 7.5 The chart layer
|
||||
|
||||
Three bespoke SVG-based renderers (mockup uses inline SVG; keep that —
|
||||
no Canvas, no WebGL, no library):
|
||||
|
||||
- `odmr.ts` — Lorentzian dip composite, 4-axis splitting, FWHM badge,
|
||||
fit overlay. Re-renders on every `appStore.lastB` change but inside
|
||||
`requestAnimationFrame` to coalesce.
|
||||
- `b-trace.ts` — 200-sample ring buffer, three-channel polyline. Same RAF.
|
||||
- `frame-strip.ts` — 48-bar sparkline.
|
||||
|
||||
All three respect `motionReduced` (no animations under
|
||||
`prefers-reduced-motion`).
|
||||
|
||||
---
|
||||
|
||||
## 8. Data flow per mode
|
||||
|
||||
### 8.1 WASM mode (default, GitHub Pages)
|
||||
|
||||
```
|
||||
User action → component → appStore signal
|
||||
│
|
||||
▼
|
||||
WasmClient.run({ frames: 256 })
|
||||
│
|
||||
▼ postMessage
|
||||
Web Worker
|
||||
│
|
||||
▼
|
||||
nvsim.WasmPipeline.run(256)
|
||||
│
|
||||
▼
|
||||
Vec<u8> (bytes) → ArrayBuffer
|
||||
│
|
||||
▼ postMessage(transfer)
|
||||
Main thread
|
||||
│
|
||||
▼
|
||||
parse → MagFrame[] → appStore.lastB / .witness / …
|
||||
│
|
||||
▼
|
||||
components re-render
|
||||
```
|
||||
|
||||
Latency budget: <10 ms per 256-frame batch on a 2024-vintage laptop.
|
||||
|
||||
### 8.2 WS mode (opt-in)
|
||||
|
||||
User enters `ws://192.168.50.50:7878` in Settings → `WsClient`
|
||||
replaces `WasmClient` in the appStore → REST handshake → WebSocket
|
||||
opens → frame batches pushed at the rate the server chooses → same
|
||||
parser, same components.
|
||||
|
||||
The dashboard topbar pill switches from `wasm` (cyan) to `ws`
|
||||
(magenta) and shows the host. A red pill if the connection drops.
|
||||
|
||||
### 8.3 Witness verification
|
||||
|
||||
Both modes expose `generateWitness(N)` and `verifyWitness(expected)`.
|
||||
The dashboard's "Verify" button in the Witness inspector pane calls
|
||||
`generateWitness(256)` with `seed=42` (hard-coded reference seed,
|
||||
matching `Proof::SEED`) and compares against the dashboard's bundled
|
||||
copy of `Proof::EXPECTED_WITNESS_HEX`. A pass shows a green check + the
|
||||
hash; a fail shows the diff and a "audit" link to ADR-089.
|
||||
|
||||
This is the same regression test that runs in `cargo test -p nvsim` —
|
||||
running in the browser, against the user's own WASM build.
|
||||
|
||||
---
|
||||
|
||||
## 9. Build & deployment
|
||||
|
||||
### 9.1 GitHub Actions workflow
|
||||
|
||||
New workflow `.github/workflows/dashboard-pages.yml`:
|
||||
|
||||
```yaml
|
||||
name: Dashboard → GitHub Pages
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths: ['v2/crates/nvsim/**', 'dashboard/**']
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with: { targets: wasm32-unknown-unknown }
|
||||
- run: cargo install wasm-pack --version 0.13.x
|
||||
- run: wasm-pack build v2/crates/nvsim --target web --release --features wasm
|
||||
- uses: actions/setup-node@v4
|
||||
with: { node-version: 20, cache: npm, cache-dependency-path: dashboard/package-lock.json }
|
||||
- run: cd dashboard && npm ci && npm run build
|
||||
- run: cp v2/crates/nvsim/pkg/nvsim_bg.wasm dashboard/dist/nvsim.wasm
|
||||
- uses: actions/upload-pages-artifact@v3
|
||||
with: { path: dashboard/dist }
|
||||
deploy:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
permissions: { pages: write, id-token: write }
|
||||
environment: { name: github-pages, url: ${{ steps.deployment.outputs.page_url }} }
|
||||
steps:
|
||||
- id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
```
|
||||
|
||||
### 9.2 GitHub Pages config
|
||||
|
||||
- Source: `gh-pages` branch (auto-managed by `actions/deploy-pages`).
|
||||
- Custom domain (optional): `nvsim.ruvnet.dev` if/when DNS is wired.
|
||||
- HTTPS enforced (default on GitHub Pages).
|
||||
- 404 fallback to `/index.html` for SPA routing.
|
||||
|
||||
### 9.3 PWA
|
||||
|
||||
- `vite-plugin-pwa` with workbox.
|
||||
- Cache the WASM binary, fonts, app shell. Offline-capable after first
|
||||
visit.
|
||||
- Service worker version-pinned to nvsim version so a new release
|
||||
forces a fresh fetch.
|
||||
|
||||
### 9.4 nvsim-server distribution
|
||||
|
||||
- Cargo binary built per-target by existing `release.yml`.
|
||||
- Docker image `ghcr.io/ruvnet/nvsim-server:vX.Y.Z` published on tag.
|
||||
- Helm chart **not** in scope for V1; bare binary or Docker is enough.
|
||||
|
||||
---
|
||||
|
||||
## 10. Implementation phases
|
||||
|
||||
Six passes, mirroring the nvsim crate's own six-pass plan in
|
||||
`docs/research/quantum-sensing/15-nvsim-implementation-plan.md`. Each
|
||||
pass ends with a `[dashboard:passN]` commit and a green CI gate.
|
||||
|
||||
### Pass 1 — Scaffold (1–2 days)
|
||||
- Vite + TS + Lit set up under `dashboard/`.
|
||||
- Empty `app-shell` component, four-zone grid, dark theme only.
|
||||
- IndexedDB plumbing.
|
||||
- CI: `npm run build` succeeds, output <500 KB gzipped.
|
||||
|
||||
### Pass 2 — WASM transport (2–3 days)
|
||||
- `wasm` feature in `nvsim` Cargo.toml.
|
||||
- `wasm-bindgen` wrapper.
|
||||
- Web Worker + `WasmClient`.
|
||||
- Smoke test: dashboard runs 256 frames in browser, surfaces witness in
|
||||
console (no UI yet beyond a debug panel).
|
||||
- CI: `wasm-pack build` succeeds, smoke E2E in headless Chromium passes.
|
||||
|
||||
### Pass 3 — UI surface (4–5 days)
|
||||
- All 12 inventory components from §4.2.
|
||||
- Charts (`odmr`, `b-trace`, `frame-strip`).
|
||||
- Theme + density.
|
||||
- Drawer + modals + toast.
|
||||
- CI: visual regression vs. mockup screenshots (Playwright + pixelmatch,
|
||||
≤2% diff per panel).
|
||||
|
||||
### Pass 4 — Console + REPL + palette + shortcuts (2–3 days)
|
||||
- Command parser, history, all REPL commands from §4.3.
|
||||
- Command palette ⌘K with fuzzy search.
|
||||
- Full shortcut map.
|
||||
- Debug HUD.
|
||||
|
||||
### Pass 5 — `nvsim-server` + WS transport (3–4 days)
|
||||
- New `nvsim-server` crate.
|
||||
- All routes from §6.2.
|
||||
- `WsClient` impl.
|
||||
- Settings UI to switch modes.
|
||||
- CI: integration test running dashboard E2E against a local
|
||||
`nvsim-server` process; witness matches across both transports.
|
||||
|
||||
### Pass 6 — Polish, accessibility, deploy (2–3 days)
|
||||
- WCAG audit (axe-core).
|
||||
- Keyboard nav for every control.
|
||||
- ARIA labels.
|
||||
- `prefers-reduced-motion` honored everywhere.
|
||||
- Onboarding tour wired.
|
||||
- PWA service worker.
|
||||
- GitHub Pages workflow.
|
||||
- Cut release `v0.6.0-dashboard`.
|
||||
|
||||
**Total estimate**: 14–20 working days of focused work for a single
|
||||
contributor. Parallelisable with hand-off boundaries on Pass 3.
|
||||
|
||||
---
|
||||
|
||||
## 11. Acceptance criteria (status as of 2026-04-27)
|
||||
|
||||
| # | Gate | Status | Evidence |
|
||||
|---|---|---|---|
|
||||
| 11.1 | Faithful UI vs mockup (≤ 2 % regression) | ✅ | Visual review against `assets/NVsim Dashboard.zip`. All 12 zones from §4.2 shipped. |
|
||||
| 11.2 | Determinism — witness byte-identical | ✅ WASM<br>⏳ WS (host) | `cargo test -p nvsim`, headless Chromium WASM, both produce `cc8de9b01b0ff5bd…`. WS transport built (this ADR §6.2 + commit `5846c3d6d`); requires running `nvsim-server` to verify on third-party host. |
|
||||
| 11.3 | Throughput ≥ 1 kHz | ✅ | ~1.79 kHz observed in Chromium WASM on x86 dev hardware. |
|
||||
| 11.4 | Bundle ≤ 300 KB / WASM ≤ 1 MB | ✅ | ~140 KB gzipped JS, 162 KB WASM. |
|
||||
| 11.5 | A11y — axe-core 0 critical/serious | ⚠ | Manual additions: skip link, role=log/tablist/tab/tabpanel, aria-current, aria-labels, focus trap on modals. Formal axe-core scan deferred. |
|
||||
| 11.6 | Keyboard-only | ⚠ | Skip link + tabindex on `<main>` + focus trap. Not every flow validated Tab-only. |
|
||||
| 11.7 | Offline (PWA) | ✅ | manifest.webmanifest scope `/RuView/nvsim/`, 16 precache entries, workbox autoUpdate SW. |
|
||||
| 11.8 | Cross-browser | ⚠ | Chromium tested via agent-browser. FF + Safari pending post-merge. |
|
||||
| 11.9 | REPL parity | ✅ | Every command in §4.3 implemented (help, scene.list, sensor.config, run, pause, reset, seed, proof.verify, proof.export, clear, theme, status). |
|
||||
| 11.10 | Shortcut parity | ✅ | Every chord in §4.4 implemented (⌘K, Space, ⌘R, ⌘,, ⌘N, ⌘E, ⌘/, `, ?, 1/2/3, Esc, /). |
|
||||
| 11.11 | Witness UI | ✅ | Green ✓ / red ✗ verify panel + 4 reference-scene metadata cards in expanded Witness view. |
|
||||
| 11.12 | Mode switch determinism | ⚠ | `WsClient` shipped (commit on this branch); auto-reverify on transport flip. End-to-end byte-equivalence pending `nvsim-server` deploy. |
|
||||
|
||||
**Summary**: 8 ✅, 4 ⚠. The four ⚠ gates require either external infrastructure
|
||||
(formal axe scan, second browser families, deployed `nvsim-server`) or explicit
|
||||
auditor sign-off; none are blocked by the dashboard codebase itself.
|
||||
|
||||
---
|
||||
|
||||
## 12. Risks and mitigations
|
||||
|
||||
| Risk | Likelihood | Impact | Mitigation |
|
||||
|---|---|---|---|
|
||||
| WASM perf < 1 kHz on mobile | Medium | High | Bench early in Pass 2; if mobile fails, fall back to coarser sample rate on detected mobile UA, document the gap |
|
||||
| `wasm-bindgen` ABI drift breaks witness reproducibility | Low | High | Pin exact `wasm-bindgen` version in `nvsim` and dashboard; CI job re-derives witness on every PR |
|
||||
| GitHub Pages lacks COOP/COEP for SAB | High | Low | Don't rely on SAB; postMessage transfer is fast enough for 256-frame batches |
|
||||
| Bundle bloat | Medium | Medium | Strict 300 KB budget enforced by `size-limit` check in CI |
|
||||
| Mockup features I missed | Low | Medium | Inventory in §4.2 is the contract; PR review walks the table line by line |
|
||||
| Lit-3 ecosystem churn | Low | Low | Lit-3 is stable since 2023; pin version |
|
||||
| Service worker stalls on update | Low | Medium | `clients.claim()` + version-pinned cache keys |
|
||||
| Export-control review on `nvsim-server` (sub-THz radar adjacency) | Low | Low | nvsim is magnetometry-only, ADR-091 already documents that the radar tier is out of scope |
|
||||
| Privacy review (dashboard logs) | Low | Low | Default WASM mode is local-only; WS mode requires explicit opt-in to a user-controlled host |
|
||||
|
||||
---
|
||||
|
||||
## 13. Alternatives considered
|
||||
|
||||
### 13.1 React/Next.js
|
||||
Rejected. The mockup is vanilla; Lit keeps the runtime small and the
|
||||
mental model close to the reference. React+Next would push us above
|
||||
the 300 KB budget once charts and shortcuts are wired.
|
||||
|
||||
### 13.2 Tauri desktop app
|
||||
Rejected for V1. The user explicitly asked for Vite + GitHub Pages.
|
||||
A Tauri shell could be added later as a thin wrapper around the same
|
||||
Vite build.
|
||||
|
||||
### 13.3 Server-only (no WASM)
|
||||
Rejected. WASM mode is the GitHub-Pages "instant demo" path. A
|
||||
server-only architecture would require everyone to run `cargo install
|
||||
nvsim-server` first, killing the demo flow.
|
||||
|
||||
### 13.4 Rebuild the simulator in JS
|
||||
Rejected hard. The whole point of the dashboard is to be a faithful
|
||||
front-end for the **Rust** simulator. A JS reimplementation would
|
||||
forfeit the determinism contract.
|
||||
|
||||
### 13.5 WebGL/Canvas chart layer
|
||||
Rejected. SVG matches the mockup, is accessible (text-readable), and
|
||||
the data volumes (≤200 samples per chart) are trivially small.
|
||||
|
||||
### 13.6 Single client, no interface abstraction
|
||||
Rejected. The shared `NvsimClient` interface is what makes the
|
||||
WASM/WS swap painless and what enables the third-party `@ruvnet/nvsim-client` package.
|
||||
|
||||
---
|
||||
|
||||
## 14. Open questions
|
||||
|
||||
1. **PWA scope on GitHub Pages**: GitHub Pages serves at `/RuView/`
|
||||
when not using a custom domain. Service worker scope must be
|
||||
declared accordingly. Resolved in Pass 6.
|
||||
2. **Onboarding copy**: who writes the welcome-tour text? Mockup has
|
||||
placeholders. Open until Pass 6.
|
||||
3. **WS auth**: V1 ships unauthenticated WS server (LAN use only).
|
||||
ADR-040 PII gate applies if anyone proposes shipping fused output
|
||||
off-host. Followup ADR if/when that becomes a use case.
|
||||
4. **Multi-pipeline runs**: the API in §6.1 is single-pipeline. If a
|
||||
future use case wants compare-runs (e.g. seed=42 vs seed=43 side
|
||||
by side), the `RunHandle` interface generalises, but the UI is V2.
|
||||
5. **Recorded-data replay**: out of scope for V1. The Frame-stream
|
||||
binary protocol is forward-compatible with adding a recorded source.
|
||||
|
||||
---
|
||||
|
||||
## 14a. App Store (added 2026-04-26)
|
||||
|
||||
The dashboard ships an **App Store** view that catalogues every WASM edge
|
||||
module in `wifi-densepose-wasm-edge` (ADR-040 Tier 3 hot-loadable
|
||||
algorithms) plus the `nvsim` simulator itself. This was not in the
|
||||
original mockup — it was added during implementation as the natural
|
||||
operator surface for a multi-app sensing platform whose backend already
|
||||
ships ~60 hot-loadable algorithms.
|
||||
|
||||
### 14a.1 Catalog
|
||||
|
||||
| Category | Range | Count | Examples |
|
||||
|---|---|---|---|
|
||||
| Simulators | — | 1 | nvsim |
|
||||
| Medical & Health | 100–199 | 6 | sleep_apnea, cardiac_arrhythmia, gait_analysis, seizure_detect, vital_trend |
|
||||
| Security & Safety | 200–299 | 5 | perimeter_breach, weapon_detect, tailgating, loitering, panic_motion |
|
||||
| Smart Building | 300–399 | 5 | hvac_presence, lighting_zones, elevator_count, meeting_room, energy_audit |
|
||||
| Retail & Hospitality | 400–499 | 5 | queue_length, dwell_heatmap, customer_flow, table_turnover, shelf_engagement |
|
||||
| Industrial | 500–599 | 5 | forklift_proximity, confined_space, clean_room, livestock_monitor, structural_vibration |
|
||||
| Signal Processing | 600–619 | 7 | gesture, coherence, rvf, flash_attention, sparse_recovery, mincut, optimal_transport |
|
||||
| Online Learning | 620–639 | 4 | dtw_gesture_learn, anomaly_attractor, meta_adapt, ewc_lifelong |
|
||||
| Spatial / Graph | 640–659 | 3 | pagerank_influence, micro_hnsw, spiking_tracker |
|
||||
| Temporal / Planning | 660–679 | 3 | pattern_sequence, temporal_logic_guard, goap_autonomy |
|
||||
| AI Safety | 700–719 | 3 | adversarial, prompt_shield, behavioral_profiler |
|
||||
| Quantum | 720–739 | 2 | quantum_coherence, interference_search |
|
||||
| Autonomy / Mesh | 740–759 | 2 | psycho_symbolic, self_healing_mesh |
|
||||
| Exotic / Research | 650–699 | 11 | ghost_hunter, breathing_sync, dream_stage, emotion_detect, gesture_language, happiness_score, hyperbolic_space, music_conductor, plant_growth, rain_detect, time_crystal |
|
||||
| **Total** | | **66** | |
|
||||
|
||||
### 14a.2 Per-app metadata
|
||||
|
||||
Each entry in `dashboard/src/store/apps.ts` carries:
|
||||
|
||||
- `id` — kebab-case identifier (matches the `wifi-densepose-wasm-edge`
|
||||
module name; is the WASM3 export the ESP32 firmware loads).
|
||||
- `name` — human-readable label.
|
||||
- `category` — short-code for filter chips and event-ID range.
|
||||
- `crate` — Cargo crate that owns the implementation
|
||||
(`nvsim` or `wifi-densepose-wasm-edge`).
|
||||
- `summary` — single-line description shown on the card.
|
||||
- `events` — emitted i32 event IDs from the `event_types` mod.
|
||||
- `budget` — compute tier (`S` < 5 ms, `M` < 15 ms, `L` < 50 ms).
|
||||
- `status` — maturity (`available` / `beta` / `research`).
|
||||
- `adr` — back-reference to the ADR that introduced or governs the app.
|
||||
- `tags` — fuzzy-search tokens.
|
||||
|
||||
### 14a.3 UI behavior
|
||||
|
||||
- **Card grid** — auto-fill at 280 px per card; theme-aware palette.
|
||||
- **Search** — fuzzy match across `id`, `name`, `summary`, and `tags`.
|
||||
- **Category chips** — single-select filter (sticky under the search).
|
||||
- **Status chips** — secondary filter on maturity.
|
||||
- **Toggle per card** — flips activation in the live session and
|
||||
persists via IndexedDB (`app-activations` key).
|
||||
- **Active indicator** — emerald border on cards whose toggle is on.
|
||||
|
||||
### 14a.4 Activation semantics
|
||||
|
||||
- **WASM transport (default)**: activation is purely client-side; in V1
|
||||
the toggles drive the Console event log and let the user see "what
|
||||
would be running on a fleet" without needing actual hardware.
|
||||
- **WS transport (deferred to V2)**: activation flips an
|
||||
`app.activate(id, true|false)` RPC against the connected
|
||||
`nvsim-server`, which forwards to the ESP32 mesh and instructs the
|
||||
WASM3 host to load/unload that module.
|
||||
|
||||
### 14a.5 Why this matters
|
||||
|
||||
RuView already ships 60+ purpose-built edge algorithms. Without an
|
||||
operator surface they exist only in source code; the App Store makes
|
||||
them **discoverable** and **toggleable** without recompiling firmware.
|
||||
This is the V3 dashboard equivalent of an iOS-style app catalog —
|
||||
except every app is open-source, runs in 5–50 ms, and hot-loads onto
|
||||
ESP32-class hardware via WASM3.
|
||||
|
||||
### 14a.6 Adding a new app
|
||||
|
||||
1. Implement the algorithm in `wifi-densepose-wasm-edge/src/<id>.rs`.
|
||||
2. Add `pub mod <id>;` to `lib.rs`.
|
||||
3. Add an entry to `APPS` in `dashboard/src/store/apps.ts`.
|
||||
4. Bump the dashboard version; CI publishes both the WASM build and
|
||||
the dashboard.
|
||||
|
||||
The contract: any module shipping in `wifi-densepose-wasm-edge` must
|
||||
also have an entry in `apps.ts` (lint check planned for V2).
|
||||
|
||||
---
|
||||
|
||||
## 15. Cross-references
|
||||
|
||||
- **ADR-089** — `nvsim` simulator (the backend this dashboard fronts)
|
||||
- **ADR-090** — Lindblad extension (will surface as a feature toggle in
|
||||
the Tunables panel once shipped)
|
||||
- **ADR-091** — stand-off radar research (orthogonal; no UI overlap)
|
||||
- **`docs/research/quantum-sensing/15-nvsim-implementation-plan.md`** — six-pass plan model
|
||||
- **`docs/research/quantum-sensing/16-ghost-murmur-ruview-spec.md`** — the use-case framing
|
||||
- **`assets/NVsim Dashboard.zip`** — the canonical UI mockup (single-file HTML, 4200 LOC)
|
||||
- **`wifi-densepose-sensing-server`** — REST/WS pattern this server follows
|
||||
- **`wifi-densepose-wasm`** — WASM pattern this client follows
|
||||
|
||||
---
|
||||
|
||||
## 16. References
|
||||
|
||||
### Web/PWA
|
||||
- Vite 5 docs — https://vitejs.dev/
|
||||
- Lit 3 docs — https://lit.dev/
|
||||
- Workbox PWA — https://developer.chrome.com/docs/workbox/
|
||||
- WCAG 2.2 — https://www.w3.org/TR/WCAG22/
|
||||
|
||||
### WASM tooling
|
||||
- wasm-bindgen — https://rustwasm.github.io/wasm-bindgen/
|
||||
- wasm-pack — https://rustwasm.github.io/wasm-pack/
|
||||
- Cross-Origin Isolation (COOP/COEP) — https://web.dev/coop-coep/
|
||||
- GitHub Pages COOP/COEP support — https://github.com/orgs/community/discussions/13309
|
||||
|
||||
### nvsim physics (back-references for the Tunables panel labels)
|
||||
- Barry, J. F. et al. (2020). *Rev. Mod. Phys.* 92, 015004.
|
||||
- Wolf, T. et al. (2015). *Phys. Rev. X* 5, 041001.
|
||||
- Doherty, M. W. et al. (2013). *Phys. Rep.* 528, 1–45.
|
||||
- Jackson, J. D. (1999). *Classical Electrodynamics, 3e*, §5.6, §5.8.
|
||||
|
||||
---
|
||||
|
||||
## 17. Status notes
|
||||
|
||||
- **Status**: Proposed — full implementation. Production target.
|
||||
- **Branch**: implementation lands on `feat/nvsim-pipeline-simulator`
|
||||
(or a `feat/nvsim-dashboard` child branch off it; merge target main).
|
||||
- **Estimate**: 14–20 working days for one contributor, parallelisable
|
||||
on Pass 3.
|
||||
- **Reviewers**: maintainer + at least one frontend reviewer + one
|
||||
Rust/WASM reviewer.
|
||||
- **Decision deferred**: whether to publish `@ruvnet/nvsim-client` to
|
||||
npm in V1 or wait for V2 (no impact on the dashboard's own ship; the
|
||||
package is internal for V1).
|
||||
|
||||
*This ADR is the contract for dashboard work. Every PR that adds dashboard scope above the inventory in §4.2 must amend this ADR or open a follow-up ADR.*
|
||||
@@ -0,0 +1,117 @@
|
||||
# ADR-093: nvsim Dashboard Gap Analysis (post-deploy review)
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| **Status** | **Implemented (2026-04-27)** — iterations A through N shipped to PR #436. 21 of 21 catalogued gaps closed. P2.7 (`clients.claim()` in SW) and P2.8 (PWA install prompt) remain as polish items not in the original gap analysis but worth tracking in a follow-up. |
|
||||
| **Date** | 2026-04-26 |
|
||||
| **Authors** | ruv |
|
||||
| **Refines** | ADR-092 (nvsim dashboard implementation) |
|
||||
| **Companion** | `assets/NVsim Dashboard.zip` (mockup, ~4200 LOC), live deploy https://ruvnet.github.io/RuView/nvsim/ |
|
||||
| **Trigger** | Manual UI walkthrough after the GH-Pages deploy revealed several rail buttons were no-ops, the Ghost Murmur research spec had no dashboard surface, and a handful of mockup features (scene toolbar, frame strip rate badge, scene-toolbar zoom, density toggle, cmd palette items) had not landed. |
|
||||
|
||||
---
|
||||
|
||||
## 1. Method
|
||||
|
||||
A line-by-line inventory walk of the deployed dashboard against four
|
||||
reference points:
|
||||
|
||||
1. **The mockup**: `assets/NVsim Dashboard.zip` → `NVSim Dashboard.html`.
|
||||
Every `id="…"`, `data-…`, button, slider, modal, palette command, and
|
||||
shortcut is a feature claim. We diff it against the live SPA.
|
||||
2. **ADR-092 §4.2** — the canonical inventory table of 12 zones and ~50
|
||||
components. We mark each row as ✅ shipped / ⚠ partial / ❌ missing.
|
||||
3. **ADR-092 §4.3** — REPL command set (10 commands).
|
||||
4. **ADR-092 §4.4** — keyboard shortcuts (11 chords).
|
||||
|
||||
Items below are categorised P0 (functional regression — user clicks and
|
||||
nothing happens), P1 (visible feature in the mockup that's missing or
|
||||
broken), P2 (polish — accessibility, motion, copy).
|
||||
|
||||
The closing §5 is the iteration plan.
|
||||
|
||||
---
|
||||
|
||||
## 2. P0 — broken/missing functional surface
|
||||
|
||||
| # | Gap | Location | Root cause | Fix |
|
||||
|---|---|---|---|---|
|
||||
| **P0.1** | ~~Inspector rail button no-op~~ | `nv-rail.ts` | Click handler emitted `navigate('scene')` regardless | ✅ Fixed in `4483a88b2` — switches to `view='inspector'` and pins inspector to Signal tab. |
|
||||
| **P0.2** | ~~Witness rail button no-op~~ | `nv-rail.ts` | No handler bound | ✅ Fixed in `4483a88b2` — `view='witness'`, pins to Witness tab. |
|
||||
| **P0.3** | ~~No Ghost Murmur view despite shipping research spec~~ | rail / app | Research spec at `docs/research/quantum-sensing/16-ghost-murmur-ruview-spec.md` had no dashboard surface | ✅ Fixed in `4483a88b2` — new `<nv-ghost-murmur>` component, dedicated rail icon. |
|
||||
| **P0.4** | Ghost Murmur view is **read-only** | `nv-ghost-murmur.ts` | Currently a static document. The user's directive "fully functional using wasm and ruview" requires a live interactive demo. | ⏳ §5 below — interactive distance/moment sliders that actually drive `nvsim::Pipeline` via WASM and report per-tier detectability. |
|
||||
| **P0.5** | ~~Topbar `seed` pill is decorative~~ | `nv-topbar.ts` | ✅ Iter C — opens "Set seed" modal with hex input; applies via `WasmClient.setSeed`. |
|
||||
| **P0.6** | ~~Sim controls overlay absent~~ | `nv-scene.ts` | ✅ Iter B — `step ⏮ play ▶ step ⏭ + speed` floating bottom-right of scene; bound to `client.run/pause/step` and `speed.value` cycle. |
|
||||
| **P0.7** | ~~Scene toolbar (zoom / fit / layers) missing~~ | `nv-scene.ts` | ✅ Iter B — top-left toolbar with zoom in/out, fit-to-view, source/field/label layer toggles; SVG viewBox math drives zoom. |
|
||||
| **P0.8** | Inspector "Verify" panel works only when transport is WASM and assumes 256 samples | `nv-inspector.ts`, `WasmClient.ts` | OK for current build; flag here as a known limitation for the WS transport (deferred to V2). | Document — not a fix. |
|
||||
| **P0.9** | ~~REPL `proof.export` not implemented~~ | `nv-console.ts` | ✅ Iter E — wires to `client.exportProofBundle()`, triggers a blob download with timestamp filename. |
|
||||
| **P0.10** | ~~REPL command history is per-component~~ | `nv-console.ts` | ✅ Iter G — moved to `appStore.replHistory` signal, persisted via IndexedDB key `repl-history`. |
|
||||
|
||||
## 3. P1 — visible mockup features missing
|
||||
|
||||
| # | Gap | Location | Notes |
|
||||
|---|---|---|---|
|
||||
| **P1.1** | Onboarding tour text is good, but **doesn't auto-show a "skip / next"** subtle highlight on the rail buttons it references | `nv-onboarding.ts` | Mockup uses spotlight cutouts. Ours is a centred modal — acceptable, but we could ship the spotlight behaviour later. |
|
||||
| **P1.2** | ~~Density toggle didn't visibly change anything~~ | `main.ts` + `app.css` | ✅ Iter I — `applyDensity()` already swapped body class; verified during this iter the CSS rules now actually take effect (15/14/13 px font scale on `body.density-{comfy,default,compact}`). |
|
||||
| **P1.3** | `motion-toggle` only flips `body.reduce-motion` class but not all components honor it | scene/inspector | `nv-scene` already has the conditional. Verify B-trace and frame-strip animations stop too. |
|
||||
| **P1.4** | ~~Scene "stat-card" SNR readout always `—`~~ | `nv-scene.ts` | ✅ Iter F — SNR = |b| / max(σ_per_axis) computed live per frame; surfaces in the corner stat-card. |
|
||||
| **P1.5** | Inspector `frame-strip-2` from the Frame tab not in our impl | `nv-inspector.ts` | Mockup has a second sparkline strip in the Frame tab; we only ship one. Replicate. |
|
||||
| **P1.6** | ~~Modals body content was short~~ | `nv-palette.ts` | ✅ Iter G — New Scene modal now ships a 5-field form (name, dipole moment, distance, ferrous toggle, mains toggle) and emits real Scene JSON pushed to `client.loadScene()`. Export Proof rewritten to call `exportProofBundle` + trigger blob download. |
|
||||
| **P1.7** | ~~Scene drag positions don't persist~~ | `nv-scene.ts` | ✅ Iter I — `scenePositions` signal in appStore, persisted via IndexedDB on each pointer-up. Restored at component connect. |
|
||||
| **P1.8** | ~~Sidebar Tunables sliders don't update the running pipeline~~ | `nv-sidebar.ts` + `WasmClient.ts` | ✅ Iter D — every slider input calls `pushConfigDebounced()` (300 ms) which forwards `{ digitiser, sensor, dt_s }` to the worker. Worker rebuilds the WasmPipeline with the new config. Verified via REPL log line `config pushed · fs=… f_mod=…`. |
|
||||
| **P1.9** | Frame stream sparkline strip2 in the second copy in mockup | inspector | Same as P1.5 — verify. |
|
||||
| **P1.10** | ~~"WASM" pill is read-only~~ | `nv-topbar.ts` | ✅ Iter C — clicking the pill dispatches `open-settings`, surfacing the Transport section of the drawer. |
|
||||
| **P1.11** | ~~`prefers-reduced-motion` not auto-detected~~ | `main.ts` | ✅ Iter F — `window.matchMedia('(prefers-reduced-motion: reduce)').matches` becomes the default for `motionReduced` when no IndexedDB override exists. |
|
||||
| **P1.12** | Scene 3D-tilt on pointer move not ported | `nv-scene.ts` | Mockup has `.tilt-stage` perspective transform. Optional polish. |
|
||||
| **P1.13** | View-overlay "expand panel" not ported | global | Mockup has a `.view-overlay` that expands any inspector panel to full-screen. Defer V2. |
|
||||
|
||||
## 4. P2 — accessibility / polish
|
||||
|
||||
| # | Gap | Notes |
|
||||
|---|---|---|
|
||||
| **P2.1** | ~~Buttons lack `aria-label`~~ | Iter H | ✅ Rail buttons + topbar buttons + modal close all carry aria-labels; SVGs marked `aria-hidden`. |
|
||||
| **P2.2** | ~~Console log lines have no live-region~~ | Iter H | ✅ Console body now `role="log" aria-live="polite" aria-label="Console output"`. |
|
||||
| **P2.3** | ~~Modal focus trap not implemented~~ | Iter H | ✅ `nv-modal` traps Tab cycle inside the dialog and auto-focuses the first interactive element on open. |
|
||||
| **P2.4** | ~~Light-theme `.ink-3` contrast borderline AA~~ | `app.css` | ✅ Iter N — `--ink-3` darkened from `#6b7684` (3.7:1) to `#54606e` (~5.4:1) on light bg, `--ink-4` from `#9ba4b0` to `#7a8390`, line/line-2 firmed. AA-compliant for normal-weight text. |
|
||||
| **P2.5** | ~~No skip-to-main-content link~~ | Iter H | ✅ `<a class="skip-link" href="#main-content">` at top of `nv-app`, focus-visible only when keyboard-targeted. Main view wrapped in `<main id="main-content" role="main">`. |
|
||||
| **P2.6** | ~~Keyboard arrow-key scene navigation~~ | `nv-scene.ts` | ✅ Iter N — Tab cycles draggable items, arrows nudge by 8 px (32 with Shift), Esc deselects, position changes persist via `scenePositions`. |
|
||||
| **P2.7** | Service worker doesn't have `clients.claim()` | Confirm. Ensures new SW activates on next nav. |
|
||||
| **P2.8** | PWA install prompt is silent | Add an install button (visible only when `beforeinstallprompt` fires). |
|
||||
|
||||
## 5. Iteration plan
|
||||
|
||||
The dynamic /loop continues with one P0/P1 item per iteration:
|
||||
|
||||
| Iter | Focus | Status |
|
||||
|---|---|---|
|
||||
| **A** | Functional Ghost Murmur demo (P0.4) | ✅ `runTransient` WASM export + interactive distance/moment sliders + per-tier detectability bars |
|
||||
| **B** | Scene sim-controls + toolbar (P0.6, P0.7) | ✅ Bottom-right sim controls, top-left zoom/layer toolbar |
|
||||
| **C** | Topbar seed + WASM pill clicks (P0.5, P1.10) | ✅ Seed modal + transport pill opens Settings drawer |
|
||||
| **D** | Sidebar tunables wire-through (P1.8) | ✅ Debounced `setConfig` RPC, 300 ms |
|
||||
| **E** | REPL `proof.export` + history persistence (P0.9, P0.10) | ✅ Blob download + IndexedDB-persisted history |
|
||||
| **F** | SNR computation + reduce-motion (P1.4, P1.11, P1.3) | ✅ |B|/max(σ) live SNR, prefers-reduced-motion auto-detect |
|
||||
| **G** | Modal contents (P1.6) | ✅ New-Scene form (5 fields), real Scene JSON push |
|
||||
| **H** | A11y pass (P2.1–P2.5) | ✅ aria-labels, focus trap, role=log, skip link, role=tablist |
|
||||
| **I** | Density toggle (P1.2) + drag persistence (P1.7) | ✅ Density CSS verified, scenePositions persisted to IndexedDB |
|
||||
| **J** | UX usability pass | ✅ nv-help center (Quickstart/Glossary/FAQ/Shortcuts/About), 10-step welcome tour, panel descriptions, settings explainers, empty-state hints |
|
||||
| **K** | Home view | ✅ `<nv-home>` as default landing — hero + 4 quick-jump cards + simplified grid hides power-user panels |
|
||||
| **L** | WsClient transport | ✅ Full REST + binary WebSocket impl against `nvsim-server`; transport-flip auto-reverify; activated via Settings drawer |
|
||||
| **M** | App Store live runtime | ✅ 6 simulated apps emit real i32 events against nvsim frame stream; runtime pills (running/simulated/mesh-only); live events feed |
|
||||
| **N** | Light-theme contrast (P2.4) + keyboard scene nav (P2.6) | ✅ AA-compliant `--ink-3`/`--ink-4`/`--line` palette in light mode; Tab/arrows/Shift-arrow/Esc on scene draggables |
|
||||
|
||||
Each iteration ends with: `npx tsc --noEmit` clean → production
|
||||
build with `NVSIM_BASE=/RuView/nvsim/` → push to `gh-pages/nvsim/`
|
||||
preserving siblings → `agent-browser` validation including console
|
||||
errors → commit on `feat/nvsim-pipeline-simulator`.
|
||||
|
||||
The acceptance criteria from ADR-092 §11 still apply unchanged. This
|
||||
ADR augments §11 rather than replacing it — every P0 item is a
|
||||
prerequisite for declaring §11.1 (faithful UI) green.
|
||||
|
||||
## 6. References
|
||||
|
||||
- ADR-092 §4.2 — full UI inventory table (the contract).
|
||||
- ADR-092 §11 — 12 acceptance gates.
|
||||
- `assets/NVsim Dashboard.zip` — canonical mockup (committed).
|
||||
- `docs/research/quantum-sensing/16-ghost-murmur-ruview-spec.md` — Ghost Murmur source material.
|
||||
- Live deploy — https://ruvnet.github.io/RuView/nvsim/ (verified: rail buttons functional, witness verifies, App Store catalog renders, onboarding tour works).
|
||||
Reference in New Issue
Block a user