Skip to content

PixelRAG → Rust port on ruvector: text + visual + real-time video RAG (no stubs)#610

Open
ruvnet wants to merge 28 commits into
mainfrom
feat/pixelrag-rust-port
Open

PixelRAG → Rust port on ruvector: text + visual + real-time video RAG (no stubs)#610
ruvnet wants to merge 28 commits into
mainfrom
feat/pixelrag-rust-port

Conversation

@ruvnet

@ruvnet ruvnet commented Jun 26, 2026

Copy link
Copy Markdown
Owner

Ports PixelRAG (visual RAG) to Rust on the ruvector substrate, plus a standalone public package (ruvnet/rupixel, wired as external/rupixel) with live in-browser demos. Everything ships as working code — grep -r 'unimplemented!' crates/pixelrag-*/src is empty.

What's here

  • Crates: pixelrag-core (pipeline + ruvector HNSW/IVF-Flat index adaptor), pixelrag-encoder (real all-MiniLM-L6-v2 text + CLIP visual via WASM/CPU sidecars), pixelrag-render (headless Chrome→screenshots), pixelrag-cli (benchmark harness: text / visual / compare modes).
  • Measured (real models, CPU): text RAG 8/8 top-1; visual RAG (CLIP) 8/8 native / 7/8 in-browser; both 1.00 on the shared 8-doc compare set. See docs/research/pixelrag/ + rupixel docs/BENCHMARK.md.
  • Real-time video (ADR-265/266/267): browser demo (WebGPU CLIP + keyframe gating + streaming Qwen3-VL captions) with secure key handling — BYO-key in the browser, server-side describe-proxy reads the key from env (never committed).
  • ADRs: 264 (port), 265 (video pipeline), 266 (MidStream scale tier + key-proxy), 267 (PhotonLayer experimental, off critical path).
  • Public: rupixel@0.1.0 on npm; live demos on GitHub Pages.

Honest scope

Visual encoder is CLIP ViT-B/32 (CPU baseline); Qwen3-VL/ColPali is the documented GPU upgrade, not stubbed. Benchmarks are small real eval sets, labeled as such.

CI note

Per the repo's known CI state, the structurally-broken shards (dependency-review, core-and-rest) can be ignored; the pixelrag crates build clean (cargo build -p pixelrag-core -p pixelrag-encoder -p pixelrag-cli -p pixelrag-render).

🤖 Generated with claude-flow

claude and others added 28 commits June 18, 2026 02:00
… detector, receipts (ADR-260 Phase 1)

Pure-Rust, dependency-light, deterministic learned-optical-frontend core:
- complex/fft: in-house radix-2 2D FFT (bit-reproducible, no external FFT lib)
- field/mask: image->scalar field, phase-only learned mask (identity/random/lens)
- propagate: Fresnel, Fraunhofer, angular-spectrum scalar diffraction
- detector: intensity capture + seeded shot/read noise, binning, quantization
- metrics: MSE/PSNR, compression ratio, frame-similarity, spectrum embedding
- receipt: BLAKE3-bound experiment receipts + verify (determinism invariant §21)
21 unit tests + doctest passing.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01PjRKJMFe6yoNY3SMVEieHy
…ss (ADR-260 Phase 2/4)

- synthetic: deterministic 4-class shape dataset (no MNIST per ADR-260 §20.2)
- decoder: feature pooling + nearest-centroid digital backend (exact param count)
- learn: seeded block hill-climbing mask optimizer against task loss; learned
  mask provably dominates its random start (acceptance gate §17.2)
- baselines: digital/random/learned variants + compression showcase
- Result: at a 2x2 (4-pixel) sensor, learned mask 1.00 vs random 0.80 vs
  digital 0.65 test accuracy — same task, 64x fewer sensor pixels (§16.3)

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01PjRKJMFe6yoNY3SMVEieHy
…mentation (ADR-260)

