492 Commits
Author SHA1 Message Date
rUv a1ca023ee8 Animate anatomical pose with opposing gait and perspective depth 2026-10-12 21:04:27 -07:00
rUv 2b3138d9d0 Replace README stick figure with shaded anatomical SVG human 2026-10-12 20:58:45 -07:00
rUv 1c678a71fa Improve README spatial visuals with distinct sensing motion and typography 2026-10-12 20:52:23 -07:00
rUv 6699a2fc44 Match README spatial SVGs to RuView header palette and add RF wave motion 2026-10-12 20:33:57 -07:00
rUv 964377765a Improve README SVG spatial motion and typography (#2257) 2026-10-12 20:28:12 -07:00
rUv 0f95193190 Merge pull request #2248 from ruvnet/codex/toolkit-release-20261012
fix(toolkit): integrate capture/device corrections for 0.9.2
2026-10-12 09:54:03 -07:00
rUv 4413491370 Merge pull request #2247 from ruvnet/codex/firmware-release-20261012
fix(firmware): correct identity and secure OTA provisioning for 0.8.14
2026-10-12 09:17:31 -07:00
ruv 2c1222789d Merge remote-tracking branch 'origin/main' into codex/toolkit-release-20261012 2026-10-12 11:49:52 -04:00
ruv 3620abff12 fix(toolkit): integrate capture and device corrections for 0.9.2
Integrate reviewed source PRs #2201-#2223, #2225-#2231, #2235-#2240, #2242 and #2243 (firmware README hunks remain in #2247). Regenerate one package manifest after integration, validate native Windows test execution, bound MTK listener startup, support official C6 release bundles, and retain stronger release metadata gates.
2026-10-12 11:49:52 -04:00
ruv a937a5fd20 fix(firmware): correct device identity and provision OTA keys for 0.8.14 2026-10-12 11:48:38 -04:00
ruv 8a140c1906 fix(docs): harden README visual XML and path validation 2026-10-10 13:41:26 -04:00
rUv 4696804b23 docs: add Cognitum-style animated RuView visual system 2026-10-09 05:45:16 -07:00
ruv a72174c571 fix: review findings and cross-PR integration fixes for aepod release set
- mediatek: cap per-device maps at 64 with oldest-first eviction; clamp --csi-ring
- training: mark live-buffer fallback runs degraded (data_source/degraded) instead of plain "completed"
- multistatic: skip CIR blend when any frame in the cohort has a placeholder phase
- groundtruth: median count baseline; radar labels carry evidence=CLAIMED
- spatial-evidence: default proof CODE; MEASURED requires a reproducer
- scripts: collect-ground-truth guards non-JSON replies and unreadable token files
- docker: entrypoint accepts 1/true/yes/on for RUVIEW_UDP_INSECURE_LAN
- adaptive model: untrack v2/data/adaptive_model.json (#2135)
- docs: ADR-379 evidence tags, RUNBOOK/README OTA wording, NOTICE for vendored MediaTek patch
- tests: fresh timestamps for privacy tests (#2119 staleness), plan_source Result handling,
  drop obsolete qualcomm-binds-nothing test (#2126), ignore slow live-binary test (#2157)

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-05 12:08:21 -04:00
ruv 69fc9efff7 Merge PR #2145 (aepod) into release integration 2026-10-05 11:48:25 -04:00
ruv 20386cf313 Merge PR #2141 (aepod) into release integration
# Conflicts:
#	docs/adr/README.md
2026-10-05 11:48:24 -04:00
ruv ca44cd1a7b Merge PR #2117 (aepod) into release integration
# Conflicts:
#	docs/integrations/home-assistant.md
#	v2/crates/wifi-densepose-sensing-server/src/main.rs
2026-10-05 11:47:34 -04:00
ruv 5fe0a6a48d Merge PR #2105 (aepod) into release integration
# Conflicts:
#	v2/crates/wifi-densepose-sensing-server/src/main.rs
2026-10-05 11:46:33 -04:00
ruv da1ef6a17d Merge PR #2102 (aepod) into release integration
# Conflicts:
#	docs/adr/README.md
2026-10-05 11:46:15 -04:00
ruv b6c2fb5b7d Merge PR #2116 (aepod) into release integration 2026-10-05 11:46:08 -04:00
ruv 2493185ab8 Merge PR #2112 (aepod) into release integration 2026-10-05 11:45:33 -04:00
ruv 678f63f4f3 Merge PR #2125 (aepod) into release integration
# Conflicts:
#	v2/crates/wifi-densepose-sensing-server/src/cli.rs
#	v2/crates/wifi-densepose-sensing-server/src/main.rs
2026-10-05 11:45:26 -04:00
ruv e9d0cef610 Merge PR #2133 (aepod) into release integration 2026-10-05 11:44:34 -04:00
ruv 51e1788c7e Merge PR #2129 (aepod) into release integration 2026-10-05 11:44:32 -04:00
ruv 7b62297f3e Merge PR #2126 (aepod) into release integration 2026-10-05 11:44:31 -04:00
ruv 7955af5bc0 Merge PR #2107 (aepod) into release integration 2026-10-05 11:44:29 -04:00
ruv de5f7edd16 Merge PR #2100 (aepod) into release integration 2026-10-05 11:44:22 -04:00
Mathew Beaneandclaude-flow db81dce7ba fix(multistatic): gate phase combining on a declared shared reference
The sensing-server bridge builds every node frame with a zero phase
placeholder and the fuser combined those phases across nodes as if they
were measured against one reference. ESP32 nodes each run an independent
crystal with a random PLL phase after reset; mesh time sync aligns frames,
not RF phase, so there is nothing to combine.

- Add PhaseReference (Unavailable / NodeLocal / Shared{id}) to
  MultiBandCsiFrame. The server bridge declares Unavailable.
- MultistaticFuser combines phase only when every frame declares the same
  Shared id. Otherwise fused_phase is empty and FusedSensingFrame carries
  PhaseFusion::AmplitudeOnly(reason). Amplitude fusion is unchanged.
- The ADR-134 CIR blend is skipped when the phase is a placeholder.
- TrustedOutput and /health/ready (trust.phase_fusion) report the mode
  and reason.
- ADR-029 status note updated.

Refs #1752, #1710, #1750.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-04 16:42:03 -04:00
Mathew Beaneandclaude-flow 76af08a9b0 docs(adr): ADR-381 node self-survey from pairwise ranging
Proposed. Defines the RangeObservation record, a warn-only check mode
against --node-positions with tolerances from MEASURED ESP32-S3 FTM
bench data, per-boot calibration, and a fill mode gated off until a
source shows MEASURED p90 link error <= 0.3 m (expected from UWB).
Records the FTM bias between responder starts plainly and parks FTM
for check mode, coarse gating and time sync rather than dropping it.
Links ADR-144, ADR-281, rufield ADR-261, #2109 and #2133.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-03 23:08:04 -04:00
Mathew Beaneandclaude-flow a1d7eb0bfd docs(spatial-evidence): ADR-382 for the RF wire contract, pin the v1 yaw convention
The spatial.evidence.v1 format is specified in WeftOS ADR-107 section 7.
ADR-382 records the part RuView emits (envelope, room_enu frame,
rf_gaussian, rf_link_observation, validation ranges, versioning) so the
contract is readable from this repository, and names ADR-107 as its origin.

ADR-107 was amended on 2026-10-03: one yaw convention (degrees
counter-clockwise from room +x), new tof_depth and radar_range types, and
an optional sensor block on radar_track_point. The two RF bodies did not
change. The crate now documents the yaw sense of an rf_gaussian
orientation and tests it (+90 degrees about +z maps local x onto room +y),
and tests that the amended example lines are rejected as unknown types by
this RF-only mirror.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-03 22:57:08 -04:00
Mathew Beaneandclaude-flow 5cffe9e7db fix(sensing-server): accept vendor --source values and bind UDP for them
The previous commit limited --source to auto/esp32/wifi/simulated, which
rejected the vendor names the server already keys on: mediatek, qualcomm,
realtek (RTL8720F radar) and realtek_csi (RTL8721Dx CSI). They are the
labels the UDP receiver writes and effective_source() ages.

On 03a89793 those names fell into the catch-all plan, which bound no UDP
receiver, so vendor frames were never ingested. They now plan like esp32
(UDP receiver bound) without the ESP32-shaped simulator. Anything else,
including case variants and runtime-only labels like "mediatek:simulated",
is still rejected.

Refs #2097

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-02 22:13:38 -04:00
Mathew Beaneandclaude-flow c51a1cf888 fix(sensing-server): apply --privacy-mode to REST, WebSocket and recordings
--privacy-mode was declared in the MQTT arg group and read only by the
MQTT publisher, so /api/v1/sensing/latest, /api/v1/pose/current, the
/ws/sensing and /api/v1/stream/pose streams and recordings kept serving
pose keypoints (and heart/breathing rate when vitals are published).

- Move --privacy-mode (env RUVIEW_PRIVACY_MODE) out of MqttArgs to a
  top-level server flag. Spelling and env var are unchanged. The MQTT
  config takes its value from the server flag.
- Add privacy_filter: one key filter for vital_signs, HR/BR leaves,
  enhanced_breathing, keypoints, pose_keypoints and joints_m.
- REST: middleware strips those keys from every JSON response on the
  HTTP and WS ports. Unparseable JSON is withheld with a 500.
- WebSocket: /ws/sensing frames and /api/v1/stream/pose messages are
  filtered; the pose physics assessment is withheld.
- /api/v1/pose/current?view=both|refined returns 403 privacy_mode.
- Recordings write filtered frames.
- Default (flag off) behaviour is unchanged; the middleware is a no-op.

Fixes #2094

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-02 22:12:45 -04:00
Mathew Beaneandclaude-flow 5755d9f11f fix(sensing-server): status waits for frames; reject unknown --source
/api/v1/status reported source_state "live_unverified" for a configured
live source before any frame had arrived, because source_state() fed a
fixed zero frame age into the ADR-295 resolver. It now uses the real age
of the last accepted frame for the current source, so the states are:

- disconnected (waiting_for_frames: true) until the first frame
- live_unverified while frames arrive within ESP32_OFFLINE_TIMEOUT (5 s)
- stale once they stop for longer than that

The response also carries waiting_for_frames and last_frame_age_ms.
ADR-270 vendor events get their own receive clock so they age the same
way.

An unknown --source value (for example "macos") used to start a server
with no data task. Clap now rejects it with the list of valid values
(auto, esp32, wifi, simulated, simulate), and plan_source returns an
error for anything else.

Docs: user guide lists the valid --source values and status states, the
macOS section uses --source wifi, and the Linux section says there is no
Linux RSSI source in the server yet.

Refs #2097

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-02 22:09:50 -04:00
Mathew Beaneandclaude-flow 3bf993275e fix(sensing-server): give the governed fuser the configured node positions
EngineBridge built its StreamingEngine without ever calling
set_node_positions, so the governed fuser placed every node at the
origin even when --node-positions was set. Startup now passes the same
keyed map the sibling multistatic_fuser gets, via
EngineBridge::with_node_positions. The fuser resolves positions by
node_id per frame, so nodes discovered later need no extra call.

/api/v1/status (and /health/ready) now reports the map under
trust.node_positions so the configuration can be checked at runtime.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-02 22:08:58 -04:00
Mathew Beaneandclaude-flow 05ea4feaed fix(sensing-server): keep recordings and models under --data-dir
Recordings, the recording list/delete routes, the trainer's dataset
loader and model export, the models routes and the adaptive classifier
all used paths relative to the process cwd (`data/recordings`,
`data/models`, `data/adaptive_model.json`), so `--data-dir` only covered
config and the session secret.

Add `recordings_dir(data_dir)` and `models_dir(data_dir)` and use them
everywhere. `MODELS_DIR` still overrides the models directory, and the
trainer now honours it too. With the default `--data-dir data` the paths
are unchanged.

Fixes #2088

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-02 22:07:11 -04:00
Mathew Beaneandclaude-flow 8c63d7b558 docs(mqtt): document the published entity set and add an ADR-115 P4.5 status note
home-assistant.md now describes current behaviour: the 15 announced
entities (13 with --privacy-mode) with their source and availability
rule, the entities that are not announced and why, publish rates and
retention, the persisted client id, and what privacy mode does and does
not cover. The guide no longer documents --semantic* flags that
sensing-server does not accept, and it drops the HIPAA/GDPR/CCPA
claims.

ADR-115 §11 records what P4.5 wired and what it did not, with a
before/after measurement against a real broker (MEASURED, one live
node).

Refs #2085, #2093

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-02 18:46:21 -04:00
Mathew Beaneandclaude-flow ea6da967d2 docs(mediatek): OpenWrt WN586X3 CSI patch set, router CSI guide, ADR-266 amendment
- firmware/openwrt-wn586x3/: the patch set that made a Wavlink WL-WN586X3
  Rev A (MT7981B + MT7976C) emit CSI on OpenWrt 24.10.8. It contains:
  MediaTek's mt7915 CSI driver patch rebased onto the mt76 revision 24.10.8
  pins (BSD-3-Clause-Clear, MediaTek author line kept); the Rev A board
  patch (GPL-2.0); a buffer-overrun fix for `mt76-vendor dump csi`; and
  an attribute-enum fix for MtkCSIdump. Each patch keeps the licence of
  the code it modifies. There are no images, firmware blobs, or captures.
- docs/mediatek-router-csi.md: an operator guide covering supported
  silicon, the image build route that was tested, arming CSI, the
  bridge, `--source mediatek`, endpoints and provenance labels, what the
  data is not, evidence, and troubleshooting. Every claim is tagged
  MEASURED, CODE-DERIVED, CLAIMED, or SYNTHETIC.
- scripts/mediatek-csi-phase-stability.py: a read-only reproducer for
  the one MEASURED offline result. On one MT7976C radio, the cross-chain
  phase arg(H0*conj(H1)) moves 0.014-0.039 rad (p50) between adjacent
  frames for well-sampled transmitters, against about 1.56 rad for raw
  per-chain phase, which is what random phase gives. It never prints a
  transmitter address. The captures it was run on are not in the tree.
- ADR-266 Amendment 1: vendor CSI exists on MT7981 through MediaTek's
  public feed patch, demonstrated on one board model, and still
  `mediatek:physical-unvalidated`. The hardware gates remain open.
- user-guide.md and the bridge README link to the guide.

Developed in whitsentry, a RuView-based project.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-02 18:32:25 -04:00
Mathew Beaneandclaude-flow ebb303cbb8 feat(hardware): carry legacy and unknown PPDU types in MediaTek MTC1
A real MT7981 (WL-WN586X3, MT7981B + MT7976C) CSI report arrived with
rx_mode = MT_PHY_TYPE_OFDM for a 2.4 GHz client. The MTC1 PpduType had no
pre-HT value, so a bridge had to drop the frame. MediaTek's CSI driver
treats legacy OFDM as its own tone-mask group, and association traffic is
legacy-rate, so these frames are routine rather than a corner case.

Add PpduType::Legacy = 6 and PpduType::Unknown = 7. Values 1-5 and the
72-byte header are unchanged. A decoder built before this change rejects
6 and 7 as UnknownPpduType (fails safe, drops the frame), so MTC1
consumers need a rebuild.

ADR-267 gains Amendment 1 recording the change, its compatibility, and the
observed 1x1x64 dimensions of the motivating capture. The capture is not
in the tree: it holds a client transmitter address and raw CSI.

Developed in whitsentry, a RuView-based project.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-02 18:17:36 -04:00
Mathew Beaneandclaude-flow 3b542f8a85 fix(docker): make UDP CSI ingest posture explicit in the container
Since ADR-296 the sensing server binds its UDP receiver to 127.0.0.1 by
default, and docker-entrypoint.sh never set a UDP bind. Inside a
container that address cannot receive from the published 5005/udp port,
so the default image never shows a node (#2089, follow-up to #1394).

The entrypoint now binds UDP on 0.0.0.0 only when the operator has set
an ADR-296 source guard (RUVIEW_UDP_ALLOW, RUVIEW_UDP_INSECURE_LAN, or
the matching CLI flags). Without a guard it keeps the loopback bind and
prints a note explaining why no node will appear and what to set,
including the macOS bridge-gateway allowlist. An explicit RUVIEW_UDP_BIND
or --udp-bind still wins.

I chose this over defaulting the bind to 0.0.0.0 unconditionally. With
no guard that would make the server refuse to start (exit 1) in auto
mode, which binds UDP, and the guard would still have to be supplied. The
change keeps ADR-296's fail-closed rule as is: a routable bind never
happens without an allowlist or the explicit insecure opt-in. Auth
defaults are unchanged.

The entrypoint also normalizes RUVIEW_UDP_INSECURE_LAN=1/yes/on to true,
since clap rejects 1 for that flag.

The compose service passes RUVIEW_API_TOKEN, the RUVIEW_UDP_* variables
and SENSING_ALLOWED_HOSTS through from the shell, with notes on the
exit-64 auth check, the macOS gateway allowlist and the 421 Host check.
The README and user-guide Docker quickstarts now set a token, and the
user guide gains a "Receiving ESP32 frames in Docker" section.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-02 16:13:10 -04:00
Mathew Beaneandclaude-flow f161abf582 feat(sensing-server): loopback UDP tee for second consumers (ADR-380)
Add --udp-tee / RUVIEW_UDP_TEE: every datagram the source allowlist admits
is copied unchanged to up to four loopback targets, so a fusion host or
Cognitum cog can read full I/Q, sequence numbers and sync packets without
binding the CSI port. Targets must be loopback and may not reuse the
listener port or port 0. Sends are non-blocking and drops are counted. Off
by default.

Tests: cargo test -p wifi-densepose-sensing-server --no-default-features
--lib udp_tee (6 passed) and --bin sensing-server (332 passed). Loopback
smoke test of the debug binary: a 288-byte datagram sent to the UDP port
arrived byte for byte at the tee target, and a non-loopback --udp-tee
target made the server exit 1 with "must be a loopback address".

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-02 03:12:19 -04:00
Mathew Beaneandclaude-flow a4f80e63a2 docs(adr): ADR-379 OTA first-boot health check, with hardware evidence
Records the decision behind the two preceding firmware commits: why an
OTA'd image has to confirm itself, the health signals (STA IP plus one CSI
frame accepted by the stream sender), the 30 s minimum uptime and 120 s
deadline, the FORCE_FAIL test hook, ota_state in /ota/status, and the httpd
stack sizing.

MEASURED 2026-09-29:
- ESP32-S3 (16 MB, rollback bootloader): OTA push to ota_1, HTTP 200;
  "httpd stack after POST /ota: 4900 of 8192 bytes never used";
  pending_verify then valid; still valid on ota_1 after a hard reset.
  A FORCE_FAIL build pushed to ota_0 rolled back to ota_1 after ~30 s.
- ESP32-C6 (4 MB layout, rollback bootloader): push to ota_1, HTTP 200;
  pending_verify then valid ~28 s later; still valid after a hard reset.

Not yet verified: the 120 s no-IP timeout path, a true power cycle (an RTS
hard reset was used), and forced rollback on the C6.

Numbered 379: main has up to ADR-378 and open PRs claim nothing higher (2026-10-02).

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-02 03:12:12 -04:00
Mathew Beaneandclaude-flow f8ab204711 fix(wifiscan): keep the redacted macOS connected link; auto+wifi keeps UDP bound
On macOS 27, without Location Services, CoreWLAN redacts both the SSID and
the BSSID, while rssi, noise and channel stay real. resolve_bssid abstained
when both identities were blank, so every macOS scan was dropped and
`--source wifi` silently produced nothing.

- mac_wifi --scan-once marks its sample `"connected": true`. It is always the
  single connected link, so a synthetic id cannot merge two networks.
- A redacted connected sample gets a stable locally administered synthetic
  BSSID; the SSID stays empty. Unmarked redacted lines still abstain.
- `--source auto` that resolves to host WiFi now also binds UDP, and wifi_task
  yields while the source is a live esp32, so ESP32 nodes that start after
  the boot probe still promote the source (the #1004 rule). Without this, the
  fix would make stock Macs ignore late-starting nodes.
- A missing helper is reported once, with the build command.
- ADR-025: Updated row + Amendment 1 recording the measured behaviour.

Measured on macOS 27: --source wifi gives source wifi:unnamed with sensing
ticks advancing; --source auto on a quiet port starts on wifi with
udp_receiver=true and promotes to esp32 (5 nodes) when real frames arrive.
Tests: wifiscan 158+1, sensing-server bin 332, all passing.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-02 03:11:08 -04:00
ruv 39b4ae9ae1 release: @ruvnet/ruview 0.9.1 and ruview umbrella 0.9.1
Bump the harness and the umbrella (which pins it), point README and the
user guide at 0.9.1, sync the stale lockfile header (0.5.1, old bin name)
with package.json, and add a plain-language changelog entry for the
live sensing views in Claude Code (ADR-377, ADR-378).

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-01 18:57:49 -04:00
ruv 4a472926e1 fix(ruview-live): code-review findings on the waterfall (ADR-378)
- Stale frames shown as live: spectrumWith now keeps only nodes in the
  latest capture, so a node that stops streaming (or a failed capture)
  leaves the waterfall and the "no CSI frames" card returns.
- Multi-antenna ESP32 nodes never reached the waterfall: with --spectrum
  the parser adds chain-0 amplitudes (ADR-018 antenna-major) in a separate
  field the SpectrumCollector reads; the kernel path is unchanged.
- Frames from different CSI layouts could be joined: spectrum results
  carry their shape, and frames merge only when shape and bins match.
- Animation ran on assumed time: frames read the real clock (the one the
  full render uses), so pulses keep the reported rates and the replay
  keeps up when a frame fires late; replay lag is pruned with the nodes.

Tests: regression tests for each; npm test 193 pass, test:security 91
pass, engine tests 4 pass, validate passes.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-01 18:47:18 -04:00
ruv 751b7ae17b feat(ruview-live): showcase views — CSI waterfall, radar fan, animated cells (ADR-378)
The /ruview pane gains three views (keys 1/2/3) drawn in terminal Rasters
and animated in place with $.ui.blit (~12 fps, no redraws):

- CSI waterfall: per-subcarrier amplitude over time from the new
  `esp32 --spectrum` capture, two frames per row via the half block,
  5-95th percentile colour limits, replayed at the frames' arrival rate,
  labelled MEASURED or SYNTHETIC from the packets' own flag; n cycles nodes.
- Radar: a 120-degree range fan with rings, a fading distance trail and a
  sonar ping to the measured range; braille heart/breathing/distance charts
  scaled to the data; a heart and breathing gauge that pulse at the
  device-reported rates ("a metronome, not a waveform").
- A shimmer rule under the title; surfaces without Raster get a note.

Harness: captureEsp32 / ruview_esp32_capture take spectrum,
spectrum_bins (8-128) and spectrum_frames (8-256): a bounded ring of
binned amplitude frames per node, dominant shape, rate and synthetic flag.

The mod is split into model/raster/anim/views/register (own-file imports
only). Tests: 11 showcase + 11 mod Node tests, a --spectrum loopback test,
4 engine tests (waterfall tab sends --spectrum, draws the Raster, blits);
npm test 189 pass, test:security 90 pass, manifest verified, validate passes.

Evidence: MEASURED on an ESP32-C6 (COM11, release c6-adr110 v0.7.0, node 6)
streaming 7-18 Hz CSI to this host; a 1x256 capture renders the occupied
band against guard/null tones. Unpacked budget 384 -> 448 KiB (+~37 KB).

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-01 18:22:40 -04:00
ruv 8b857e41cd docs: README and user guide for @ruvnet/ruview 0.9.0 (devices, radar, MCP/ChatGPT, Claude Code mod)
- README MetaHarness section pinned to 0.9.0 with the hardware, MCP-over-HTTP,
  mod, Homecore and kernel commands; plugin section lists the ruview-live mod.
- User guide: new "RuView npm toolkit" section (hardware CLI, alert meanings,
  ESPHome kits, MCP/ChatGPT connection, the /ruview mod, Homecore + kernel),
  TOC entry, 0.5.0 pins updated.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-01 17:26:40 -04:00
ruv 093e3bbeae feat(ruview): ruview-live Claude Code mod shipped in the npm package (ADR-377)
- mod/: a Claude Code mod (function hooks). /ruview opens a pane beside
  the transcript with CSI nodes (rate, loss, RSSI, shape, SYNTHETIC) and an
  optional ESPHome radar (presence, distance, device-reported vitals),
  alerts (heartbeat-only boards + buffer-starvation hint), Refresh/Close
  buttons and a one-line status; refreshed on $.clock.every.
- Reads only through the harness CLI beside it (fixed read-only argv,
  --json) located via $.plugin.root (mods may import nothing else).
- Packaged in @ruvnet/ruview (mod/.claude-plugin, mod/hooks), listed in the
  repo marketplace as ruview-live@ruview; `ruview mod` prints how to load it.
- @ruvnet/ruview 0.9.0; umbrella ruview 0.9.0 (still unpublished).

Verified: claude plugin validate (mod + marketplace); claude plugin test
2/2 x3 runs; harness 172 tests + 89 security; real Claude Code headless
`/ruview refresh` from an installed tarball and with the live radar kit.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-01 17:12:53 -04:00
ruv 4128661789 docs(adr-376): record release outcome — components published, unscoped ruview refused by npm (403, similar to iview)
Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-01 16:45:20 -04:00
ruv b6f3abd35e feat(npm): ruview umbrella package + ESPHome radar source (ADR-376, ADR-373 A3)
- harness/ruview-umbrella -> npm `ruview` 0.8.0: one CLI and one MCP server
  for the operator harness, Homecore and the vitals kernel. `ruview homecore
  ...`, `ruview kernel <doctor|info|selftest|parity|synth|analyze|bench>`,
  `ruview capabilities`; everything else delegates to @ruvnet/ruview. MCP
  serves ruview_* + homecore_* tools and the ui:// console (stdio + HTTP).
- @ruvnet/ruview 0.8.0: bin renamed `ruview-harness` (the umbrella owns
  `ruview`; a clean tarball install showed the bin collision). New exports
  (cli, cli-ui, mcp, mcp-http, ui, esphome, kernel); injectable MCP handler;
  kernel as optional peer + setKernelImporter so the kernel resolves from
  the umbrella's tree under linked/pnpm installs.
- mmwave --source esphome: dependency-free read-only ESPHome native API
  client (private hosts only; encrypted/password APIs reported). Live Seeed
  MR60BHA2 kit: presence, distance, device-reported HR/BR (MEASURED).
- monitor detects Ameba CSI buffer starvation; radar views in terminal UI
  and console widget.
- homecore 0.1.0 and @ruvnet/ruview-kernel 0.1.0 gain ./cli exports.

Gates: harness 166 + 89 security, homecore 27 + 23, kernel 21 + 12,
umbrella 4; clean-dir tarball install smoke incl. live radar over HTTP MCP.
Local publish is a one-off exception to ADR-265 D2, recorded in ADR-376.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-01 16:30:23 -04:00
ruv 45796e4e3e feat(ruview): MCP Apps console widget, HTTP transport, terminal UI (ADR-375)
- ui://ruview/console-v1.html: one self-contained widget for MCP Apps hosts
  and ChatGPT (ui.resourceUri + openai/outputTemplate). Renders node
  streams, device scans and doctor results; Refresh re-runs the tool via
  window.openai.callTool or an MCP Apps tools/call. Empty CSP allowlist, no
  network, textContent only, parent-frame messages only.
- MCP: protocol negotiation (2025-06-18/2025-03-26/2024-11-05),
  structuredContent + compact JSON text (17-33% smaller, MEASURED),
  resources/list|read, tool titles, canonical tool name in result _meta.
  Transport-neutral handleRpc + shared FIFO dispatcher.
- `mcp start --http`: Streamable HTTP for ChatGPT/remote clients. Bearer or
  secret-path token (constant-time), loopback default, Origin allowlist,
  256 KiB cap, no batches, write grants never honoured over HTTP.
- CLI: formatted TTY output (tables, rate bars, alerts first, NO_COLOR),
  JSON for pipes/--json, capture countdown, `esp32 --watch` with per-node
  sparklines, lazy module loading (--help ~20% faster, MEASURED).
- monitor detects Ameba CSI report-buffer starvation ("lack of csi buf"),
  the root cause of the Realtek heartbeat-only stall seen live.
- Size budget 320 -> 384 KiB (package ~339 kB).

Verified: 160 tests + 83 security tests; headless-Chrome e2e of the MCP
Apps flow against live boards (refresh round trip 108 -> 105 packets);
HTTP security probes; clean tarball smoke (stdio + HTTP).

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-01 15:52:26 -04:00
ruv 3cd360f9e2 fix(ruview): CSI loss survives stray and reordered sequence numbers
Live RTL8721Dx capture (node 3, COM10) reported 97% loss: one stray
sequence value (+52,835, then straight back) was counted as 52,834 lost
frames, and every late UDP packet re-counted its gap. The tracker now
treats a single out-of-window value as a stray, needs two agreeing frames
to accept a counter reset, and lets a late packet fill its own gap
(seqReordered / seqStrays / seqResyncs in the summary). Against ground
truth on the live board (unique sequence numbers over the span): 4,783 of
4,783 present, loss 0, 9 strays; the tracker matched both.

ADR-373 Amendment 2 records the live Realtek run: devices -> realtek,
7,404/7,404 packets decoded, monitor at 1500000 baud without a reset, and
12,549 live frames analyzed by the WASM kernel.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-10-01 15:20:21 -04:00