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>
- 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>
Hotkeys reach a pane only while it holds the keyboard, and `focus` alone
was not taking it. The engine's documented dialog form does: open with
focus + closeOnEscape + holdToasts (Escape closes, as originally). Each
open also requests `rows` for its view (overview 16, waterfall 30,
radar 26) so the inline pane opens tall enough for the bordered design
instead of a third of the screen; switching views re-requests the size,
and picture heights leave room for the chrome (rows - 15).
Co-Authored-By: claude-flow <ruv@ruv.net>
The compact inline layout read as broken next to the bordered cards the
user prefers; restore the previous design (78a147405). This reverts
commit 629e1b9c6.
Co-Authored-By: claude-flow <ruv@ruv.net>
Outside fullscreen the pane sits inline above the prompt with a few rows,
so the bordered cards, rule and footer were cut off (Refresh/Close never
visible). Inline (or under 18 rows) the pane is now compact: views and
actions share the top row, no borders/rule/gaps, pictures sized to the
rows left, radar readings beside a small fan. The top row always says
whether the pane holds the keyboard ("keys active · Esc returns them" or
"click the pane or press ctrl+x tab to use the keys").
Co-Authored-By: claude-flow <ruv@ruv.net>
Button hotkeys reach a Pane only while it holds the keyboard; the pane
opened without it, so 1/2/3/r/c went to the prompt. Open (and
/ruview waterfall|radar) now request `focus: true`; closeOnEscape is
dropped so Escape hands the keys back without closing; an unfocused pane
shows "click the pane or press ctrl+x tab to use the keys".
Co-Authored-By: claude-flow <ruv@ruv.net>
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>
- Header: RuView + LIVE/STALE badge (fresh within 2 refresh periods),
"updated <time> (Ns ago)", a 5 s redraw tick keeps the age current.
- Bordered cards for the radar and the CSI nodes, side by side from 100
columns, stacked below.
- Radar: PRESENCE DETECTED (+ target count) in green; distance, heart and
breathing with per-refresh sparklines; device-reported vitals outside
resting ranges (heart 40-180, breathing 4-40 bpm) are flagged in yellow
instead of shown as fact (the live kit reported breathing 1.0 bpm).
- Nodes: per-node rate sparkline; "no packets" is a short hint in the card
rather than a long top alert (status no longer counts it as an alert);
an unconfigured radar says how to configure it.
- Buttons show their hotkeys.
Tests: 11 Node unit tests, 3 engine tests (mounted pane validates on the
terminal surface), validate passes.
Co-Authored-By: claude-flow <ruv@ruv.net>
A hot reload (or a resumed session) re-runs register with fresh variables
while the engine keeps the pane open, so no timer ran and the pane stayed
on "waiting for the first capture". Drawing the pane now resumes polling
when no timer is running. Engine test mounts the pane with no /ruview in
the module instance: fails without the fix, passes with it.
Co-Authored-By: claude-flow <ruv@ruv.net>
$.clock.now() resolves a promise of epoch milliseconds; refresh passed the
promise into the model. Await it, and have the pane print "—" for any
non-finite timestamp. Seen live in Claude Code 2.1.287 (/ruview pane).
Regression tests fail without the fix (2/2) and pass with it.
Co-Authored-By: claude-flow <ruv@ruv.net>
- 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>
- 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>
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>
The flash flow's boot-log capture decoded serial lines and wrote text to a
stdout that the scrubbed child env leaves on cp1252. The ESP32-C6 release
firmware logs U+2192, so the capture died mid-boot (bootLog.captured=false);
an earlier abort would have hidden the CSI evidence and reported a good
flash as unvalidated. Write raw bytes instead. Regression test forces
PYTHONIOENCODING=cp1252 through a stand-in serial module (fails without
the fix). ADR-373 Amendment 2 records the real C6 flash evidence.
Co-Authored-By: claude-flow <ruv@ruv.net>
Findings from a hardware run of this branch against an RTL8721Dx board
(PL2303GC) and an ESP32-C6 (CP210x) on Windows 11:
- esp32 capture decodes Realtek RAC1 (ADR-323, CRC-verified, 8/16-bit
tones) and RHB1 heartbeats, ADR-110 sync and ADR-081 mesh packets, and
reports every CSI shape a node sends.
- Capture fails (no_decodable_packets / heartbeat_only) instead of
returning ok:true + MEASURED when nothing decodes; names
heartbeat-only senders.
- --analyze runs live single-antenna CSI through @ruvnet/ruview-kernel at
the measured frame rate with a bounded buffer.
- monitor opens the port with DTR/RTS deasserted (no node reboot), takes
--baud, and explains the C6/S3 USB-Serial/JTAG console.
- devices classifies Prolific 067B:23A3 as a Realtek board.
- Windows: owner-only ACL on the hosts file (fails closed); symlink test
skips only where Windows refuses symlinks.
- kernel build names uninitialized submodules when cargo fails.
- Parser ~3.2x faster (MEASURED, 0.42-0.52M -> 1.33-1.67M packets/s).
Co-Authored-By: claude-flow <ruv@ruv.net>
CI fixes (both failures on PR #2062 were in this branch):
- harness/ruview: remove `2.11.0` literals from training remedies; the
ADR-265 D3 version-literal gate rejects them.
- ruview-kernel workflow: install wasm32 for the toolchain pinned by
v2/rust-toolchain (the action only added it to `stable`); build.mjs now
fails fast with the exact `rustup target add` remedy.
Kernel optimization (ADR-368 amendment):
- New `analyze_flat` / `session_push_flat` ops via `call_f64`: WASM
`rvk_call_f64` (alignment-agnostic bytes) and napi `callF64(Float64Array)`.
`analyze()`/`session.push()` pack uniform frames automatically; irregular
input keeps the JSON path and its per-frame errors. `analyzeFlat()` is the
zero-copy entry. Shared `Session::step` makes both paths byte-identical on
identical f64 inputs (Rust test), and the binary path avoids serde_json's
non-correctly-rounded float parsing.
- MEASURED (`ruview-kernel bench --seconds 120`, one Linux x64 host):
2.82x (wasm) and 2.45x (napi) faster than the JSON transport.
- Profiled remaining cost (examples/profile_stages.rs): heart-rate ACF in
wifi-densepose-vitals dominates; left for a separate, output-reviewed
change. Rejected WASM +simd128 and opt-level=s after three measured runs
(bench/wasm-variants.mjs).
Device e2e (ADR-373 amendment):
- test/e2e/devices.e2e.mjs + `npm run test:e2e:devices` + new workflow
ruview-device-e2e.yml: pty-emulated MR60BHA2 and RPLIDAR through real
pyserial, a UDP ESP32 node, and the real iPhone relay, via the CLI.
- mmWave auto-detect keeps probe frames and reads only the remainder;
iPhone LiDAR gains max_frames and returns immediately when refused.
Suite wall time 19.6 s -> 5.6 s (MEASURED, dev container).
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_015H55jmprfz4oHWXSFbX5rf
@ruvnet/ruview 0.7.0 gives CLI, MCP, and SDK access to RuView sensing
hardware on the machine it is attached to, and to other machines over SSH.
Devices (ADR-373, src/devices/):
- ruview_devices_scan: pyserial port list classified by USB VID:PID
(Espressif native USB, CP210x, CH34x, FTDI) into ESP32 / mmWave / RPLIDAR
roles with the command that confirms each.
- ruview_esp32_capture: receive-only UDP listener parsing ADR-018 CSI
frames, vitals, and the other 0xC511000x packets per node: rate,
sequence loss, RSSI, subcarriers, frequency, device vitals.
- ruview_mmwave_read: MR60BHA2 (60 GHz) and LD2410 (24 GHz) parsers ported
byte-for-byte from firmware mmwave_sensor.c; baud/frame auto-detect.
- ruview_lidar_read: RPLIDAR SCAN over serial (start/stop, DTR best-effort)
and the iPhone LiDAR relay as a WebSocket client (token only via
RUVIEW_LIDAR_TOKEN; statistics only, never raw depth).
- Dependency-free serial via a fixed pyserial pump (argv-only, bounded,
hex output immune to secret redaction). Schema-level port pattern
validation added to the policy validator.
- All device tools require the new `device-access` MCP grant.
Remote hosts (ADR-374, src/remote.js):
- ~/.config/ruview/hosts.json (0600), CLI-only `hosts add`; strict
name/target validation against ssh option and shell injection.
- `ssh -o BatchMode=yes -o StrictHostKeyChecking=yes -- <target>` running a
version-pinned `ruview call <tool> --read-only`, every token single-quoted;
read-only enforced locally and remotely; no mutations, credentialed reads,
or host hopping. MCP needs `remote-host` plus the remote tool's grant.
Also: device-access skill, doctor `devices`/`remote` groups, SDK
`devices.*`/`hosts.*` with types, generic `ruview call` verb, guidance
capability, 320 KiB package budget, CI smoke expects 22 tools.
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_015H55jmprfz4oHWXSFbX5rf
@ruvnet/ruview 0.6.0 turns the harness into a complete npm operator
surface: one policy-checked tool registry behind the CLI, the MCP server,
and a new typed SDK.
- SDK (ADR-369): `@ruvnet/ruview/sdk` createRuView() with doctor,
firmware.{ports,plan,flash,monitor}, training.{plan,run,gate,calibrate},
kernel.{selfTest,load}, guidance/claimCheck/verify/spaces; strict mode
throws RuViewError; TypeScript declarations in src/sdk.d.ts.
- Firmware (ADR-370): cross-platform `python -m esptool` flashing replaces
the Windows-only stub. SHA256SUMS verification (mismatch always fatal),
bundle containment, variant/partition checks, argv-only command, chip_id
preflight that refuses a mismatched chip, boot-log capture;
hardwareValidated only when CSI callbacks appear without a panic.
Read-only ruview_firmware_plan / ruview_firmware_ports.
- Training (ADR-371): ruview_train / ruview_train_plan run pose-smoke,
pose (MM-Fi), or room training from the trusted checkout with in-repo
paths only, logs/checkpoints under v2/target/ruview-train, and libtorch
remedies. ruview_train_gate enforces mean-pose baseline, leakage-free
splits, subject/time disjointness, and evidence tagging.
- Doctor (ADR-372): structured pass/warn/fail/skip checks with remedies
across runtime, integrity, hosts, repo, Rust, Python/esptool, firmware
bundles, serial, sensing server, and the compute kernel; --json/--group;
hardware probe and network checks are CLI/SDK-only.
- Plan tools cannot take `confirm`; acting tools keep grant+confirm over
MCP. Policy files and TOOL_POLICY are drift-tested.
- Unpacked budget 160 KiB → 224 KiB in both npm workflows; CI tarball smoke
now checks the SDK and the training gate.
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_015H55jmprfz4oHWXSFbX5rf
Adds a portable RuView compute kernel for JavaScript, built from the Rust
source of truth and wired into the @ruvnet/ruview metaharness.
Rust
- v2/crates/ruview-kernel: bounded single-function JSON ABI
(call(op, json) -> envelope) over the ADR-021 wifi-densepose-vitals
pipeline: streaming sessions, batch analyze, deterministic SplitMix64
synthetic CSI (SYNTHETIC), bounded session registry, strict input
validation (deny_unknown_fields, width/finite/magnitude checks, size and
count limits). wasm32-only zero-import C ABI (rvk_alloc/free/call).
- v2/crates/ruview-kernel-napi: napi-rs transport exposing only
abiVersion()/call(); standalone workspace (excluded from v2) so napi never
enters `cargo test --workspace`; panic=unwind + catch_unwind.
npm (harness/ruview-kernel, zero runtime deps)
- loadKernel({backend: wasm|napi|auto}); WASM default (no host authority),
napi never silently falls back, auto reports fallbackReason.
- SHA256SUMS integrity verification; mismatch is always fatal; loader
rejects any WASM module that imports host functions.
- Browser-safe ./wasm entry; CLI doctor/info/selftest/parity/synth/
analyze/bench; build.mjs builds artifacts from source (no shell).
- Unit, security, and e2e tests (CLI round trip, cross-backend parity).
Metaharness
- New read-only tool ruview_kernel_selftest / `ruview kernel`: imports the
fixed optional package, fails closed with kernel_not_installed; policy,
claims, MCP policy, guidance capability, and manifest updated.
CI: .github/workflows/ruview-kernel-npm.yml builds both transports on
Linux/macOS/Windows, requires napi in tests, runs parity, verifies
artifacts, packs, and runs the cross-package e2e. No publish step.
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_015H55jmprfz4oHWXSFbX5rf
Fix breathing confidence, Windows desktop launch and clean UI builds, contributor-harness line-ending integrity, runtime secret hygiene, and remove the six ADR-299 CSI/person-data files from the current tree.
FlywheelResult has no dataSource field — @metaharness/flywheel stamps it
as replayBundle.data_source (snake_case). This test never actually ran in
CI here (nested .github/workflows/ under wifi-veil/ is inert on GitHub);
caught only once the wifi-veil/ tree was extracted to its own repo and its
own top-level Actions ran for real.
Adopt "WiFi Veil" as the product name across all user-facing surfaces, keeping
VEIL (Verifiable Emission-shaping for Identity-Leakage prevention) as the
technical codename it's built on. Only prose, titles, descriptions, and the
console UI change — no code identifiers, file names, crate/npm `name` fields,
or the deterministic proof witness are touched, so `cargo test` and the C-core
host test are unaffected.
- Crate & research READMEs: title + defining line now "WiFi Veil (codename VEIL — …)".
- Cargo.toml / package.json / plugin.json descriptions: "WiFi Veil …".
- Console UI (veil-console.html): title, brand, and copy say "WiFi Veil".
- Firmware tree (README, per-provider READMEs, BUILD/INTEGRATION/MEASUREMENT):
"WiFi Veil protector/core/shield".
- Harness manifest: recomputed SHA-256 digests for the four changed packaged
files (README, package.json, CLAUDE.md, plugin.json) — all verified consistent.
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01WEXNqzs7UsfNFBcP5yW21p
Two additions on top of the hyper-optimized VEIL shield.
1) Adaptive optimization (v2/crates/wifi-densepose-privshield/src/optimize.rs):
- optimal_bits_across_snr / model_optimal_bits_for_snr: the throughput-
optimal feedback resolution shifts with SNR (unconstrained optimum 4 bits
at 5-10 dB, 3 bits at 20-40 dB); within the spec {5,7,9} set it stays 5,
which is why the shipped shield is SNR-stable.
- adaptive_shield / min_passes_for_n: derive a shield for a specific
deployment. Finding: the collapse budget is N-independent in this model
(48 passes collapses N in {8,64} alike) — it is set by the fine-subspace
dimension, not the candidate count. Defaults unchanged, so the proof
witness is untouched. 38 tests + doctest pass; clippy -D warnings clean.
2) npm metaharness harness/wifi-densepose-privshield/ (ADR-289), mirroring
wifi-densepose-sar-harness (ADR-286) with two improvements:
- @metaharness/* imported dynamically inside the commands that need them, so
`guidance` and `--help` run with ZERO dependencies installed (offline / pre
`npm install`).
- a dependency-free VEIL `guidance` command: a source-cited, evidence-
labelled, read-only capability map (topics: overview, threat,
countermeasure, compliance, optimization, experiment).
Standard router + flywheel (SYNTHETIC) + Darwin wiring, tailored to VEIL
task axes and policy levers. Tests: smoke + router + flywheel (need install)
and guidance (offline). .harness manifest generated with real per-file
hashes. Validated offline: cli syntax, --help, guidance topics, exit codes,
graceful degradation when deps are absent.
Docs: research bundle 08 gains a per-deployment adaptivity section; 07 and the
crate README point at the harness; ADR-289 added and indexed.
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01WEXNqzs7UsfNFBcP5yW21p
- .claude/commands/route.md and flywheel.md -- the two CLI subcommands
added alongside darwin/router/flywheel wiring never got matching
guidance files (unlike doctor/review-diff), so they weren't fully
wired into the harness's own MCP tool listing. Added, following the
existing pattern.
- CLAUDE.md: note the crate + harness are both published now (crates.io
v0.3.1, npm v0.1.0).
- New ADR-286 documenting the harness's MetaHarness scaffold + the
darwin/router/flywheel wiring decision, following the ADR-182/ADR-285
precedent (every harness in this repo gets one).
- docs/adr/README.md: index rows for ADR-286 and the crate's ADR
(287 -- see the next commit for the renumbering-from-283 story).
Mints a real MetaHarness (via vendor/metaharness's published `npx
metaharness analyze --scaffold`, template vertical:coding, host
claude-code) for the wifi-densepose-sar crate: architect/implementer/
reviewer/test-writer agents, doctor/review-diff commands, MCP server,
Claude Code plugin -- following the same pattern as harness/ruview/
(ADR-182) and harness/homecore/ (ADR-285).
Adds real wiring for the three pieces this was scoped around:
- Darwin Mode (@metaharness/darwin) -- wired by the scaffold itself
(npm run evolve / evolve:dry).
- Router (@metaharness/router) -- src/router.ts, a real k-NN
cost-optimal Router over two example model tiers. Its labelled
examples are illustrative seed data (see the file's honesty note),
not measured eval-log observations; the routing mechanism itself is
real and tested.
- Flywheel (@metaharness/flywheel) -- src/flywheel.ts, the real
propose/evaluate/gate/promote loop wired with a SYNTHETIC proposer
and evaluator (dataSource: 'SYNTHETIC', no model call). Proves the
wiring end-to-end: a real signed, independently-replayable lineage,
promoting each generation once the evaluator's noopRate actually
moves (the default gate requires it to strictly improve -- a
constant noopRate, even a "good" one, blocks every promotion
forever, which the first version of this evaluator hit and the
final version fixes).
14/14 tests pass (5 router + 5 flywheel + 4 install-smoke), `npm run
build` clean under strict TypeScript, CLI commands (route, flywheel)
verified manually. `.harness/manifest.json` is stale relative to the
router/flywheel additions -- this scaffold has no manifest:update
script (unlike harness/homecore/); documented as a known gap in the
harness's own README.
* docs(adr): deep review of the RuView npm surface — ADR-263/264/265 optimization strategies
ADR-263 — @ruvnet/ruview@0.1.0 harness review (O1–O9):
- HIGH: claim-check CLI fails open on empty input (no --text/--file -> PASS exit 0)
- HIGH: MCP stdio server head-of-line blocking (spawnSync verify/calibrate up to 600s)
- MEASURED: optionalDependencies triple the cold npx install (4 pkgs/620kB/71 files
vs 1 pkg/172kB/22 files with --omit=optional) for a path that never imports them
- maxBuffer truncation, python -c port interpolation, version drift, duplicate skills,
guardrail METRIC_TERMS substring false positives ('map'/'F1' — found by dogfooding
claim-check on these very ADRs), zero CI
ADR-264 — @ruvnet/rvagent@0.1.0 + @ruv/ruview-cli review (O1–O9), verified against
the published registry tarball:
- HIGH: exports.require -> dist/index.cjs which is never built nor published
- MEASURED: 44 dead source-map files = 62,698B of the 188kB unpacked payload
- stdio-only server described as dual-transport; mixed dot/underscore tool names;
double Zod validation + hand-duplicated advertised schemas; 2-fd leak per training
job; unbounded body in the unwired HTTP scaffold; dead detectCogBinary candidates;
ruview bin-name collision
ADR-265 — cross-cutting npm distribution strategy: npm-packages.yml CI matrix
(test + pack-content/size gate + tarball-install smoke test), publish-from-CI-only
with npm provenance, version single-sourcing from package.json, bin/namespace
ownership (ruview bin belongs to @ruvnet/ruview), claim-check on package READMEs.
Docs only — no runtime code changed. Index/CHANGELOG/CLAUDE.md/README counts updated.
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01WrGfTGKv1oWZ6iwXZACULz
* fix(npm): implement ADR-263/264/265 — harness fail-closed + async MCP, rvagent packaging/transport/naming, npm CI+provenance gate
ADR-263 (@ruvnet/ruview 0.2.0), O1-O9:
- claim-check fails closed on empty input (CLI exit 2, empty_text tool error)
- MCP stdio server dispatches tools/call asynchronously (promise-based spawn);
ping answers while a 3s fake verify runs — pinned by new e2e test
- optionalDependencies dropped: cold npx installs exactly 1 package
(MEASURED: was 4 pkgs/620kB/71 files via npm i in a clean prefix)
- bounded rolling output tails replace spawnSync 1MiB maxBuffer
- node_monitor port passed via sys.argv, never spliced into python -c source
- serverInfo.version read from package.json; resources/prompts stubs
- skills single-sourced: prepack sync script generates .claude/skills/ copies
- which() = memoized dep-free PATH scan
- tools underscore-canonical (ruview_claim_check, ...) + dotted aliases
- guardrail precision: word-boundary map/f1/auc/iou, code-span + F1/O2 label
scrubbing, quantitative-claims-only; packaging reproducer hints
- 30/30 tests (was 17), incl. concurrency e2e + fail-open regression pins
ADR-264 (@ruvnet/rvagent 0.2.0), O1-O9:
- exports fixed: types-first, phantom dist/index.cjs require target removed
- tarball map-free: 127,704B unpacked / 46 files / 0 maps (MEASURED,
npm pack --dry-run; was 188kB incl. 44 maps referencing unshipped src)
- Streamable HTTP actually wired behind RVAGENT_HTTP_PORT: one transport +
one MCP server per session (mcp-session-id routing), 1MiB body cap (413),
port-aware localhost origin gate; dual-transport description now true
- tools renamed underscore-canonical with dotted router-only aliases
- single Zod validation gate; advertised inputSchema generated from the same
Zod source (zod-to-json-schema)
- train_count: parent log fds closed (was leaking 2/job); job records
persisted to <jobsDir>/<id>.json (job_status survives restarts); bounded
log-tail reads
- detectCogBinary probes its candidates instead of dead-coding them
- version from package.json; @types/express dropped; @types/jest -> 29
- README rewritten to match reality (no phantom subcommands/policy layer)
- 99/99 jest tests (incl. new session/body-cap suite + previously-broken
manifest suite); stdio handshake + HTTP session flow smoke-tested live
ADR-265 D1-D4:
- .github/workflows/npm-packages.yml: 3-package x Node 20/22 gate — tests,
version-literal grep (D3), pack-content/size gate, tarball-install smoke
test (catches the ADR-264 F1 class), README claim-check (D4)
- .github/workflows/ruview-npm-release.yml: publish from CI only with
npm publish --provenance
- @ruv/ruview-cli bin renamed ruview-cli (ruview bin belongs to
@ruvnet/ruview); version single-sourced
- ci.yml NODE_VERSION 18 -> 20
ADR statuses updated to Accepted/implemented; harness manifest re-pinned;
ADR-263/264/265 + both package READMEs pass claim-check.
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01WrGfTGKv1oWZ6iwXZACULz
* perf(rvagent): lazy-load HTTP transport + memoize generated tool schemas
stdio time-to-first-response ~242ms -> ~189ms (-22%; MEASURED, median of
repeated initialize round-trips against dist/index.js in this container).
- ./http-transport.js now imported lazily inside the RVAGENT_HTTP_PORT
branch: it chain-loads the MCP SDK streamableHttp module (~48ms MEASURED
via per-module import() timing) which the default stdio path never uses
- toolInputJsonSchema memoized per tool: schemas are static for the process
lifetime; under the session-per-server HTTP model every session calls
tools/list, so stop re-walking the Zod tree each time
No behavior change: 99/99 jest tests; HTTP session flow re-smoke-tested
through the lazy import path (initialize -> 200 + mcp-session-id).
Profiled @ruvnet/ruview too and left it alone: 50ms CLI startup vs ~29ms
bare 'node -e ""' floor on the same box (MEASURED) — already near the
interpreter floor with zero dependencies.
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01WrGfTGKv1oWZ6iwXZACULz
* ci(ruview-cli): pass jest --passWithNoTests so the private no-test package doesn't fail the npm-packages matrix
Co-Authored-By: claude-flow <ruv@ruv.net>
* fix(npm): address 10 verified review findings in harness + rvagent before 0.2.0 publish
harness/ruview (@ruvnet/ruview):
- guardrails: digit gate now sees numbers inside code spans; F1-style
metric tokens followed by ':' or a nearby number are no longer scrubbed
(fail-open regressions in the honesty gate)
- mcp-server: tools/call requests serialize through a FIFO promise chain
(hardware/mutating tools never overlap) while ping/tools/list stay
immediate; stdin close drains in-flight responses before exit
- tools: which() no longer memoizes negative lookups
tools/ruview-mcp (@ruvnet/rvagent):
- index: realpath invoked-directly guard — library import no longer
connects a stdio transport to the consumer's process
- http-transport: explicit allowedOrigins is exact-match only (localhost
any-port convenience applies only with no configured allowlist);
session map gains maxSessions=64 + 5min idle TTL sweep
- train-count: job records persist the child pid and reconcile stale
'running' status after a server restart (exit-code marker or dead pid)
- config: cog binary candidates ordered by process.arch
.github/workflows/ruview-npm-release.yml: port the full ADR-265 D1 gate
(version-literal check, unpacked-size budget, tarball-install smoke test)
from npm-packages.yml so the publish path enforces what the header claims.
Tests: harness 30→36, rvagent 99→112, all passing.
Co-Authored-By: claude-flow <ruv@ruv.net>
---------
Co-authored-by: Claude <noreply@anthropic.com>
A host-portable RuView agent harness minted via MetaHarness and hardened
per ADR-182. Published as @ruvnet/ruview@0.1.0 (bare `ruview` blocked by
npm's typosquat filter → scoped fallback).
What it does:
- 6 fail-closed `ruview.*` tools (onboard, claim_check, verify,
node_monitor, calibrate, node_flash) exposed as CLI verbs + a
dependency-free MCP stdio server.
- The "prove everything" rule made executable: `ruview.claim_check`
flags untagged accuracy claims and the retracted "100%" framing.
- 5 host-neutral skills (onboard/provision-node/calibrate-room/
train-pose/verify) + bundled .claude/ config + provenance manifest.
Validated: 17/17 unit tests, live MCP handshake, `ruview.verify` ran the
real verify.py to VERDICT: PASS, clean `npx @ruvnet/ruview` from registry.
Packs to 16.7 kB / 21 files; kernel+host are optionalDependencies so the
operator tools install lightweight.
README: documented as the portable, multi-host companion to the in-repo
plugins/ruview/ Claude Code plugin (not a replacement).