Stub crates registered as workspace members so each is independently
buildable/testable while the implementation swarm fills them in.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01PjRKJMFe6yoNY3SMVEieHy
…vacy, CLI demos (ADR-260 Phases 2-4)

photonlayer-ruvector (22 tests): 32-dim experiment embeddings (mask histogram +
frame spectrum), cosine nearest-experiment recall, Fiedler-spectral pass/fail
boundary analysis, mask-family coherence gates, verifying receipt store.

photonlayer-wasm (17 tests): 5-view browser pipeline (incoming/mask/masked/
sensor + frame hash) with min-max u8 encoders; in-browser verify_receipt_json
(anti-swap); default_config_json.

photonlayer-bench (9 tests): + verification module (FAR/FRR/EER) and privacy
module (linear reconstruction-attack leakage). Learned mask EER 0.001 vs random
0.133; optical capture reduces reconstruction PSNR vs identity.

photonlayer-cli: bench / barcode / edge / privacy-gate / verify-receipt demos
with ASCII frame rendering. Barcode decodes all 4 classes from non-human-readable
frames; privacy-gate emits a verifying RVF receipt. Clean build, zero warnings.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01PjRKJMFe6yoNY3SMVEieHy
…ry (ADR-260 security)

Add OpticalConfig::validate() + MAX_GRID_DIM cap as the security choke point:
reject non-power-of-two/oversized grids, non-finite or non-physical optical
params, and binning=0 before any allocation or FFT. Enforced in OpticalField::
from_image (pre-allocation) and in the WASM run_trace boundary (dimension guard
+ config.validate) to block allocation-DoS and 32-bit usize overflow from a
malicious config_json. +2 core tests (now 23).

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01PjRKJMFe6yoNY3SMVEieHy
…ator

Formalizes the architecture, pipeline, crate layout, RuVector experiment-memory
schema, RVF receipt binding, benchmarks, acceptance gates, the determinism
invariant, and the application/positioning/ethics framing (front-end thesis;
industrial sensors -> drone preprocessing -> medical research -> consented
verification; non-goal: mass-surveillance face ID).

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01PjRKJMFe6yoNY3SMVEieHy
…ivacy verification), SOTA research brief

ADR-261: canonical PhaseMask exchange format, determinism invariant (in-house
FFT + seeded RNG + BLAKE3), and import replay-verification.
ADR-262: privacy-preserving consented verification — FAR/FRR/EER, reconstruction-
attack leakage metric, receipt provenance, RuVector governance; documents the
measured numbers (learned EER 0.001 vs 0.133; optical reduces reconstruction PSNR)
and the mass-surveillance non-goal.
sota.md: D2NN, differentiable optics (TorchOptics/waveprop/diffractsim), hybrid
DOE+CNN compression, edge-enhanced D2NN, 2026 full-Stokes metasurface+U-Net;
credible-vs-overclaimed table; reference->component mapping; feasibility ranking.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01PjRKJMFe6yoNY3SMVEieHy
…ark; fix wasm lint

- README (crate/repo face): positioning ("captures the answer"), the auditable
  optical-compression wedge, measured compression-sweep table, honest "do not
  claim yet" scope.
- docs/research/photonlayer/ASSESSMENT.md: full positioning, use-case risk table,
  prove-next roadmap (energy model, harder datasets, reconstruction-attack suite,
  hardware bridge), demos, products, scoring, acceptance test, references.
- tests/more_data_bench.rs: larger-N compression sweep (1/4/9/16-px sensors,
  40 samples/class, 300 iters) + WIN regression guard. Measured: at 64x reduction
  learned=0.988 vs random=0.738.
- Fix photonlayer-wasm useless-comparison lint -> meaningful monotonicity check.
…tical)

Hot-path optimization for the mask-learning loop, which propagates thousands
of fields through one fixed config. The config-only transfer function H was
recomputed on every call, and every propagate() cloned the field buffer.

