Merge commit 'd803bfe2b1fe7f5e219e50ac20d6801a0a58ac75' as 'vendor/ruvector'
This commit is contained in:
5
vendor/ruvector/npm/packages/rvf-solver/.npmignore
vendored
Normal file
5
vendor/ruvector/npm/packages/rvf-solver/.npmignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
src/
|
||||
tsconfig.json
|
||||
*.js.map
|
||||
pkg/.gitignore
|
||||
pkg/.gitkeep
|
||||
254
vendor/ruvector/npm/packages/rvf-solver/README.md
vendored
Normal file
254
vendor/ruvector/npm/packages/rvf-solver/README.md
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
# @ruvector/rvf-solver
|
||||
|
||||
[](https://www.npmjs.com/package/@ruvector/rvf-solver)
|
||||
[](https://github.com/ruvnet/ruvector/blob/main/LICENSE)
|
||||

|
||||
|
||||
Self-learning temporal solver with Thompson Sampling, PolicyKernel, ReasoningBank, and SHAKE-256 tamper-evident witness chains. Runs in the browser, Node.js, and edge runtimes via WebAssembly.
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install @ruvector/rvf-solver
|
||||
```
|
||||
|
||||
Or via the unified SDK:
|
||||
|
||||
```bash
|
||||
npm install @ruvector/rvf
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- **Thompson Sampling two-signal model** — safety Beta distribution + cost EMA for adaptive policy selection
|
||||
- **18 context-bucketed bandits** — 3 range x 3 distractor x 2 noise levels for fine-grained context awareness
|
||||
- **KnowledgeCompiler with signature-based pattern cache** — distills learned patterns into reusable compiled configurations
|
||||
- **Speculative dual-path execution** — runs two candidate arms in parallel, picks the winner
|
||||
- **Three-loop adaptive solver** — fast: constraint propagation solve, medium: PolicyKernel skip-mode selection, slow: KnowledgeCompiler pattern distillation
|
||||
- **SHAKE-256 tamper-evident witness chain** — 73 bytes per entry, cryptographically linked proof of all operations
|
||||
- **Full acceptance test with A/B/C ablation modes** — validates learned policy outperforms fixed and compiler baselines
|
||||
- **~160 KB WASM binary, `no_std`** — runs anywhere WebAssembly does (browsers, Node.js, Deno, Cloudflare Workers, edge runtimes)
|
||||
|
||||
## Quick Start
|
||||
|
||||
```typescript
|
||||
import { RvfSolver } from '@ruvector/rvf-solver';
|
||||
|
||||
// Create a solver instance (loads WASM on first call)
|
||||
const solver = await RvfSolver.create();
|
||||
|
||||
// Train on 100 puzzles (difficulty 1-5)
|
||||
const result = solver.train({ count: 100, minDifficulty: 1, maxDifficulty: 5 });
|
||||
console.log(`Accuracy: ${(result.accuracy * 100).toFixed(1)}%`);
|
||||
console.log(`Patterns learned: ${result.patternsLearned}`);
|
||||
|
||||
// Run full acceptance test (A/B/C ablation)
|
||||
const manifest = solver.acceptance({ cycles: 3 });
|
||||
console.log(`Mode A (fixed): ${manifest.modeA.finalAccuracy.toFixed(3)}`);
|
||||
console.log(`Mode B (compiler): ${manifest.modeB.finalAccuracy.toFixed(3)}`);
|
||||
console.log(`Mode C (learned): ${manifest.modeC.finalAccuracy.toFixed(3)}`);
|
||||
console.log(`All passed: ${manifest.allPassed}`);
|
||||
|
||||
// Inspect Thompson Sampling policy state
|
||||
const policy = solver.policy();
|
||||
console.log(`Context buckets: ${Object.keys(policy?.contextStats ?? {}).length}`);
|
||||
console.log(`Speculative attempts: ${policy?.speculativeAttempts}`);
|
||||
|
||||
// Get raw SHAKE-256 witness chain
|
||||
const chain = solver.witnessChain();
|
||||
console.log(`Witness chain: ${chain?.length ?? 0} bytes`);
|
||||
|
||||
// Free WASM resources
|
||||
solver.destroy();
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `RvfSolver.create(): Promise<RvfSolver>`
|
||||
|
||||
Creates a new solver instance. Initializes the WASM module on the first call; subsequent calls reuse the loaded module. Up to 7 concurrent instances are supported.
|
||||
|
||||
```typescript
|
||||
const solver = await RvfSolver.create();
|
||||
```
|
||||
|
||||
### `solver.train(options: TrainOptions): TrainResult`
|
||||
|
||||
Trains the solver on randomly generated puzzles using the three-loop architecture. The fast loop applies constraint propagation, the medium loop selects skip modes via Thompson Sampling, and the slow loop distills patterns into the KnowledgeCompiler cache.
|
||||
|
||||
```typescript
|
||||
const result = solver.train({ count: 200, minDifficulty: 1, maxDifficulty: 10 });
|
||||
```
|
||||
|
||||
### `solver.acceptance(options?: AcceptanceOptions): AcceptanceManifest`
|
||||
|
||||
Runs the full acceptance test with training/holdout cycles across all three ablation modes (A, B, C). Returns a manifest with per-cycle metrics, pass/fail status, and witness chain metadata.
|
||||
|
||||
```typescript
|
||||
const manifest = solver.acceptance({ cycles: 5, holdoutSize: 50 });
|
||||
```
|
||||
|
||||
### `solver.policy(): PolicyState | null`
|
||||
|
||||
Returns the current Thompson Sampling policy state including per-context-bucket arm statistics, KnowledgeCompiler cache stats, and speculative execution counters. Returns `null` if no training has been performed.
|
||||
|
||||
```typescript
|
||||
const policy = solver.policy();
|
||||
```
|
||||
|
||||
### `solver.witnessChain(): Uint8Array | null`
|
||||
|
||||
Returns the raw SHAKE-256 witness chain bytes. Each entry is 73 bytes and provides tamper-evident proof of all training and acceptance operations. Returns `null` if the chain is empty. The returned `Uint8Array` is a copy safe to use after `destroy()`.
|
||||
|
||||
```typescript
|
||||
const chain = solver.witnessChain();
|
||||
```
|
||||
|
||||
### `solver.destroy(): void`
|
||||
|
||||
Frees the WASM solver instance and releases all associated memory. The instance must not be used after calling `destroy()`.
|
||||
|
||||
```typescript
|
||||
solver.destroy();
|
||||
```
|
||||
|
||||
## Types
|
||||
|
||||
### TrainOptions
|
||||
|
||||
| Field | Type | Default | Description |
|
||||
|-------|------|---------|-------------|
|
||||
| `count` | `number` | required | Number of puzzles to generate and solve |
|
||||
| `minDifficulty` | `number` | `1` | Minimum puzzle difficulty (1-10) |
|
||||
| `maxDifficulty` | `number` | `10` | Maximum puzzle difficulty (1-10) |
|
||||
| `seed` | `bigint \| number` | random | RNG seed for reproducible runs |
|
||||
|
||||
### TrainResult
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `trained` | `number` | Number of puzzles trained on |
|
||||
| `correct` | `number` | Number solved correctly |
|
||||
| `accuracy` | `number` | Accuracy ratio (correct / trained) |
|
||||
| `patternsLearned` | `number` | Patterns distilled by the ReasoningBank |
|
||||
|
||||
### AcceptanceOptions
|
||||
|
||||
| Field | Type | Default | Description |
|
||||
|-------|------|---------|-------------|
|
||||
| `holdoutSize` | `number` | `50` | Number of holdout puzzles per cycle |
|
||||
| `trainingPerCycle` | `number` | `200` | Number of training puzzles per cycle |
|
||||
| `cycles` | `number` | `5` | Number of train/test cycles |
|
||||
| `stepBudget` | `number` | `500` | Maximum constraint propagation steps per puzzle |
|
||||
| `seed` | `bigint \| number` | random | RNG seed for reproducible runs |
|
||||
|
||||
### AcceptanceManifest
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `version` | `number` | Manifest schema version |
|
||||
| `modeA` | `AcceptanceModeResult` | Mode A results (fixed heuristic) |
|
||||
| `modeB` | `AcceptanceModeResult` | Mode B results (compiler-suggested) |
|
||||
| `modeC` | `AcceptanceModeResult` | Mode C results (learned policy) |
|
||||
| `allPassed` | `boolean` | `true` if Mode C passed |
|
||||
| `witnessEntries` | `number` | Number of entries in the witness chain |
|
||||
| `witnessChainBytes` | `number` | Total witness chain size in bytes |
|
||||
|
||||
### AcceptanceModeResult
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `passed` | `boolean` | Whether this mode met the accuracy threshold |
|
||||
| `finalAccuracy` | `number` | Accuracy on the final holdout cycle |
|
||||
| `cycles` | `CycleMetrics[]` | Per-cycle accuracy and cost metrics |
|
||||
|
||||
### PolicyState
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `contextStats` | `Record<string, Record<string, SkipModeStats>>` | Per-context-bucket, per-arm Thompson Sampling statistics |
|
||||
| `earlyCommitPenalties` | `number` | Total early-commit penalty cost |
|
||||
| `earlyCommitsTotal` | `number` | Total early-commit attempts |
|
||||
| `earlyCommitsWrong` | `number` | Early commits that were incorrect |
|
||||
| `prepass` | `string` | Current prepass strategy identifier |
|
||||
| `speculativeAttempts` | `number` | Number of speculative dual-path executions |
|
||||
| `speculativeArm2Wins` | `number` | Times the second speculative arm won |
|
||||
|
||||
## Acceptance Test Modes
|
||||
|
||||
The acceptance test validates the solver's learning capability through three ablation modes run across multiple train/test cycles:
|
||||
|
||||
**Mode A (Fixed)** -- Uses a fixed heuristic skip-mode policy. This establishes the baseline performance without any learning. The policy does not adapt regardless of puzzle characteristics.
|
||||
|
||||
**Mode B (Compiler)** -- Uses the KnowledgeCompiler's signature-based pattern cache to select skip modes. The compiler distills observed patterns into compiled configurations but does not perform online Thompson Sampling updates.
|
||||
|
||||
**Mode C (Learned)** -- Uses the full Thompson Sampling two-signal model with context-bucketed bandits. This is the complete system: the fast loop solves, the medium loop selects arms based on safety Beta and cost EMA, and the slow loop feeds patterns back to the compiler. Mode C should outperform both A and B, demonstrating genuine self-improvement.
|
||||
|
||||
The test passes when Mode C achieves the accuracy threshold on holdout puzzles. The witness chain records every training and evaluation operation for tamper-evident auditability.
|
||||
|
||||
## Architecture
|
||||
|
||||
The solver uses a three-loop adaptive architecture:
|
||||
|
||||
```
|
||||
+-----------------------------------------------+
|
||||
| Slow Loop: KnowledgeCompiler |
|
||||
| - Signature-based pattern cache |
|
||||
| - Distills observations into compiled configs |
|
||||
+-----------------------------------------------+
|
||||
| ^
|
||||
v |
|
||||
+-----------------------------------------------+
|
||||
| Medium Loop: PolicyKernel |
|
||||
| - Thompson Sampling (safety Beta + cost EMA) |
|
||||
| - 18 context buckets (range x distractor x noise) |
|
||||
| - Speculative dual-path execution |
|
||||
+-----------------------------------------------+
|
||||
| ^
|
||||
v |
|
||||
+-----------------------------------------------+
|
||||
| Fast Loop: Constraint Propagation Solver |
|
||||
| - Generates and solves puzzles |
|
||||
| - Reports outcomes back to PolicyKernel |
|
||||
+-----------------------------------------------+
|
||||
|
|
||||
v
|
||||
+-----------------------------------------------+
|
||||
| SHAKE-256 Witness Chain (73 bytes/entry) |
|
||||
| - Tamper-evident proof of all operations |
|
||||
+-----------------------------------------------+
|
||||
```
|
||||
|
||||
The fast loop runs on every puzzle, the medium loop updates policy parameters after each solve, and the slow loop periodically compiles accumulated observations into cached patterns. All operations are recorded in the SHAKE-256 witness chain.
|
||||
|
||||
## Unified SDK
|
||||
|
||||
When using the `@ruvector/rvf` unified SDK, the solver is available as a sub-module:
|
||||
|
||||
```typescript
|
||||
import { RvfSolver } from '@ruvector/rvf';
|
||||
|
||||
const solver = await RvfSolver.create();
|
||||
const result = solver.train({ count: 100 });
|
||||
console.log(`Accuracy: ${(result.accuracy * 100).toFixed(1)}%`);
|
||||
solver.destroy();
|
||||
```
|
||||
|
||||
## Related Packages
|
||||
|
||||
| Package | Description |
|
||||
|---------|-------------|
|
||||
| [`@ruvector/rvf`](https://www.npmjs.com/package/@ruvector/rvf) | Unified TypeScript SDK |
|
||||
| [`@ruvector/rvf-node`](https://www.npmjs.com/package/@ruvector/rvf-node) | Native N-API bindings for Node.js |
|
||||
| [`@ruvector/rvf-wasm`](https://www.npmjs.com/package/@ruvector/rvf-wasm) | Browser WASM package |
|
||||
| [`@ruvector/rvf-mcp-server`](https://www.npmjs.com/package/@ruvector/rvf-mcp-server) | MCP server for AI agents |
|
||||
|
||||
## License
|
||||
|
||||
MIT OR Apache-2.0
|
||||
|
||||
## Links
|
||||
|
||||
- [GitHub Repository](https://github.com/ruvnet/ruvector)
|
||||
- [RVF Format Specification](https://github.com/ruvnet/ruvector/tree/main/crates/rvf)
|
||||
- [npm Package](https://www.npmjs.com/package/@ruvector/rvf-solver)
|
||||
195
vendor/ruvector/npm/packages/rvf-solver/dist/solver.js
vendored
Normal file
195
vendor/ruvector/npm/packages/rvf-solver/dist/solver.js
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.RvfSolver = void 0;
|
||||
let wasmExports = null;
|
||||
async function getWasm() {
|
||||
if (wasmExports)
|
||||
return wasmExports;
|
||||
// Dynamic import to support both CJS and ESM
|
||||
const initModule = await Promise.resolve().then(() => __importStar(require('../pkg/rvf_solver')));
|
||||
const init = initModule.default || initModule;
|
||||
wasmExports = await init();
|
||||
return wasmExports;
|
||||
}
|
||||
function splitSeed(seed) {
|
||||
if (seed === undefined) {
|
||||
const s = BigInt(Math.floor(Math.random() * 2 ** 64));
|
||||
return [Number(s & 0xffffffffn), Number((s >> 32n) & 0xffffffffn)];
|
||||
}
|
||||
const s = typeof seed === 'number' ? BigInt(seed) : seed;
|
||||
return [Number(s & 0xffffffffn), Number((s >> 32n) & 0xffffffffn)];
|
||||
}
|
||||
function readJson(wasm, handle, lenFn, readFn) {
|
||||
const len = lenFn(handle);
|
||||
if (len <= 0)
|
||||
return null;
|
||||
const ptr = wasm.rvf_solver_alloc(len);
|
||||
if (ptr === 0)
|
||||
return null;
|
||||
try {
|
||||
readFn(handle, ptr);
|
||||
const buf = new Uint8Array(wasm.memory.buffer, ptr, len);
|
||||
const text = new TextDecoder().decode(buf);
|
||||
return JSON.parse(text);
|
||||
}
|
||||
finally {
|
||||
wasm.rvf_solver_free(ptr, len);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* RVF Self-Learning Solver.
|
||||
*
|
||||
* Wraps the rvf-solver-wasm WASM module providing:
|
||||
* - PolicyKernel with Thompson Sampling (two-signal model)
|
||||
* - Context-bucketed bandit (18 buckets)
|
||||
* - KnowledgeCompiler with signature-based pattern cache
|
||||
* - Speculative dual-path execution
|
||||
* - Three-loop adaptive solver (fast/medium/slow)
|
||||
* - SHAKE-256 tamper-evident witness chain
|
||||
*/
|
||||
class RvfSolver {
|
||||
constructor(handle, wasm) {
|
||||
this.handle = handle;
|
||||
this.wasm = wasm;
|
||||
}
|
||||
/**
|
||||
* Create a new solver instance.
|
||||
* Initializes the WASM module on first call.
|
||||
*/
|
||||
static async create() {
|
||||
const wasm = await getWasm();
|
||||
const handle = wasm.rvf_solver_create();
|
||||
if (handle < 0) {
|
||||
throw new Error('Failed to create solver instance (max 8 concurrent instances)');
|
||||
}
|
||||
return new RvfSolver(handle, wasm);
|
||||
}
|
||||
/**
|
||||
* Train the solver on generated puzzles.
|
||||
*
|
||||
* Uses the three-loop architecture:
|
||||
* - Fast loop: constraint propagation solver
|
||||
* - Medium loop: PolicyKernel skip-mode selection
|
||||
* - Slow loop: KnowledgeCompiler pattern distillation
|
||||
*/
|
||||
train(options) {
|
||||
const [seedLo, seedHi] = splitSeed(options.seed);
|
||||
const correct = this.wasm.rvf_solver_train(this.handle, options.count, options.minDifficulty ?? 1, options.maxDifficulty ?? 10, seedLo, seedHi);
|
||||
if (correct < 0) {
|
||||
throw new Error('Training failed: invalid handle');
|
||||
}
|
||||
const result = readJson(this.wasm, this.handle, (h) => this.wasm.rvf_solver_result_len(h), (h, p) => this.wasm.rvf_solver_result_read(h, p));
|
||||
return result ?? {
|
||||
trained: options.count,
|
||||
correct,
|
||||
accuracy: correct / options.count,
|
||||
patternsLearned: 0,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Run the full acceptance test with training/holdout cycles.
|
||||
*
|
||||
* Runs all three ablation modes:
|
||||
* - Mode A: Fixed heuristic policy
|
||||
* - Mode B: Compiler-suggested policy
|
||||
* - Mode C: Learned Thompson Sampling policy
|
||||
*
|
||||
* Returns the full manifest with per-cycle metrics and witness chain.
|
||||
*/
|
||||
acceptance(options) {
|
||||
const opts = options ?? {};
|
||||
const [seedLo, seedHi] = splitSeed(opts.seed);
|
||||
const status = this.wasm.rvf_solver_acceptance(this.handle, opts.holdoutSize ?? 50, opts.trainingPerCycle ?? 200, opts.cycles ?? 5, opts.stepBudget ?? 500, seedLo, seedHi);
|
||||
if (status < 0) {
|
||||
throw new Error('Acceptance test failed: invalid handle');
|
||||
}
|
||||
const manifest = readJson(this.wasm, this.handle, (h) => this.wasm.rvf_solver_result_len(h), (h, p) => this.wasm.rvf_solver_result_read(h, p));
|
||||
if (!manifest) {
|
||||
throw new Error('Failed to read acceptance manifest');
|
||||
}
|
||||
return {
|
||||
version: manifest.version,
|
||||
modeA: manifest.mode_a,
|
||||
modeB: manifest.mode_b,
|
||||
modeC: manifest.mode_c,
|
||||
allPassed: manifest.all_passed,
|
||||
witnessEntries: manifest.witness_entries,
|
||||
witnessChainBytes: manifest.witness_chain_bytes,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Get the current policy state (Thompson Sampling parameters,
|
||||
* context buckets, KnowledgeCompiler cache stats).
|
||||
*/
|
||||
policy() {
|
||||
return readJson(this.wasm, this.handle, (h) => this.wasm.rvf_solver_policy_len(h), (h, p) => this.wasm.rvf_solver_policy_read(h, p));
|
||||
}
|
||||
/**
|
||||
* Get the raw SHAKE-256 witness chain bytes.
|
||||
*
|
||||
* The witness chain is 73 bytes per entry and provides
|
||||
* tamper-evident proof of all training/acceptance operations.
|
||||
* Verifiable using `rvf_witness_verify` from `@ruvector/rvf-wasm`.
|
||||
*/
|
||||
witnessChain() {
|
||||
const len = this.wasm.rvf_solver_witness_len(this.handle);
|
||||
if (len <= 0)
|
||||
return null;
|
||||
const ptr = this.wasm.rvf_solver_alloc(len);
|
||||
if (ptr === 0)
|
||||
return null;
|
||||
try {
|
||||
this.wasm.rvf_solver_witness_read(this.handle, ptr);
|
||||
const buf = new Uint8Array(this.wasm.memory.buffer, ptr, len);
|
||||
// Copy to avoid referencing WASM memory after free
|
||||
return new Uint8Array(buf);
|
||||
}
|
||||
finally {
|
||||
this.wasm.rvf_solver_free(ptr, len);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Destroy the solver instance and free WASM resources.
|
||||
*/
|
||||
destroy() {
|
||||
if (this.handle > 0) {
|
||||
this.wasm.rvf_solver_destroy(this.handle);
|
||||
this.handle = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.RvfSolver = RvfSolver;
|
||||
//# sourceMappingURL=solver.js.map
|
||||
26
vendor/ruvector/npm/packages/rvf-solver/package.json
vendored
Normal file
26
vendor/ruvector/npm/packages/rvf-solver/package.json
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "@ruvector/rvf-solver",
|
||||
"version": "0.1.7",
|
||||
"description": "RVF self-learning temporal solver — Thompson Sampling, PolicyKernel, ReasoningBank",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"require": "./dist/index.js",
|
||||
"default": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"files": ["dist/", "pkg/", "package.json"],
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"build:wasm": "cargo build --release --target wasm32-unknown-unknown --manifest-path ../../crates/rvf/rvf-solver-wasm/Cargo.toml && wasm-opt -Oz ../../crates/rvf/target/wasm32-unknown-unknown/release/rvf_solver_wasm.wasm -o pkg/rvf_solver_bg.wasm"
|
||||
},
|
||||
"keywords": ["solver", "wasm", "thompson-sampling", "reasoning-bank", "self-learning", "rvf", "agi"],
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/ruvnet/ruvector",
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/",
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
0
vendor/ruvector/npm/packages/rvf-solver/pkg/.gitkeep
vendored
Normal file
0
vendor/ruvector/npm/packages/rvf-solver/pkg/.gitkeep
vendored
Normal file
2
vendor/ruvector/npm/packages/rvf-solver/pkg/.npmignore
vendored
Normal file
2
vendor/ruvector/npm/packages/rvf-solver/pkg/.npmignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Allow all files to be included in npm package
|
||||
# (overrides .gitignore which blocks everything)
|
||||
48
vendor/ruvector/npm/packages/rvf-solver/pkg/rvf_solver.d.ts
vendored
Normal file
48
vendor/ruvector/npm/packages/rvf-solver/pkg/rvf_solver.d.ts
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Type declarations for the RVF Solver WASM module exports.
|
||||
*/
|
||||
|
||||
export interface RvfSolverWasmExports {
|
||||
memory: WebAssembly.Memory;
|
||||
|
||||
// Memory management
|
||||
rvf_solver_alloc(size: number): number;
|
||||
rvf_solver_free(ptr: number, size: number): void;
|
||||
|
||||
// Lifecycle
|
||||
rvf_solver_create(): number;
|
||||
rvf_solver_destroy(handle: number): number;
|
||||
|
||||
// Training
|
||||
rvf_solver_train(
|
||||
handle: number,
|
||||
count: number,
|
||||
min_diff: number,
|
||||
max_diff: number,
|
||||
seed_lo: number,
|
||||
seed_hi: number,
|
||||
): number;
|
||||
|
||||
// Acceptance testing
|
||||
rvf_solver_acceptance(
|
||||
handle: number,
|
||||
holdout: number,
|
||||
training: number,
|
||||
cycles: number,
|
||||
budget: number,
|
||||
seed_lo: number,
|
||||
seed_hi: number,
|
||||
): number;
|
||||
|
||||
// Result reads
|
||||
rvf_solver_result_len(handle: number): number;
|
||||
rvf_solver_result_read(handle: number, out_ptr: number): number;
|
||||
rvf_solver_policy_len(handle: number): number;
|
||||
rvf_solver_policy_read(handle: number, out_ptr: number): number;
|
||||
rvf_solver_witness_len(handle: number): number;
|
||||
rvf_solver_witness_read(handle: number, out_ptr: number): number;
|
||||
}
|
||||
|
||||
export default function init(
|
||||
input?: ArrayBuffer | Uint8Array | WebAssembly.Module | string,
|
||||
): Promise<RvfSolverWasmExports>;
|
||||
62
vendor/ruvector/npm/packages/rvf-solver/pkg/rvf_solver.js
vendored
Normal file
62
vendor/ruvector/npm/packages/rvf-solver/pkg/rvf_solver.js
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* @ruvector/rvf-solver — JS glue for the RVF Solver WASM module.
|
||||
*
|
||||
* Loads the .wasm binary and re-exports all C-ABI functions plus the
|
||||
* WASM linear memory object.
|
||||
*
|
||||
* Works in Node.js (CJS) and browsers (via bundler).
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var wasmInstance = null;
|
||||
|
||||
var _isNode = typeof process !== 'undefined' &&
|
||||
typeof process.versions !== 'undefined' &&
|
||||
typeof process.versions.node === 'string';
|
||||
|
||||
/**
|
||||
* Initialize the WASM module.
|
||||
* Returns the exports object with all rvf_solver_* functions and `memory`.
|
||||
*
|
||||
* @param {ArrayBuffer|BufferSource|WebAssembly.Module|string} [input]
|
||||
* Optional pre-loaded bytes, Module, or file path override.
|
||||
*/
|
||||
async function init(input) {
|
||||
if (wasmInstance) return wasmInstance;
|
||||
|
||||
var wasmBytes;
|
||||
|
||||
if (input instanceof ArrayBuffer || ArrayBuffer.isView(input)) {
|
||||
wasmBytes = input;
|
||||
} else if (typeof WebAssembly !== 'undefined' && input instanceof WebAssembly.Module) {
|
||||
var inst = await WebAssembly.instantiate(input, {});
|
||||
wasmInstance = inst.exports;
|
||||
return wasmInstance;
|
||||
} else if (_isNode) {
|
||||
// Node.js: use fs.readFileSync with __dirname (CJS) or require.resolve fallback
|
||||
var fs = require('node:fs');
|
||||
var path = require('node:path');
|
||||
var wasmPath;
|
||||
if (typeof input === 'string') {
|
||||
wasmPath = input;
|
||||
} else {
|
||||
// __dirname is always available in CJS (no import.meta needed)
|
||||
wasmPath = path.join(__dirname, 'rvf_solver_bg.wasm');
|
||||
}
|
||||
wasmBytes = fs.readFileSync(wasmPath);
|
||||
} else {
|
||||
// Browser: caller must provide bytes or use a bundler that handles .wasm imports
|
||||
throw new Error(
|
||||
'rvf_solver: browser environment detected but no WASM bytes provided. ' +
|
||||
'Pass an ArrayBuffer or WebAssembly.Module to init(), or use a bundler.'
|
||||
);
|
||||
}
|
||||
|
||||
var compiled = await WebAssembly.instantiate(wasmBytes, {});
|
||||
wasmInstance = compiled.instance.exports;
|
||||
return wasmInstance;
|
||||
}
|
||||
|
||||
// CJS export
|
||||
init.default = init;
|
||||
module.exports = init;
|
||||
BIN
vendor/ruvector/npm/packages/rvf-solver/pkg/rvf_solver_bg.wasm
vendored
Normal file
BIN
vendor/ruvector/npm/packages/rvf-solver/pkg/rvf_solver_bg.wasm
vendored
Normal file
Binary file not shown.
46
vendor/ruvector/npm/packages/rvf-solver/src/index.ts
vendored
Normal file
46
vendor/ruvector/npm/packages/rvf-solver/src/index.ts
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* @ruvector/rvf-solver — Self-learning temporal solver with AGI capabilities.
|
||||
*
|
||||
* Provides Thompson Sampling policy learning, ReasoningBank pattern
|
||||
* distillation, and SHAKE-256 tamper-evident witness chains.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { RvfSolver } from '@ruvector/rvf-solver';
|
||||
*
|
||||
* const solver = await RvfSolver.create();
|
||||
*
|
||||
* // Train on 100 puzzles
|
||||
* const result = solver.train({ count: 100, minDifficulty: 1, maxDifficulty: 5 });
|
||||
* console.log(`Accuracy: ${(result.accuracy * 100).toFixed(1)}%`);
|
||||
*
|
||||
* // Run full acceptance test
|
||||
* const manifest = solver.acceptance({ cycles: 3 });
|
||||
* console.log(`Mode C passed: ${manifest.allPassed}`);
|
||||
*
|
||||
* // Get policy state
|
||||
* const policy = solver.policy();
|
||||
* console.log(`Context buckets: ${Object.keys(policy?.contextStats ?? {}).length}`);
|
||||
*
|
||||
* // Get witness chain
|
||||
* const chain = solver.witnessChain();
|
||||
* console.log(`Witness chain: ${chain?.length ?? 0} bytes`);
|
||||
*
|
||||
* solver.destroy();
|
||||
* ```
|
||||
*/
|
||||
|
||||
export { RvfSolver } from './solver';
|
||||
|
||||
export type {
|
||||
TrainOptions,
|
||||
TrainResult,
|
||||
AcceptanceOptions,
|
||||
AcceptanceManifest,
|
||||
AcceptanceModeResult,
|
||||
CycleMetrics,
|
||||
PolicyState,
|
||||
SkipMode,
|
||||
SkipModeStats,
|
||||
CompiledConfig,
|
||||
} from './types';
|
||||
207
vendor/ruvector/npm/packages/rvf-solver/src/solver.ts
vendored
Normal file
207
vendor/ruvector/npm/packages/rvf-solver/src/solver.ts
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
import type { RvfSolverWasmExports } from '../pkg/rvf_solver';
|
||||
import type {
|
||||
TrainOptions,
|
||||
TrainResult,
|
||||
AcceptanceOptions,
|
||||
AcceptanceManifest,
|
||||
PolicyState,
|
||||
} from './types';
|
||||
|
||||
let wasmExports: RvfSolverWasmExports | null = null;
|
||||
|
||||
async function getWasm(): Promise<RvfSolverWasmExports> {
|
||||
if (wasmExports) return wasmExports;
|
||||
// Dynamic import to support both CJS and ESM
|
||||
const initModule = await import('../pkg/rvf_solver');
|
||||
const init = initModule.default || initModule;
|
||||
wasmExports = await init();
|
||||
return wasmExports;
|
||||
}
|
||||
|
||||
function splitSeed(seed?: bigint | number): [number, number] {
|
||||
if (seed === undefined) {
|
||||
const s = BigInt(Math.floor(Math.random() * 2 ** 64));
|
||||
return [Number(s & 0xFFFFFFFFn), Number((s >> 32n) & 0xFFFFFFFFn)];
|
||||
}
|
||||
const s = typeof seed === 'number' ? BigInt(seed) : seed;
|
||||
return [Number(s & 0xFFFFFFFFn), Number((s >> 32n) & 0xFFFFFFFFn)];
|
||||
}
|
||||
|
||||
function readJson<T>(
|
||||
wasm: RvfSolverWasmExports,
|
||||
handle: number,
|
||||
lenFn: (h: number) => number,
|
||||
readFn: (h: number, ptr: number) => number,
|
||||
): T | null {
|
||||
const len = lenFn(handle);
|
||||
if (len <= 0) return null;
|
||||
const ptr = wasm.rvf_solver_alloc(len);
|
||||
if (ptr === 0) return null;
|
||||
try {
|
||||
readFn(handle, ptr);
|
||||
const buf = new Uint8Array(wasm.memory.buffer, ptr, len);
|
||||
const text = new TextDecoder().decode(buf);
|
||||
return JSON.parse(text) as T;
|
||||
} finally {
|
||||
wasm.rvf_solver_free(ptr, len);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* RVF Self-Learning Solver.
|
||||
*
|
||||
* Wraps the rvf-solver-wasm WASM module providing:
|
||||
* - PolicyKernel with Thompson Sampling (two-signal model)
|
||||
* - Context-bucketed bandit (18 buckets)
|
||||
* - KnowledgeCompiler with signature-based pattern cache
|
||||
* - Speculative dual-path execution
|
||||
* - Three-loop adaptive solver (fast/medium/slow)
|
||||
* - SHAKE-256 tamper-evident witness chain
|
||||
*/
|
||||
export class RvfSolver {
|
||||
private handle: number;
|
||||
private wasm: RvfSolverWasmExports;
|
||||
|
||||
private constructor(handle: number, wasm: RvfSolverWasmExports) {
|
||||
this.handle = handle;
|
||||
this.wasm = wasm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new solver instance.
|
||||
* Initializes the WASM module on first call.
|
||||
*/
|
||||
static async create(): Promise<RvfSolver> {
|
||||
const wasm = await getWasm();
|
||||
const handle = wasm.rvf_solver_create();
|
||||
if (handle < 0) {
|
||||
throw new Error('Failed to create solver instance (max 8 concurrent instances)');
|
||||
}
|
||||
return new RvfSolver(handle, wasm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Train the solver on generated puzzles.
|
||||
*
|
||||
* Uses the three-loop architecture:
|
||||
* - Fast loop: constraint propagation solver
|
||||
* - Medium loop: PolicyKernel skip-mode selection
|
||||
* - Slow loop: KnowledgeCompiler pattern distillation
|
||||
*/
|
||||
train(options: TrainOptions): TrainResult {
|
||||
const [seedLo, seedHi] = splitSeed(options.seed);
|
||||
const correct = this.wasm.rvf_solver_train(
|
||||
this.handle,
|
||||
options.count,
|
||||
options.minDifficulty ?? 1,
|
||||
options.maxDifficulty ?? 10,
|
||||
seedLo,
|
||||
seedHi,
|
||||
);
|
||||
if (correct < 0) {
|
||||
throw new Error('Training failed: invalid handle');
|
||||
}
|
||||
const result = readJson<TrainResult>(
|
||||
this.wasm,
|
||||
this.handle,
|
||||
(h) => this.wasm.rvf_solver_result_len(h),
|
||||
(h, p) => this.wasm.rvf_solver_result_read(h, p),
|
||||
);
|
||||
return result ?? {
|
||||
trained: options.count,
|
||||
correct,
|
||||
accuracy: correct / options.count,
|
||||
patternsLearned: 0,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the full acceptance test with training/holdout cycles.
|
||||
*
|
||||
* Runs all three ablation modes:
|
||||
* - Mode A: Fixed heuristic policy
|
||||
* - Mode B: Compiler-suggested policy
|
||||
* - Mode C: Learned Thompson Sampling policy
|
||||
*
|
||||
* Returns the full manifest with per-cycle metrics and witness chain.
|
||||
*/
|
||||
acceptance(options?: AcceptanceOptions): AcceptanceManifest {
|
||||
const opts = options ?? {};
|
||||
const [seedLo, seedHi] = splitSeed(opts.seed);
|
||||
const status = this.wasm.rvf_solver_acceptance(
|
||||
this.handle,
|
||||
opts.holdoutSize ?? 50,
|
||||
opts.trainingPerCycle ?? 200,
|
||||
opts.cycles ?? 5,
|
||||
opts.stepBudget ?? 500,
|
||||
seedLo,
|
||||
seedHi,
|
||||
);
|
||||
if (status < 0) {
|
||||
throw new Error('Acceptance test failed: invalid handle');
|
||||
}
|
||||
const manifest = readJson<any>(
|
||||
this.wasm,
|
||||
this.handle,
|
||||
(h) => this.wasm.rvf_solver_result_len(h),
|
||||
(h, p) => this.wasm.rvf_solver_result_read(h, p),
|
||||
);
|
||||
if (!manifest) {
|
||||
throw new Error('Failed to read acceptance manifest');
|
||||
}
|
||||
return {
|
||||
version: manifest.version,
|
||||
modeA: manifest.mode_a,
|
||||
modeB: manifest.mode_b,
|
||||
modeC: manifest.mode_c,
|
||||
allPassed: manifest.all_passed,
|
||||
witnessEntries: manifest.witness_entries,
|
||||
witnessChainBytes: manifest.witness_chain_bytes,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current policy state (Thompson Sampling parameters,
|
||||
* context buckets, KnowledgeCompiler cache stats).
|
||||
*/
|
||||
policy(): PolicyState | null {
|
||||
return readJson<PolicyState>(
|
||||
this.wasm,
|
||||
this.handle,
|
||||
(h) => this.wasm.rvf_solver_policy_len(h),
|
||||
(h, p) => this.wasm.rvf_solver_policy_read(h, p),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw SHAKE-256 witness chain bytes.
|
||||
*
|
||||
* The witness chain is 73 bytes per entry and provides
|
||||
* tamper-evident proof of all training/acceptance operations.
|
||||
* Verifiable using `rvf_witness_verify` from `@ruvector/rvf-wasm`.
|
||||
*/
|
||||
witnessChain(): Uint8Array | null {
|
||||
const len = this.wasm.rvf_solver_witness_len(this.handle);
|
||||
if (len <= 0) return null;
|
||||
const ptr = this.wasm.rvf_solver_alloc(len);
|
||||
if (ptr === 0) return null;
|
||||
try {
|
||||
this.wasm.rvf_solver_witness_read(this.handle, ptr);
|
||||
const buf = new Uint8Array(this.wasm.memory.buffer, ptr, len);
|
||||
// Copy to avoid referencing WASM memory after free
|
||||
return new Uint8Array(buf);
|
||||
} finally {
|
||||
this.wasm.rvf_solver_free(ptr, len);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the solver instance and free WASM resources.
|
||||
*/
|
||||
destroy(): void {
|
||||
if (this.handle > 0) {
|
||||
this.wasm.rvf_solver_destroy(this.handle);
|
||||
this.handle = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
104
vendor/ruvector/npm/packages/rvf-solver/src/types.ts
vendored
Normal file
104
vendor/ruvector/npm/packages/rvf-solver/src/types.ts
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
/** Configuration for solver training. */
|
||||
export interface TrainOptions {
|
||||
/** Number of puzzles to generate and solve. */
|
||||
count: number;
|
||||
/** Minimum puzzle difficulty (1-10). Default: 1. */
|
||||
minDifficulty?: number;
|
||||
/** Maximum puzzle difficulty (1-10). Default: 10. */
|
||||
maxDifficulty?: number;
|
||||
/** RNG seed (BigInt or number). Default: random. */
|
||||
seed?: bigint | number;
|
||||
}
|
||||
|
||||
/** Result of a training run. */
|
||||
export interface TrainResult {
|
||||
/** Number of puzzles trained on. */
|
||||
trained: number;
|
||||
/** Number solved correctly. */
|
||||
correct: number;
|
||||
/** Accuracy (correct / trained). */
|
||||
accuracy: number;
|
||||
/** Number of patterns learned by the ReasoningBank. */
|
||||
patternsLearned: number;
|
||||
}
|
||||
|
||||
/** Configuration for acceptance testing. */
|
||||
export interface AcceptanceOptions {
|
||||
/** Number of holdout puzzles per cycle. Default: 50. */
|
||||
holdoutSize?: number;
|
||||
/** Number of training puzzles per cycle. Default: 200. */
|
||||
trainingPerCycle?: number;
|
||||
/** Number of train/test cycles. Default: 5. */
|
||||
cycles?: number;
|
||||
/** Maximum steps per puzzle. Default: 500. */
|
||||
stepBudget?: number;
|
||||
/** RNG seed (BigInt or number). Default: random. */
|
||||
seed?: bigint | number;
|
||||
}
|
||||
|
||||
/** Per-cycle metrics from an acceptance mode. */
|
||||
export interface CycleMetrics {
|
||||
cycle: number;
|
||||
accuracy: number;
|
||||
costPerSolve: number;
|
||||
}
|
||||
|
||||
/** Result of a single acceptance mode (A, B, or C). */
|
||||
export interface AcceptanceModeResult {
|
||||
passed: boolean;
|
||||
finalAccuracy: number;
|
||||
cycles: CycleMetrics[];
|
||||
}
|
||||
|
||||
/** Full acceptance test manifest. */
|
||||
export interface AcceptanceManifest {
|
||||
version: number;
|
||||
/** Mode A: fixed heuristic policy. */
|
||||
modeA: AcceptanceModeResult;
|
||||
/** Mode B: compiler-suggested policy. */
|
||||
modeB: AcceptanceModeResult;
|
||||
/** Mode C: learned Thompson Sampling policy. */
|
||||
modeC: AcceptanceModeResult;
|
||||
/** True if Mode C passed (the full learned mode). */
|
||||
allPassed: boolean;
|
||||
/** Number of witness entries in the chain. */
|
||||
witnessEntries: number;
|
||||
/** Total witness chain bytes. */
|
||||
witnessChainBytes: number;
|
||||
}
|
||||
|
||||
/** Skip mode for the PolicyKernel. */
|
||||
export type SkipMode = 'none' | 'weekday' | 'hybrid';
|
||||
|
||||
/** Per-arm stats from Thompson Sampling. */
|
||||
export interface SkipModeStats {
|
||||
attempts: number;
|
||||
successes: number;
|
||||
totalSteps: number;
|
||||
alphaSafety: number;
|
||||
betaSafety: number;
|
||||
costEma: number;
|
||||
earlyCommitWrongs: number;
|
||||
}
|
||||
|
||||
/** Compiled knowledge entry. */
|
||||
export interface CompiledConfig {
|
||||
maxSteps: number;
|
||||
avgSteps: number;
|
||||
observations: number;
|
||||
expectedCorrect: boolean;
|
||||
hitCount: number;
|
||||
counterexampleCount: number;
|
||||
compiledSkip: SkipMode;
|
||||
}
|
||||
|
||||
/** Full policy state from the PolicyKernel. */
|
||||
export interface PolicyState {
|
||||
contextStats: Record<string, Record<string, SkipModeStats>>;
|
||||
earlyCommitPenalties: number;
|
||||
earlyCommitsTotal: number;
|
||||
earlyCommitsWrong: number;
|
||||
prepass: string;
|
||||
speculativeAttempts: number;
|
||||
speculativeArm2Wins: number;
|
||||
}
|
||||
194
vendor/ruvector/npm/packages/rvf-solver/test/solver.test.mjs
vendored
Executable file
194
vendor/ruvector/npm/packages/rvf-solver/test/solver.test.mjs
vendored
Executable file
@@ -0,0 +1,194 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import assert from 'assert';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const packageDir = path.dirname(__dirname);
|
||||
|
||||
/**
|
||||
* Test suite for RvfSolver TypeScript SDK
|
||||
*
|
||||
* Validates:
|
||||
* 1. Import/export of all types and classes
|
||||
* 2. Type structure and defaults
|
||||
* 3. WASM integration (if binary available)
|
||||
*/
|
||||
|
||||
console.log('Starting RvfSolver TypeScript SDK validation tests...\n');
|
||||
|
||||
// Test 1: Import/export validation
|
||||
console.log('Test 1: Import/export validation');
|
||||
try {
|
||||
// Try both CommonJS (.js) and ESM (.mjs) outputs
|
||||
let distIndex = path.join(packageDir, 'dist', 'index.mjs');
|
||||
if (!fs.existsSync(distIndex)) {
|
||||
distIndex = path.join(packageDir, 'dist', 'index.js');
|
||||
}
|
||||
|
||||
if (!fs.existsSync(distIndex)) {
|
||||
throw new Error('dist/index.mjs or dist/index.js not found - run: npm run build');
|
||||
}
|
||||
|
||||
const module = await import(`file://${distIndex}`);
|
||||
|
||||
// Handle both default and named exports (CommonJS)
|
||||
const RvfSolver = module.RvfSolver || module.default?.RvfSolver;
|
||||
|
||||
assert(typeof RvfSolver === 'function', 'RvfSolver class should be exported');
|
||||
console.log(' ✓ RvfSolver class exported');
|
||||
|
||||
// Verify all type exports (TypeScript types don't exist at runtime, but we verify the structure)
|
||||
const exportedNames = Object.keys(module).sort();
|
||||
console.log(` ✓ Module exports: ${exportedNames.join(', ')}`);
|
||||
|
||||
// Check minimum expected exports
|
||||
assert(exportedNames.includes('RvfSolver') || module.default?.RvfSolver, 'Should export RvfSolver');
|
||||
console.log(' ✓ All required exports present (RvfSolver)');
|
||||
|
||||
} catch (error) {
|
||||
console.error(` ✗ FAILED: ${error.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Test 2: Type structure validation (via TypeScript definitions)
|
||||
console.log('\nTest 2: Type structure validation');
|
||||
try {
|
||||
const dtsFile = path.join(packageDir, 'dist', 'types.d.ts');
|
||||
|
||||
if (!fs.existsSync(dtsFile)) {
|
||||
throw new Error(`dist/types.d.ts not found - run: npm run build`);
|
||||
}
|
||||
|
||||
const dtsContent = fs.readFileSync(dtsFile, 'utf8');
|
||||
|
||||
// Verify TrainOptions interface
|
||||
assert(dtsContent.includes('interface TrainOptions'), 'TrainOptions interface should be defined');
|
||||
assert(dtsContent.includes('count: number'), 'TrainOptions should have count property');
|
||||
assert(dtsContent.includes('minDifficulty'), 'TrainOptions should have minDifficulty property');
|
||||
assert(dtsContent.includes('maxDifficulty'), 'TrainOptions should have maxDifficulty property');
|
||||
assert(dtsContent.includes('seed'), 'TrainOptions should have seed property');
|
||||
console.log(' ✓ TrainOptions has expected shape (count, minDifficulty, maxDifficulty, seed)');
|
||||
|
||||
// Verify TrainResult interface
|
||||
assert(dtsContent.includes('interface TrainResult'), 'TrainResult interface should be defined');
|
||||
assert(dtsContent.includes('trained: number'), 'TrainResult should have trained property');
|
||||
assert(dtsContent.includes('correct: number'), 'TrainResult should have correct property');
|
||||
assert(dtsContent.includes('accuracy: number'), 'TrainResult should have accuracy property');
|
||||
assert(dtsContent.includes('patternsLearned: number'), 'TrainResult should have patternsLearned property');
|
||||
console.log(' ✓ TrainResult has expected fields (trained, correct, accuracy, patternsLearned)');
|
||||
|
||||
// Verify AcceptanceOptions interface
|
||||
assert(dtsContent.includes('interface AcceptanceOptions'), 'AcceptanceOptions interface should be defined');
|
||||
assert(dtsContent.includes('holdoutSize'), 'AcceptanceOptions should have holdoutSize property');
|
||||
assert(dtsContent.includes('trainingPerCycle'), 'AcceptanceOptions should have trainingPerCycle property');
|
||||
assert(dtsContent.includes('cycles'), 'AcceptanceOptions should have cycles property');
|
||||
assert(dtsContent.includes('stepBudget'), 'AcceptanceOptions should have stepBudget property');
|
||||
console.log(' ✓ AcceptanceOptions has expected defaults (holdoutSize, trainingPerCycle, cycles, stepBudget)');
|
||||
|
||||
// Verify AcceptanceManifest interface
|
||||
assert(dtsContent.includes('interface AcceptanceManifest'), 'AcceptanceManifest interface should be defined');
|
||||
assert(dtsContent.includes('modeA: AcceptanceModeResult'), 'AcceptanceManifest should have modeA property');
|
||||
assert(dtsContent.includes('modeB: AcceptanceModeResult'), 'AcceptanceManifest should have modeB property');
|
||||
assert(dtsContent.includes('modeC: AcceptanceModeResult'), 'AcceptanceManifest should have modeC property');
|
||||
assert(dtsContent.includes('allPassed: boolean'), 'AcceptanceManifest should have allPassed property');
|
||||
console.log(' ✓ AcceptanceManifest has expected fields (modeA, modeB, modeC, allPassed)');
|
||||
|
||||
// Verify AcceptanceModeResult interface
|
||||
assert(dtsContent.includes('interface AcceptanceModeResult'), 'AcceptanceModeResult interface should be defined');
|
||||
assert(dtsContent.includes('passed: boolean'), 'AcceptanceModeResult should have passed property');
|
||||
assert(dtsContent.includes('finalAccuracy: number'), 'AcceptanceModeResult should have finalAccuracy property');
|
||||
assert(dtsContent.includes('cycles: CycleMetrics[]'), 'AcceptanceModeResult should have cycles property');
|
||||
console.log(' ✓ AcceptanceModeResult has expected structure');
|
||||
|
||||
// Verify PolicyState interface
|
||||
assert(dtsContent.includes('interface PolicyState'), 'PolicyState interface should be defined');
|
||||
assert(dtsContent.includes('contextStats'), 'PolicyState should have contextStats property');
|
||||
assert(dtsContent.includes('earlyCommitPenalties'), 'PolicyState should have earlyCommitPenalties property');
|
||||
console.log(' ✓ PolicyState has expected properties (contextStats, earlyCommitPenalties, etc.)');
|
||||
|
||||
// Verify SkipMode type
|
||||
assert(dtsContent.includes("type SkipMode = 'none' | 'weekday' | 'hybrid'"), 'SkipMode type should be defined');
|
||||
console.log(' ✓ SkipMode type defined (none | weekday | hybrid)');
|
||||
|
||||
// Verify SkipModeStats interface
|
||||
assert(dtsContent.includes('interface SkipModeStats'), 'SkipModeStats interface should be defined');
|
||||
assert(dtsContent.includes('attempts: number'), 'SkipModeStats should have attempts property');
|
||||
assert(dtsContent.includes('successes: number'), 'SkipModeStats should have successes property');
|
||||
console.log(' ✓ SkipModeStats has expected structure (attempts, successes, totalSteps, etc.)');
|
||||
|
||||
// Verify CompiledConfig interface
|
||||
assert(dtsContent.includes('interface CompiledConfig'), 'CompiledConfig interface should be defined');
|
||||
assert(dtsContent.includes('maxSteps: number'), 'CompiledConfig should have maxSteps property');
|
||||
assert(dtsContent.includes('avgSteps: number'), 'CompiledConfig should have avgSteps property');
|
||||
console.log(' ✓ CompiledConfig has expected fields (maxSteps, avgSteps, observations, etc.)');
|
||||
|
||||
// Verify CycleMetrics interface
|
||||
assert(dtsContent.includes('interface CycleMetrics'), 'CycleMetrics interface should be defined');
|
||||
assert(dtsContent.includes('cycle: number'), 'CycleMetrics should have cycle property');
|
||||
assert(dtsContent.includes('accuracy: number'), 'CycleMetrics should have accuracy property');
|
||||
assert(dtsContent.includes('costPerSolve: number'), 'CycleMetrics should have costPerSolve property');
|
||||
console.log(' ✓ CycleMetrics has expected structure (cycle, accuracy, costPerSolve)');
|
||||
|
||||
} catch (error) {
|
||||
console.error(` ✗ FAILED: ${error.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Test 3: WASM integration test (conditional)
|
||||
console.log('\nTest 3: WASM integration test');
|
||||
try {
|
||||
const wasmBinaryPath = path.join(packageDir, 'pkg', 'rvf_solver_bg.wasm');
|
||||
|
||||
if (!fs.existsSync(wasmBinaryPath)) {
|
||||
console.warn(' ⊘ SKIPPED: WASM binary not available at pkg/rvf_solver_bg.wasm');
|
||||
} else {
|
||||
console.log(' Found WASM binary, loading solver...');
|
||||
|
||||
// Try both CommonJS and ESM outputs
|
||||
let distIndex = path.join(packageDir, 'dist', 'index.mjs');
|
||||
if (!fs.existsSync(distIndex)) {
|
||||
distIndex = path.join(packageDir, 'dist', 'index.js');
|
||||
}
|
||||
|
||||
const module = await import(`file://${distIndex}`);
|
||||
const RvfSolver = module.RvfSolver || module.default?.RvfSolver;
|
||||
|
||||
// Create solver instance
|
||||
console.log(' Creating RvfSolver instance...');
|
||||
const solver = await RvfSolver.create();
|
||||
assert(solver !== null, 'Solver should be created');
|
||||
console.log(' ✓ RvfSolver.create() succeeded');
|
||||
|
||||
// Run small training session
|
||||
console.log(' Running training with count=10...');
|
||||
const trainResult = solver.train({ count: 10 });
|
||||
|
||||
// Verify result structure
|
||||
assert(typeof trainResult.trained === 'number', 'trained should be a number');
|
||||
assert(typeof trainResult.correct === 'number', 'correct should be a number');
|
||||
assert(typeof trainResult.accuracy === 'number', 'accuracy should be a number');
|
||||
// patternsLearned may be undefined if not populated by WASM, but if present should be a number
|
||||
assert(trainResult.patternsLearned === undefined || typeof trainResult.patternsLearned === 'number', 'patternsLearned should be a number or undefined');
|
||||
|
||||
// Verify expected values
|
||||
assert(trainResult.trained === 10, `trained should be 10, got ${trainResult.trained}`);
|
||||
assert(trainResult.correct >= 0 && trainResult.correct <= 10, 'correct should be between 0 and 10');
|
||||
assert(trainResult.accuracy >= 0 && trainResult.accuracy <= 1, 'accuracy should be between 0 and 1');
|
||||
assert(trainResult.patternsLearned === undefined || trainResult.patternsLearned >= 0, 'patternsLearned should be non-negative or undefined');
|
||||
|
||||
console.log(` ✓ Training result valid: trained=${trainResult.trained}, correct=${trainResult.correct}, accuracy=${(trainResult.accuracy * 100).toFixed(1)}%`);
|
||||
|
||||
// Clean up
|
||||
solver.destroy();
|
||||
console.log(' ✓ Solver destroyed successfully');
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(` ✗ FAILED: ${error.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('\n✅ All tests passed!');
|
||||
18
vendor/ruvector/npm/packages/rvf-solver/tsconfig.json
vendored
Normal file
18
vendor/ruvector/npm/packages/rvf-solver/tsconfig.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "commonjs",
|
||||
"lib": ["ES2020"],
|
||||
"declaration": true,
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"moduleResolution": "node",
|
||||
"sourceMap": true
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
Reference in New Issue
Block a user