ruvector/crates/ruvector-learning-wasm
rUv eafba64fa5
fix(security): RUSTSEC advisories + clippy hardening in RuVector (#504)
* fix(security): RUSTSEC advisories + clippy hardening in RuVector

- Replace all bare `partial_cmp().unwrap()` calls on f32/f64 with
  `.unwrap_or(Ordering::Equal)` to prevent panics on NaN values in
  sorting/max-by operations across ruvllm, ruvector-dag, prime-radiant,
  and rvagent-wasm (12 sites in production code).
- Add input validation guards to the HTTP search endpoint: reject k=0,
  k > 10_000, empty vectors, and vectors exceeding 65_536 dimensions,
  preventing memory exhaustion via unbounded allocations.
- Harden LocalFsBackend::execute in rvagent-cli with env_clear() +
  safe-env allowlist (SEC-005), deadline-based timeout enforcement, and
  1 MB output truncation, matching the security posture of LocalShellBackend.
- Remove 129 occurrences of the deprecated `unused_unit = "allow"` lint
  and 3 occurrences of the removed `clippy::match_on_vec_items` lint from
  Cargo.toml files workspace-wide; both are no-ops in current Rust/Clippy.
- All 653+ tests across ruvector-core, ruvector-server, ruvector-dag,
  rvagent-cli, and prime-radiant pass with zero failures.

Note: `bytes` is already at 1.11.1 (>= 1.10.0); `paste` 1.0.15 is a
transitive dependency with no semver fix available upstream; `cargo audit`
returns clean.

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

* fix(ci): cargo fmt + restore workspace unused_unit lint allow

- Run cargo fmt --all across all 9 files that drifted from rustfmt style
  (prime-radiant/energy.rs, ruvector-dag/bottleneck.rs+reasoning_bank.rs,
   ruvector-server/points.rs, ruvllm/pretrain_pipeline.rs+report.rs+registry.rs,
   rvagent-cli/app.rs, rvagent-wasm/gallery.rs)
- Add [workspace.lints.clippy] unused_unit = "allow" to root Cargo.toml;
  the per-crate entries removed in the security commit were still needed —
  moving to workspace-level is cleaner and restores -D warnings CI pass

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

* fix(ci): remove unneeded unit return type in ruvix bench

Removes `-> ()` from the Fn bound in run_benchmark_with_kernel
(crates/ruvix/benches/src/ruvix.rs:50) — triggers clippy::unused_unit
under -D warnings. Clippy prefers `Fn(&mut Kernel)` without explicit
unit return.

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

* fix(ci): resolve rustfmt and clippy unused_unit failures

- Run cargo fmt --all to fix long closure formatting in 9 files
  (energy.rs, bottleneck.rs, reasoning_bank.rs, points.rs,
  pretrain_pipeline.rs, report.rs, registry.rs, app.rs, gallery.rs)
- Add unused_unit = "allow" to [lints.clippy] in ruvix-bench and
  ruvector-mincut Cargo.toml files to suppress the unused_unit lint
  that was previously suppressed globally and now fires on two
  Fn(&mut T) -> () and FnMut() -> () function bounds

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-05-23 05:40:24 -04:00
..
pkg docs(wasm): add comprehensive SEO-optimized README files for npm packages 2026-01-01 06:35:55 +00:00
src style: apply rustfmt across entire codebase 2026-01-28 17:00:26 +00:00
Cargo.toml fix(security): RUSTSEC advisories + clippy hardening in RuVector (#504) 2026-05-23 05:40:24 -04:00
README.md feat(wasm): add 5 exotic AI WASM packages with npm publishing 2026-01-01 06:31:11 +00:00

ruvector-learning-wasm

Ultra-fast MicroLoRA adaptation for WASM - rank-2 LoRA with <100us latency for per-operator learning.

Installation

npm install ruvector-learning-wasm

Overview

This package provides Low-Rank Adaptation (LoRA) matrices optimized for WebAssembly execution. It enables real-time per-operator-type learning in query optimization systems with minimal latency overhead.

Key Features

  • Rank-2 LoRA: Minimal parameter count (2d parameters per adapter)
  • Per-Operator Scoping: Separate adapters for 17 different operator types
  • <100us Adaptation: Instant weight updates for real-time learning
  • WASM-Optimized: Compiled to WebAssembly for near-native performance
  • Zero-Allocation Hot Paths: Pre-allocated buffers for performance-critical operations

JavaScript API

WasmMicroLoRA

The main LoRA engine for single-adapter use cases.

import init, { WasmMicroLoRA } from 'ruvector-learning-wasm';

// Initialize WASM module
await init();

// Create a new MicroLoRA engine
const lora = new WasmMicroLoRA(
  256,    // dim: Embedding dimension (max 256)
  0.1,    // alpha: Scaling factor
  0.01    // learning_rate: Learning rate for adaptation
);

// Forward pass with typed array
const input = new Float32Array(256).fill(1.0);
const output = lora.forward_array(input);

// Adapt with gradient
const gradient = new Float32Array(256).fill(0.1);
lora.adapt_array(gradient);

// Get statistics
console.log('Forward count:', lora.forward_count());
console.log('Adapt count:', lora.adapt_count());
console.log('Delta norm:', lora.delta_norm());
console.log('Parameter count:', lora.param_count());

// Reset engine
lora.reset();

Zero-Allocation API

For performance-critical loops, use the buffer-based API:

const lora = new WasmMicroLoRA(256, 0.1, 0.01);

// Get buffer pointers
const inputPtr = lora.get_input_ptr();
const outputPtr = lora.get_output_ptr();
const dim = lora.dim();

// Create views into WASM memory
const memory = new Float32Array(lora.memory.buffer);
const inputView = new Float32Array(memory.buffer, inputPtr, dim);
const outputView = new Float32Array(memory.buffer, outputPtr, dim);

// Write input directly
inputView.set(myInputData);

// Forward pass (zero allocation)
lora.forward();

// Read output directly
const result = outputView.slice();

// Adapt using input buffer as gradient
lora.adapt();

// Adapt with reward (for RL)
lora.adapt_with_reward(0.5); // improvement ratio

WasmScopedLoRA

Per-operator-type LoRA manager with 17 specialized adapters plus category fallback.

import init, { WasmScopedLoRA } from 'ruvector-learning-wasm';

await init();

const scopedLora = new WasmScopedLoRA(
  256,    // dim
  0.1,    // alpha
  0.01    // learning_rate
);

// Operator types (0-16)
const HNSW_SCAN = 2;
const HASH_JOIN = 5;
const FILTER = 9;

// Forward for specific operator
const input = new Float32Array(256).fill(1.0);
const output = scopedLora.forward_array(HNSW_SCAN, input);

// Adapt for specific operator
const gradient = new Float32Array(256).fill(0.1);
scopedLora.adapt_array(FILTER, gradient);

// Per-operator statistics
console.log('HNSW forward count:', scopedLora.forward_count(HNSW_SCAN));
console.log('Filter adapt count:', scopedLora.adapt_count(FILTER));
console.log('Filter delta norm:', scopedLora.delta_norm(FILTER));

// Total statistics
console.log('Total forwards:', scopedLora.total_forward_count());
console.log('Total adapts:', scopedLora.total_adapt_count());

// Get operator name
console.log(WasmScopedLoRA.scope_name(HNSW_SCAN)); // "HnswScan"

// Enable/disable category fallback (default: enabled)
scopedLora.set_category_fallback(true);

// Reset specific operator or all
scopedLora.reset_scope(FILTER);
scopedLora.reset_all();

Operator Types

Value Name Category
0 SeqScan Scan
1 IndexScan Scan
2 HnswScan Scan
3 IvfFlatScan Scan
4 NestedLoopJoin Join
5 HashJoin Join
6 MergeJoin Join
7 Aggregate Aggregation
8 GroupBy Aggregation
9 Filter Transform
10 Project Transform
11 Sort Order
12 Limit Order
13 VectorDistance Vector
14 Rerank Vector
15 Materialize Utility
16 Result Utility

WasmTrajectoryBuffer

Trajectory recording for reinforcement learning and pattern analysis.

import init, { WasmTrajectoryBuffer } from 'ruvector-learning-wasm';

await init();

const buffer = new WasmTrajectoryBuffer(
  1000,   // capacity: max trajectories to store
  256     // embedding_dim
);

// Record a trajectory
const embedding = new Float32Array(256).fill(1.0);
buffer.record(
  embedding,
  2,        // op_type: HnswScan
  0,        // attention_type
  100.0,    // execution_ms
  150.0     // baseline_ms (improvement = 150/100 - 1 = 0.5)
);

// Get statistics
console.log('Total count:', buffer.total_count());
console.log('Buffer length:', buffer.len());
console.log('Mean improvement:', buffer.mean_improvement());
console.log('Best improvement:', buffer.best_improvement());
console.log('Success rate:', buffer.success_rate());
console.log('Best attention type:', buffer.best_attention());
console.log('Variance:', buffer.variance());

// Filter by quality
console.log('High quality count:', buffer.high_quality_count(0.5));

// Filter by operator
console.log('HnswScan trajectories:', buffer.count_by_operator(2));

// Reset buffer
buffer.reset();

Architecture

Input Embedding (d-dim)
       |
       v
  +---------+
  | A: d x 2 |  Down projection
  +---------+
       |
       v
  +---------+
  | B: 2 x d |  Up projection (initialized to zero)
  +---------+
       |
       v
Delta W = alpha * (A @ B)
       |
       v
Output = Input + Delta W

Category Fallback

When an operator has fewer than 10 adaptations, the output is blended with the category adapter based on relative experience:

weight = min(operator_adapt_count / 10, 1.0)
output = operator_output * weight + category_output * (1 - weight)

This enables transfer learning between similar operators (e.g., all scan types share Scan category knowledge).

Performance

  • Forward pass: ~50us for 256-dim embeddings
  • Adaptation: ~30us for gradient update
  • Memory: ~2KB per LoRA pair (A + B matrices)
  • WASM size: ~39KB (release build)

TypeScript Types

Full TypeScript definitions are included in the package:

export class WasmMicroLoRA {
  constructor(dim?: number, alpha?: number, learning_rate?: number);
  get_input_ptr(): number;
  get_output_ptr(): number;
  dim(): number;
  forward(): void;
  forward_array(input: Float32Array): Float32Array;
  adapt(): void;
  adapt_array(gradient: Float32Array): void;
  adapt_with_reward(improvement: number): void;
  reset(): void;
  forward_count(): bigint;
  adapt_count(): bigint;
  delta_norm(): number;
  param_count(): number;
}

export class WasmScopedLoRA {
  constructor(dim?: number, alpha?: number, learning_rate?: number);
  get_input_ptr(): number;
  get_output_ptr(): number;
  forward(op_type: number): void;
  forward_array(op_type: number, input: Float32Array): Float32Array;
  adapt(op_type: number): void;
  adapt_array(op_type: number, gradient: Float32Array): void;
  adapt_with_reward(op_type: number, improvement: number): void;
  reset_scope(op_type: number): void;
  reset_all(): void;
  forward_count(op_type: number): bigint;
  adapt_count(op_type: number): bigint;
  delta_norm(op_type: number): number;
  total_forward_count(): bigint;
  total_adapt_count(): bigint;
  set_category_fallback(enabled: boolean): void;
  static scope_name(op_type: number): string;
}

export class WasmTrajectoryBuffer {
  constructor(capacity?: number, embedding_dim?: number);
  record(
    embedding: Float32Array,
    op_type: number,
    attention_type: number,
    execution_ms: number,
    baseline_ms: number
  ): void;
  total_count(): bigint;
  len(): number;
  is_empty(): boolean;
  mean_improvement(): number;
  best_improvement(): number;
  success_rate(): number;
  best_attention(): number;
  variance(): number;
  reset(): void;
  high_quality_count(threshold: number): number;
  count_by_operator(op_type: number): number;
}

License

MIT OR Apache-2.0