- Propagator precomputes H once per (config,w,h); propagate_into() runs the
  forward FFT -> xH -> inverse FFT in place (no per-call clone).
- Output is bit-for-bit identical to the free propagate() (asserted in
  cached_propagator_is_bit_identical, always-on).
- Measured 1.70x over the naive path at 64x64 x3000 (release):
  naive=615ms -> cached+inplace=361ms. Proof is an --ignored timing test
  (debug wall-clock is meaningless); correctness gate runs in the default suite.

Also lands:
- ADR-263 PhotonLayer FiberGate (transmission-matrix MMF backend; receipt-
  verified, NOT zero-knowledge; non-square T; nalgebra column-major contract).
- docs/research/photonlayer/APPLICATIONS.md — task-trained-sensors positioning,
  application areas, viral demos, product path, platform acceptance test.

Co-Authored-By: claude-flow <ruv@ruv.net>
…fferential ablation (M2)

Adds an honest, reproducible real-data benchmark for the learned optical
frontend (ADR-260 M2), replacing the synthetic-only 4-class evaluation that
ADR-260 itself flagged as a scientific-integrity risk.

New modules (photonlayer-bench):
- mnist.rs    : parses raw uncompressed IDX (verified magic 0x803/0x801),
                downsamples 28x28 -> 20x20 centered in a 32x32 power-of-two
                optical grid. Dataset is fetched once into a gitignored cache
                (NOT vendored); loader has zero network/decompression deps.
- diffdetect.rs: differential-detection readout (Li/Ozcan arXiv:1906.03417) -
                10 positive + 10 negative detector regions, score I+_k - I-_k.
- mnist_bench.rs: trains one phase mask (seeded block hill-climbing) and runs
                the full acceptance comparison + ablation on the IDENTICAL mask.

Integration test (mnist_differential_bench.rs, NOT a standalone bin to avoid
the CrowdStrike AV os-error-5 on fresh exes): fast always-on smoke guard +
#[ignore] heavy run with a documented command.

Measured (deterministic, seed 0x6e157, 4000 train / 2000 blind test, balanced):
  full-image baseline (1024 px, 10240-param centroid)  0.7540
  optical compressed  (  64 px,   640-param centroid)  0.7420
  delta vs baseline                                   -0.0120  (PASS, allows -0.02)
  sensor pixel reduction                               16.0x   (>= 16x)
  digital MAC reduction                                16.0x   (>= 10x)
  learned vs random mask (decoded)                     +0.0925
