Skip to content

Commit de823e0

Browse files
ruvnetruvnet
andauthored
fix(ruvector): remove dead external parallel-worker import + CI guard (#531) (#532)
* fix(ruvector): remove dead external parallel-worker import (#531) The ONNX embedder dynamically imported `ruvector-onnx-embeddings-wasm/parallel` in two places — a package that was never published, never declared in package.json, and explicitly rejected in ADR-194. Both import sites resolved into catch blocks, so the external multi-core path was dead code while `detectParallelAvailable()` reported availability based on the missing package. - onnx-embedder.ts: drop both `import('ruvector-onnx-embeddings-wasm/parallel')` sites; `tryInitParallel()` now goes straight to the bundled, zero-dependency worker pool (`onnx/bundled-parallel.mjs`) — the only parallel implementation. - `detectParallelAvailable()` now probes the bundled pool file instead of the unpublished external package, so the capability signal is correct. - Runtime behavior is preserved: the old external attempt always threw, and 'auto'/false already fell through to return false. - CI: add a guard step to ruvector-npm-ci that fails the build if any source re-introduces an import/require/from of the dead package (doc comments OK). - Bump 0.2.27 → 0.2.28. Validated: tsc clean, `node --test tests/*.test.mjs` 8/8 pass (incl. worker-pool cosine-equivalence), guard verified to fire on a reintroduced import. Closes #531 Co-Authored-By: claude-flow <ruv@ruv.net> * fix(ci): ruvector smoke uses --dimension (CLI flag is singular, not --dimensions) The functional-smoke job called `create --dimensions 64` but the CLI option is `-d, --dimension`. Pre-existing failure on main, surfaced while shipping #531. Co-Authored-By: claude-flow <ruv@ruv.net> --------- Co-authored-by: ruvnet <ruvnet@gmail.com>
1 parent 712e22c commit de823e0

3 files changed

Lines changed: 39 additions & 34 deletions

File tree

.github/workflows/ruvector-npm-ci.yml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,19 @@ jobs:
4040
- name: Install (isolated from workspace)
4141
run: npm install --no-audit --no-fund --legacy-peer-deps --no-workspaces --no-optional
4242

43+
- name: Guard — no dead external parallel-worker import (issue #531)
44+
run: |
45+
# `ruvector-onnx-embeddings-wasm/parallel` was never published and is
46+
# rejected by ADR-194. The bundled worker pool
47+
# (onnx/bundled-parallel.mjs) is the only parallel implementation.
48+
# Fail if any source re-introduces an import/require/from of the dead
49+
# package. Doc comments that merely mention the name are allowed.
50+
if grep -rnE "(import|require|dynamicImport)[[:space:]]*\([[:space:]]*['\"]ruvector-onnx-embeddings-wasm/parallel['\"]|from[[:space:]]+['\"]ruvector-onnx-embeddings-wasm/parallel['\"]" src/; then
51+
echo "::error::Dead external import of 'ruvector-onnx-embeddings-wasm/parallel' found — package is unpublished and rejected by ADR-194. Use the bundled onnx/bundled-parallel.mjs pool instead (issue #531)."
52+
exit 1
53+
fi
54+
echo "Guard OK: no dead external parallel-worker import in src/."
55+
4356
- name: Build
4457
# tsc exits non-zero on pre-existing errors but still emits dist/
4558
# (noEmitOnError is not set in tsconfig, defaults to false).
@@ -160,7 +173,7 @@ jobs:
160173
TMP=$(mktemp -d)
161174
DB="$TMP/smoke.db"
162175
163-
node bin/cli.js create "$DB" --dimensions 64
176+
node bin/cli.js create "$DB" --dimension 64
164177
echo "Created DB at $DB"
165178
166179
# Generate 200 random float32 vectors as JSON and insert them

npm/packages/ruvector/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ruvector",
3-
"version": "0.2.27",
3+
"version": "0.2.28",
44
"description": "Self-learning vector database for Node.js — hybrid search, Graph RAG, FlashAttention-3, HNSW, 50+ attention mechanisms",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

npm/packages/ruvector/src/core/onnx-embedder.ts

Lines changed: 24 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,17 @@ export function isOnnxAvailable(): boolean {
118118
}
119119

120120
/**
121-
* Check if parallel workers are available (npm package installed)
121+
* Check whether the bundled parallel worker pool can be loaded — i.e. the
122+
* `onnx/bundled-parallel.mjs` file ships in the package. This reflects the
123+
* *bundled* pool (the only parallel implementation), NOT the unpublished
124+
* external `ruvector-onnx-embeddings-wasm/parallel` package, which was rejected
125+
* in ADR-194. See https://github.com/ruvnet/RuVector/issues/531.
122126
*/
123-
async function detectParallelAvailable(): Promise<boolean> {
127+
function detectParallelAvailable(): boolean {
124128
try {
125-
await dynamicImport('ruvector-onnx-embeddings-wasm/parallel');
126-
parallelAvailable = true;
127-
return true;
129+
const poolPath = path.join(__dirname, 'onnx', 'bundled-parallel.mjs');
130+
parallelAvailable = fs.existsSync(poolPath);
131+
return parallelAvailable;
128132
} catch {
129133
parallelAvailable = false;
130134
return false;
@@ -145,39 +149,27 @@ function detectSimd(): boolean {
145149
}
146150

147151
/**
148-
* Try to load ParallelEmbedder from npm package (optional)
152+
* Initialize the bundled, zero-dependency worker pool for batch throughput.
153+
*
154+
* Opt-in only (`enableParallel === true`) so the default/'auto' path does not
155+
* silently spawn worker threads for existing callers. Output vectors are
156+
* bit-identical to the single-thread path (issue #523).
157+
*
158+
* The previously-referenced external package
159+
* `ruvector-onnx-embeddings-wasm/parallel` was never published and was rejected
160+
* in ADR-194; the bundled pool (`onnx/bundled-parallel.mjs`) is the only
161+
* parallel implementation. See https://github.com/ruvnet/RuVector/issues/531.
149162
*/
150163
async function tryInitParallel(config: OnnxEmbedderConfig): Promise<boolean> {
151-
// Skip if explicitly disabled
152-
if (config.enableParallel === false) return false;
153-
154-
// 1) Optional external package (back-compat). Absent by default.
155-
try {
156-
const parallelModule = await dynamicImport('ruvector-onnx-embeddings-wasm/parallel');
157-
const { ParallelEmbedder } = parallelModule;
158-
159-
parallelEmbedder = new ParallelEmbedder({
160-
numWorkers: config.numWorkers,
161-
});
162-
await parallelEmbedder.init(config.modelId || DEFAULT_MODEL);
163-
164-
parallelThreshold = config.parallelThreshold || 4;
165-
parallelEnabled = true;
166-
parallelAvailable = true;
167-
console.error(`Parallel embedder ready (external): ${parallelEmbedder.numWorkers} workers, SIMD: ${simdAvailable}`);
168-
return true;
169-
} catch {
170-
// External package not installed — fall through to the bundled pool.
171-
}
172-
173-
// 2) Bundled, zero-dependency worker pool over the already-loaded model bytes.
174-
// Opt-in only (enableParallel === true) so the default/'auto' path does not
175-
// silently spawn worker threads for existing callers. Vectors are identical
176-
// to the single-thread path (issue #523).
164+
// Skip unless parallelism is explicitly requested (covers false and 'auto').
177165
if (config.enableParallel !== true) {
178166
parallelAvailable = false;
179167
return false;
180168
}
169+
if (!detectParallelAvailable()) {
170+
console.error('Parallel embedder not available: bundled worker pool (onnx/bundled-parallel.mjs) missing');
171+
return false;
172+
}
181173
try {
182174
if (!loadedModelBytes || !loadedTokenizerJson) {
183175
throw new Error('model bytes unavailable for bundled pool');

0 commit comments

Comments
 (0)