ACCEPTANCE (user's relative-to-baseline test): PASS.

Honest caveats reported in-table: this is a SINGLE hill-climbed phase mask +
tiny decoder (single-layer optical compression). The Li/Ozcan ~97% MNIST figure
is a 5-layer diffractive net trained end-to-end by backprop with differential
readout as the final layer; multi-layer + gradient is future work. The
optics-only argmax differential lever is reported as a transparency floor (the
mask is trained for the decoder readout, not the argmax readout). No absolute
SOTA claim is made.

cargo test -p photonlayer-core (23 pass) and -p photonlayer-bench --lib
(14 pass) green; clippy clean.

Co-Authored-By: claude-flow <ruv@ruv.net>
…ng + citations into ASSESSMENT

Adds the measured real-data MNIST table (optical 74.20% vs full-image baseline
75.40%, -1.20pp, 16x sensor + 16x MAC reduction; +9.25pp learned-vs-random),
the verbatim non-overclaiming positioning paragraph (competitive single-layer
optical compression, NOT a new accuracy SOTA), the must-avoid language list,
and the closest architectural citations (Wirth-Singh arXiv:2406.06534 primary,
Bezzam 2206.01429, Lin Science 2018, Li/Ozcan 1906.03417, Wang 2507.17374).

Co-Authored-By: claude-flow <ruv@ruv.net>
…emult + precompute FFT twiddle tables

OPT-A (bit-identical): replace `fft_2d + fftshift_2d` in both Fraunhofer
paths (free `fraunhofer()` and `Propagator::propagate_into`) with a ±1
checkerboard premultiply `(-1)^(x+y)` before the transform. By the DFT
shift theorem, FFT of the premultiplied input equals fftshift of the FFT,
eliminating the fftshift's full-buffer alloc + quadrant copy. True negate
(`Complex::ZERO - c`) is exact ±1.0 -> element-for-element identical to the
old sequence (new test `checkerboard_premult_equals_fft_then_fftshift`).

OPT-B (deliberately changes bits, determinism gain): precompute a per-
dimension `TwiddleTable` (`exp(sign·2π·j/n)` for j in 0..n/2) and INDEX it
by stride per butterfly instead of accumulating `w *= wlen`. Kills the f32
drift the accumulation injected and recomputes angles once per 2D FFT
instead of per row/column. Proven: FFT is bit-for-bit reproducible across
runs, and max-abs error vs an f64 reference DFT does NOT increase
(it decreases — drift removed). No hardcoded golden hashes/values in the
repo to update; re-run-determinism tests stay valid by construction.

Measured (release, 64x64 x3000, --ignored --nocapture):
  fraunhofer OPT-A+B: old(fft+fftshift,accum-twiddle)=210.5ms ->
  new(checkerboard+table)=116.1ms = 1.81x, max_diff_vs_old=5.7e-6 (f32 noise).
M1 cached-propagator benchmark still 2.00x and bit-identical.

All 27 photonlayer-core unit tests + propagation bit-identical gate green;
photonlayer-ruvector / photonlayer-bench / photonlayer-cli build and tests
green. Determinism invariant preserved (scalar cos/sin FFT, no FMA/SIMD/RFFT).

Co-Authored-By: claude-flow <ruv@ruv.net>
…ench — isolates the differential lever

The M2 benchmark previously reported the differential-vs-plain argmax delta as a
small (+0.10pp) transparency footnote, because the single mask was trained for
the DECODER objective, not the argmax readout. That understated the Li/Ozcan
differential-detection mechanism. This adds a SECOND, clearly-labeled mask
trained directly for the argmax-differential objective, so the lever is shown in
isolation. Config A is unchanged and remains the product/acceptance headline.

Two masks, two objectives — A proves task-useful compression (the product
claim); B isolates the differential-detection lever (the mechanism). Both fully
deterministic (stated seeds), both reproduced by the integration test.

Measured (real MNIST, 4000 train / 2000 blind test, on current core HEAD):
  CONFIG A (decoder objective, seed 0x6e157) — product/acceptance:
    full-image baseline (1024 px)  0.7540
    optical compressed  (  64 px)  0.7305   (-2.35pp; 16x sensor + 16x MACs)
    learned vs random decoded      +0.0810  (WIN guard, asserted)
  CONFIG B (argmax-diff objective, seed 0x6e15c) — mechanism, NO decoder:
    plain argmax I+_k              0.1840
    differential argmax I+ - I-    0.3490
    differential lever delta       +0.1650  (asserted >= +0.05)
    NOTE: absolute accuracy is single-layer optics-only (no decoder) and modest
    by construction; the +0.1650 isolates the lever, NOT a headline accuracy.

No SOTA/beats language; no cherry-picking — both configs are in the printed table.

NOTE on Config A drift: an earlier measurement on commit 69424ec read optical
0.7420 (-1.20pp, acceptance PASS). The core FFT crate changed underneath us
(cbcd0eb, "precompute FFT twiddle tables") which slightly altered the
diffraction output for ALL FFT paths (AngularSpectrum included), shifting Config
A to 0.7305 (-2.35pp). Acceptance is REPORTED, not hard-asserted, so the test
stays green; the honest current-core number is -2.35pp. Flagged to the core
author — the twiddle-table change is not bit-identical to the pre-cbcd0eb2 FFT.

Scope: photonlayer-bench only (mnist_bench.rs + integration test). Core untouched.
cargo test -p photonlayer-bench --lib (14) + smoke green; full #[ignore] passes
(647s); clippy clean.

Co-Authored-By: claude-flow <ruv@ruv.net>
…eiling

Adds run_mnist_config_a (fast Config-A-only harness) and a permanent #[ignore]
iteration sweep proving the -2pp acceptance line is NOT a training-budget issue
on the drift-corrected (post-cbcd0eb2) FFT core. Measured (seed 0x6e157,
4000 train / 2000 blind test):
  iters 1500 -> optical 73.05% (-2.35pp)
  iters 3000 -> optical 73.25% (-2.15pp)
  iters 4500 -> optical 73.20% (-2.20pp)
The block hill-climber has converged; the residual ~2pp gap is an OPTIMIZER
limit. Closing it (and reaching ~85-89%) requires analytic gradient descent
through the diffraction operator (Propagator::backward_into with conj(H)) — the
documented roadmap keystone, not a tonight change. No fabricated numbers; the
honest single-mask result is reported, not asserted to PASS.

Co-Authored-By: claude-flow <ruv@ruv.net>
…izer-ceiling honesty

The pre-OPT-B -1.20pp figure was stale after the twiddle-table FFT change.
Updates Config A to the true converged number on the optimized core
(73.05% / -2.35pp at 16x/16x; +8.10pp learned-vs-random), adds Config B
(+16.50pp differential lever), and states the honest framing: the gap is an
optimizer ceiling (sweep: 1500/3000/4500 -> -2.35/-2.15/-2.20pp), closeable
only by analytic gradient descent (backward_into with conj(H)) — the roadmap
keystone, with ~85-89% headroom. No PASS asserted that the method cannot reach.

Co-Authored-By: claude-flow <ruv@ruv.net>
…uvector

ADR-264 proposes porting StarTrail-org/PixelRAG (visual/pixel-native RAG) to
Rust on the ruvector substrate. This lands the scaffold and a runnable M1
plumbing slice.

M0 — five crates (pixelrag-core/encoder/render/serve/cli), registered in the
workspace, all building clean. Darwin benchmark harness (.metaharness/bench.json,
canonical + verifies OK) with a labeled subset fixture and BENCH.md.

M1 — pixelrag-core index adaptor wired to ruvector_core::VectorDB; deterministic
SYNTHETIC embedder (plumbing only — real Qwen3-VL-Embedding-2B is blocked on
weights/GPU); pixelrag-cli benchmark harness runs end-to-end and emits
recall/ndcg/mrr + latency/build/memory.

HONESTY: all bench numbers are subset-fixture + synthetic-embedding plumbing
validation, NOT semantic retrieval quality. True recall vs the Python baseline,
the render port (M2), and serve (M3) remain to be done; tracked by horizon.

Co-Authored-By: claude-flow <ruv@ruv.net>
…end to evolve

Adds a second, real ANN backend (ruvector-rairs IvfFlat) alongside the M1 HNSW
path, selectable via `pixelrag-cli benchmark --index-backend ivf-flat` and the
Config IndexBackend enum (default stays HNSW).

IVF needs train-then-add (k-means), unlike HNSW's incremental insert, so the
index adaptor buffers embeddings and trains+adds on a finalize step; nclusters is
clamped for tiny corpora so the subset fixture doesn't panic. Deterministic seed.

Both backends run end-to-end on the subset fixture (synthetic embeddings):
ivf-flat is ~8x lower search latency and faster build than hnsw but ~1.5x memory
per doc — a genuine (latency x memory) tradeoff for darwin's Pareto loop. recall
and ndcg are identical and trivial (k >= 6-doc corpus).

HONESTY: still subset-fixture + synthetic-embedding plumbing — NOT semantic
retrieval quality, and the tradeoff is directionally plausible but noisy at 6
docs. Real recall and a robust frontier need Qwen3-VL-2B + a real-scale corpus.

Co-Authored-By: claude-flow <ruv@ruv.net>
Public standalone repo + npm CLI for the PixelRAG Rust port (npx rupixel).
Canonical buildable crates remain in crates/pixelrag-*; external/ is excluded
from the workspace, so this is a vendored reference snapshot.

Co-Authored-By: claude-flow <ruv@ruv.net>
Make it real and drop every stub.

Real embeddings: pixelrag-encoder gains a real SidecarEmbedder running
all-MiniLM-L6-v2 (sentence-transformers) via a transformers.js WASM/CPU sidecar
(crates/pixelrag-cli/sidecar) — no GPU, no weights blocker. pixelrag-cli bench
gains --embedder real (default) with a dynamic embedding dim.

Real eval: tests/fixtures/pixelrag is now 30 passages across 6 topics with 12
paraphrase queries + qrels (semantic, not keyword). Measured (real MiniLM):
recall@10=1.00, ndcg@10=0.96, mrr=1.00; search p50 0.40ms (ivf-flat) / 1.17ms
(hnsw).

No stubs: deleted pixelrag-render and pixelrag-serve (entirely placeholder) and
removed every unimplemented!() from the remaining crates — encoder Qwen/ONNX/
Python stub backends, core M2 load/render methods, cli index/search stub
subcommands. `grep -r 'unimplemented!' crates/pixelrag-*/src` is now empty; the
three remaining crates (core/encoder/cli) build clean.

Honest scope unchanged: this is real TEXT-semantic retrieval. The visual
(screenshot + Qwen3-VL) path is roadmap prose, not stubbed code.

Co-Authored-By: claude-flow <ruv@ruv.net>
…o, no stubs)

Co-Authored-By: claude-flow <ruv@ruv.net>
…g-render, visual bench

- pixelrag-render: real headless Chrome/Edge rendering via render sidecar (re-added
  to workspace; the old stub crate stays deleted).
- Visual benchmark (cli --mode visual): shells the CLIP sidecar (clip-vit-base-patch32,
  WASM/CPU) to embed rendered doc screenshots + text queries into one space, indexes
  image vectors in ruvector, measures text->image retrieval.
- Measured over 8 rendered document screenshots (8 paraphrase queries):
  top-1=1.00, recall@10=1.00, ndcg@10=1.00, mrr=1.00.
- Still no stubs (grep unimplemented! is empty). CLIP is a real visual encoder;
  Qwen3-VL/ColPali remains a GPU drop-in upgrade, documented not stubbed.

Co-Authored-By: claude-flow <ruv@ruv.net>
…P demo)

Co-Authored-By: claude-flow <ruv@ruv.net>
Same 8 docs / 8 queries / qrels in both modalities (extracted page text +
rendered screenshots) for the traditional-vs-visual RAG benchmark. Measured:
both 1.00 top-1/ndcg/mrr on this clean corpus (text RAG p50 0.62ms, visual 0.52ms).

Co-Authored-By: claude-flow <ruv@ruv.net>
…nchmark)

Co-Authored-By: claude-flow <ruv@ruv.net>
…ADME)

Co-Authored-By: claude-flow <ruv@ruv.net>
…escribe sidecars

ADR-265 (video pipeline: frame sampling + keyframe gating + CLIP), ADR-266
(MidStream Rust ingest tier + server-side key-proxy), ADR-267 (PhotonLayer optical
front-end, experimental/off-path). New sidecars: render (headless Chrome→frames),
clip (CLIP image+text), describe-proxy (secure server-side OpenRouter proxy reading
the key from env — never committed). Demo + describe validated; key is BYO in the
browser, env-only in the proxy.

Co-Authored-By: claude-flow <ruv@ruv.net>
…emo)

Co-Authored-By: claude-flow <ruv@ruv.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants