Skip to content

Optimize exact mincut, routing and RuField spatial awareness across Rust, Node and WASM - #986

Merged
ruvnet merged 21 commits into
mainfrom
fix/mincut-correctness-performance-20260915
Sep 16, 2026
Merged

ruvnet merged 21 commits into
mainfrom
fix/mincut-correctness-performance-20260915

Conversation

@ruvnet

@ruvnet ruvnet commented Sep 15, 2026 •

Copy link
Copy Markdown
Owner

RuField spatial awareness follow up (September 16, 2026)

Integrated RuView RuField events with the exact directed road router across Rust, native Node, WASM and the npm worker API.

Key behavior:

  • Explicit zone and space cell bindings map observations to road nodes. The adapter does not project current uncalibrated CSI cells into geographic coordinates.
  • Verified live events and synthetic test events update incident arc costs or close arcs at a configured risk threshold.
  • P3 through P5 observations are rejected. Non synthetic events fail closed unless the caller confirms prior RuField TrustVerifier validation.
  • Event size, IDs, timestamps, numeric values, bindings, active sources and dedup state are bounded.
  • Independent sensors mapped to the same node are tracked separately. Routing uses the maximum live risk, and expiry of one sensor preserves other live observations.
  • Costs always derive from immutable base arcs, so repeated observations cannot compound. Expiry restores exact original costs and open states.
  • Direct mutation of the wrapped router is not exposed, preserving the restoration invariant.
  • A real signed rufield.mfs.v0.1 event emitted by the RuView bridge is included as a compatibility fixture.

Validated at a55d429:

  • 8 Rust tests passed, including independent sensor aggregation, replay, privacy, trust, time, malformed input and exact restoration.
  • 2 native Node tests and 4 WASM and worker tests passed.
  • Deep Ruflo 3.25.6 code scans found zero issues in the Rust routing directory and npm routing directory.
  • GitHub runner, real DIMACS NY graph: 264,346 nodes, 733,846 arcs, 10,000 events, ingest p50 1.345 microseconds, p95 2.625 microseconds.
  • GitHub runner, real DIMACS BAY graph: 321,270 nodes, 800,172 arcs, 10,000 events, ingest p50 1.339 microseconds, p95 2.536 microseconds.
  • Both real graph runs restored 32 sampled routes exactly after expiry. The focused routing workflow and workspace Clippy with warnings denied passed. Evidence: https://github.com/ruvnet/RuVector/actions/runs/35040036589

Trust boundary: this consumer intentionally does not reimplement RuField Ed25519 trust registry and replay policy. Hosts must set verified=true only after RuField TrustVerifier accepts the receipt. Signature shaped JSON alone is never considered proof.

README files remain unchanged. No merge or npm publication was performed.


Map and routing follow-up (September 15, 2026)

Added a separate exact directed road-routing engine alongside the undirected mincut engine. The routing API supports stable arc IDs, parallel arcs, integer costs, consecutive-arc turn prohibitions, closures and atomic cost updates. Compressed adjacency, reusable query scratch, an indexed heap and directed landmark A* accelerate repeated queries. Closures and increases preserve admissible landmark bounds; decreases and reopening discard them. Geographic nearest-vertex lookup uses a balanced 3D k-d tree on spherical coordinates, including poles and the date line.

Node exposes RoadRouter and WASM exposes WasmRoadRouter. The npm ./routing export provides a dedicated WASM worker in Node and browsers, typed declarations, a bounded request queue, timeouts and cancellation. Aborting an in-flight request terminates that worker and rejects all its pending operations. Graph inputs, scalar IDs, integer costs, coordinate ranges, batch lengths and work budgets are validated. Shared input buffers are rejected by the worker client. Query heaps contain at most one entry per state.

Reproducible validation:

  • Real DIMACS road networks: New York (264,346 vertices, 733,846 arcs) and Bay Area (321,270 vertices, 800,172 arcs). Both graph and coordinate downloads are SHA-256 pinned.
  • Fixed seed 20260915; 128 endpoint pairs per graph: 64 uniform pairs and 64 endpoints of directed 24-step random walks. Independent igraph 0.11.9 supplies expected costs.
  • Separate Dijkstra and A* scratch buffers, alternating execution order, one warm-up and three measured repetitions per pair. Returned paths are checked arc-by-arc. Timings exclude input parsing and include route reconstruction. Process RSS contains both routers and is not per-algorithm memory.
  • Sixteen controlled closure/restoration pairs have independently computed igraph expectations, including a route made unreachable. Replayed through Rust, native Node, WASM and worker APIs.
  • Four routing Rust tests include 160 seeded directed graphs with an independent Floyd-Warshall oracle on expanded turn states, weight updates, malformed inputs, cancellation, atomicity, geographic oracle comparisons and zero-cost cases.
  • Native tests: 4 passed. npm tests: 7 passed in the source package and 7 passed after isolated tarball installation. Real Chromium module-worker checks passed for routing, turn restrictions, closure, geographic lookup and abort.
  • Complete API benchmark checks 2,304 route results across native Node, WASM and worker runtimes, plus closure traces. Benchmark pipelines now fail on child errors.

Paired kernel results at 2670867, uniform endpoints (milliseconds):

Dataset Dijkstra median Landmark A* median A* p95 Paired geometric-mean speedup
NY 18.441 1.613 6.191 11.56x
BAY 21.642 2.145 12.227 8.89x

Landmark preprocessing: NY 583.0 ms, BAY 654.3 ms. Local-query geometric-mean improvements are 1.84x and 1.60x, but 5/64 NY and 15/64 BAY local pairs regress by more than 10%, mostly at microsecond/sub-microsecond scales. No sampled uniform pair regressed by more than 10%. These comparisons establish improvement over this Dijkstra baseline, not superiority over CCH, OSRM, GraphHopper or routing SOTA.

Map lookup: 256 slightly offset real-node queries per graph, exact agreement with a linear scan using precomputed spherical coordinates. Mean indexed time: NY 1.09 microseconds, BAY 1.26 microseconds; scan means 593.08 and 716.58 microseconds. Spatial construction time is reported separately.

Complete API uniform-route timing, including returned arrays and worker messaging:

Runtime NY median / p95 ms BAY median / p95 ms
native 1.326 / 4.586 1.390 / 8.585
wasm 1.621 / 6.634 1.760 / 11.446
worker 1.738 / 7.281 2.065 / 12.067

Evidence:

Security review:

  • Scope: new Rust routing/spatial modules, Node/WASM bindings, npm worker boundaries and the root lockfile. Threats: malformed graphs, stale results after updates, numeric truncation, excessive search work, queue flooding and worker lifecycle races. No network, authentication, secrets or tenant data handling was added to the routing library.
  • Enforced caps: 1M vertices, 4M arcs/turn pairs, costs <= 1e9, <=16 landmarks with <=8M vertex-landmark pairs, bounded search/preprocessing work, <=32 queued worker requests and <=128 MiB queued cloned input. Hosts must still choose limits appropriate to available memory; synchronous bindings are not a service-level resource sandbox.
  • Read-only Ruflo 3.25.6 security scans (--depth deep --type all) on the routing core, Node/WASM routing bindings and final npm routing directory reported no findings. Manual review and regression tests cover atomic updates, integer validation, invalid coordinates, shared buffers, cancellation, queue limits and timeouts. These scans do not certify the entire repository.
  • Fixed public advisory RUSTSEC-2026-0285: Rustls 0.23.41 -> 0.23.45 and webpki 0.103.13 -> 0.103.15. Entries were taken from a Cargo-resolved, compiled dependency graph; workspace lockfile integrity and audit pass. No production dependency was added.
  • Advisory evidence: cargo-audit 0.22.2, September 15, 2026, 1,246 loaded advisories; Cargo.lock SHA-256 301a651013671209b7a6d845a3cf8068b851fdebe71dac9e4bd753ab4290f81c. The audit reported a crates.io-index refresh warning, so this is not a complete yanked-package assessment.
  • Existing allowed informational warnings remain for rustls-pemfile 2.2.0 and lru 0.12.5/0.16.4 (transitive via ratatui/lattice-embed). They were not introduced by this routing change. No claim that the full workspace is vulnerability-free.

Practical limits: these historical DIMACS graphs have known map gaps and contain no current OSM access policy. This API consumes normalized directed graphs; an OSM importer must resolve access, conditional and complex via-way rules before construction. The native turn model prohibits consecutive arc pairs. Geographic snapping returns the nearest vertex, not a point along an edge. We have not built a live navigation service, map renderer, turn-by-turn instructions, or a competing SOTA routing-engine baseline. Longer-term acceleration and current OSM integration remain separate work.

README files remain unchanged. PR is open for review; no merge or npm publication was performed.


Real-data optimization follow-up (September 15, 2026)

Implemented linear-time structural certificates and an indexed maximum-adjacency heap in the exact kernel. For a connected simple weighted graph, every cut is either a bridge or contains at least two edges. Therefore the cut value is at least min(lightest bridge, twice the lightest edge). A bridge or singleton partition is returned early only when it meets that bound. All other inputs still use the exact contraction solver. The iterative DFS avoids native and WASM stack overflow; heap updates retain only one entry per active vertex.

Added explicit Node clear() to release graph allocations and cached state without waiting for JavaScript garbage collection, while retaining solver configuration.

Data and methodology:

  • Four real public SNAP sources: European institution email, GR-QC collaborations, Facebook social circles, and HepPh collaborations.
  • 11 frozen workload views: largest connected components, 2-cores, 4-cores, and email reciprocity weights derived from observed communication directions. Removed self loops and collapsed duplicate/directed pairs explicitly. Reciprocity is not message frequency.
  • Email and GR-QC were development datasets; Facebook and HepPh were held out from optimization design. Dense core views prevent leaf cuts from hiding fallback costs.
  • Pinned source SHA-256 hashes and igraph 0.11.9 reference answers. CI artifacts contain normalized inputs, provenance, raw results, and runtime measurements.
  • Three kernel solves per case, median on one GitHub runner, same compiler and inputs, compared with revision 93fdf5e. Parsing is outside the kernel timer. Each solve checks both value and partition crossing weight.
  • A 90-second budget applies to the complete three-solve baseline case. Timed-out cases have no speedup ratio. Timeout cleanup kills the entire process group before subsequent measurements.

Verified paired kernel and runtime run, kernel code unchanged by the subsequent Node clear() addition:

Workload Vertices Edges Baseline kernel ms Optimized kernel ms Ratio
email-Eu-core-lcc 986 16064 767.029 0.798 960.99x
email-Eu-core-core2 891 15969 613.495 0.846 725.01x
email-Eu-core-core4 817 15784 504.620 225.114 2.24x
email-Eu-core-core4-reciprocity 817 15784 529.964 223.652 2.37x
ca-GrQc-lcc 4158 13422 3095.229 1.102 2809.97x
ca-GrQc-core2 3413 12677 2150.977 1.117 1924.99x
facebook_combined-lcc 4039 88234 20872.084 3.604 5792.02x
facebook_combined-core2 3964 88159 20566.981 3.613 5691.94x
facebook_combined-core4 3754 87666 18254.208 4987.304 3.66x
ca-HepPh-lcc 11204 117619 90 s case timeout 6.840 n/a
ca-HepPh-core2 10051 116466 90 s case timeout 7.017 n/a

Kernel process peak RSS on the Facebook largest component fell from 12,544 KiB to 9,624 KiB, about 23%. These measurements include the benchmark process and input storage, not just heap entries. The indexed heap alone has O(n) entries instead of accumulating O(m) stale entries. Total graph storage remains O(n+m).

Validation:

  • 159 focused Rust tests, including 33,792 exhaustive topology cases, 1,024 additional seeded weighted cases, a weighted bridge counterexample, and a 100,000-vertex iterative-DFS test.
  • Native and WASM real-data runs check 66 graph builds and 72 controlled delete/restore operations against independent reference values and matching partitions. The update replay uses observed edges but is not a historical event stream.
  • Runtime reports include construction median, query p50/p95/p99, update p50/p95, sample counts, and cumulative process peak RSS. Update tail samples are small (18 per tested graph/runtime); no production p99 claim.
  • Largest validated real view: 11,204 vertices and 117,619 edges. Million-vertex scalability and real-browser frame responsiveness remain unvalidated.
  • Dense Facebook core still takes seconds. Large certificate gains are workload-specific, and do not establish a new general asymptotic bound.

Acceptance: rerun MinCut regression and MinCut real data. All optimized cases must complete and every checked value/partition must agree with the igraph oracle; baseline timeouts remain visible. Review the dense-core rows separately from certificate fast paths.

Latest head e23dc31:

  • Focused regression workflow passes all jobs, including 3 native runtime tests and npm package installation.
  • Workspace Clippy and formatting pass.
  • Real Node/WASM runtime job passes with explicit native cleanup. The earlier paired kernel run above tests the identical kernel.
  • Largest graph construction median through the complete API: native 103.87 ms, WASM 111.06 ms.
  • Dense Facebook core construction remains native 4771.79 ms, WASM 5481.42 ms. Move long solves off interactive threads before deploying that workload in a UI.
  • Local and remote trees match. No README edits, merge, or npm publication.

Earlier implementation and synthetic benchmark evidence

The public dynamic solver could return a cut value without a matching partition, reuse stale canonical results, and spend time maintaining structures that were not supplying a correct global cut. WASM batches also solved after every edge, and weight replacement could remove an edge before rejecting its replacement.

This PR improves the implementation and JavaScript distribution. README files are unchanged.

Changes:

  • Use a sparse exact Stoer-Wagner kernel with a matching cached partition and crossing edges, including tree and disconnected-graph paths.
  • Skip solves for insertions and weight increases within a cached side, and for deletions and weight decreases across the cached partition. These operations provably preserve its optimality. Refresh crossing weights from original edges to avoid subtractive drift.
  • Add validated Rust batch insertion/deletion with at most one solve. Invalid weights, duplicate undirected edges, and missing deletions leave graph state and update statistics unchanged. As with other updates, direct external mutation through graph() is outside this cache-maintenance contract.
  • Add Node and WASM typed-array insertion batches, Node typed deletion batches, and safe weight updates that retain existing edge IDs.
  • Reject lossy Number vertex IDs in WASM array APIs and invalid approximate epsilon values before Node constructors can panic. Normalize empty cut values to positive zero.
  • Avoid allocating partition and edge vectors for Node's scalar minCut() result.
  • Make the unused ruvector-core dependency optional; the simd feature continues to activate it.
  • Add @ruvector/mincut-wasm packaging with Node CommonJS/ESM consumption, a browser ESM entry, generated declarations, explicit WASM exports, prepack artifact validation, and installed-tarball tests.
  • Fix canonical cache invalidation and successful-prefix error bookkeeping in the pre-existing canonical batch API. This remains distinct from the new all-or-nothing main-solver batches.

Compatibility:

  • Existing JavaScript methods remain available. WASM scalar u64 endpoints remain BigInt; array inputs accept safe integer Numbers; new packed endpoints use Uint32Array with Float64Array weights.
  • Invalid WASM batches now make no partial changes, and invalid Number IDs now throw instead of silently truncating.
  • wasm-bindgen copies typed slices across the boundary; this is not a zero-copy claim.
  • The npm package has not been published. CI builds and tests release artifacts on Linux/Node 22; the browser entry is initialized from bytes under Node, not exercised in a real browser.

Research assessment:

  • Faster Pseudo-Deterministic Minimum Cut (February 2026) gives weighted static O(m log² n) and fully dynamic unweighted polylogarithmic updates with near-linear queries. Those dynamic bounds do not apply to this arbitrary weighted API. The existing source-anchored canonical consumers retain regression coverage; this PR does not implement the paper's faster backend.
  • Exact fully dynamic bounded minimum cut (December 2025) has cut-size restrictions, with a separate randomized approximation result for weighted graphs. The implemented fast paths use directly checkable cut-preservation conditions, with an exact polynomial fallback. No subpolynomial bound is claimed.
  • NAPI-RS v3 adds WASI thread support and lifetime changes. The workspace uses v2 across multiple crates; this scoped change retains its ABI and improves the existing browser-compatible wasm-bindgen package rather than introducing a workspace-wide migration.

Validation at 93fdf5e:

  • MinCut regression workflow: all three jobs pass.
  • 156 focused Rust tests pass: 2 standalone kernel tests, 8 public API tests, 24 algorithm tests, 23 graph tests, and 99 canonical tests. The two exhaustive oracles cover 33,792 weighted graph topologies.
  • Native addon: 2 runtime tests pass.
  • WASM package: 4 runtime tests pass, then all 4 pass again after installing the npm tarball in an isolated consumer.
  • Scoped rustfmt and the full workspace Clippy (deny warnings) and Rustfmt jobs pass: https://github.com/ruvnet/RuVector/actions/runs/35031362936. Other workspace checks are tracked separately; this is not a claim that every workspace test passes.
  • Local and remote Git trees match. README files and Cargo.lock are unchanged.

Measured release-mode medians on the same GitHub runner, 40 vertices, 780 edges, five repetitions after warmup:

Runtime Individual insert calls Typed batch Ratio
Native Node addon 24.289 ms 0.591 ms 41.1x
WASM under Node 30.552 ms 0.922 ms 33.1x

Both paths assert the same final exact cut value. These are synthetic batch-construction measurements, not universal speedup or latency guarantees. New batches reduce both boundary crossings and intermediate solves. The generated WASM binary is 352,870 bytes; the npm tarball containing both Node and web distributions is 257.3 kB.

Reproduce after building bindings using npm/packages/mincut-wasm/bench/batch.cjs. The workflow builds bindings and generates matching wasm-bindgen glue automatically, runs the benchmark, packs the package, and tests installation. The public Rust benchmark now compares against the previously verified c92142b revision; the original repository implementation can fail nondeterministically with duplicate-edge errors during its benchmark. The historical original-base comparison remains available in the earlier validated run.

The package is prepared for review, not published. Existing dependency security findings are not suppressed or bundled into this focused patch.

@ruvnet
ruvnet marked this pull request as ready for review September 15, 2026 22:05
@ruvnet ruvnet changed the title Fix dynamic mincut correctness and eliminate redundant maintenance Fix and optimize mincut core, WASM batches, Node bindings, and npm packaging Sep 15, 2026
@ruvnet ruvnet changed the title Fix and optimize mincut core, WASM batches, Node bindings, and npm packaging Optimize exact mincut on real SNAP graphs, WASM and Node with independent validation Sep 15, 2026
@ruvnet ruvnet changed the title Optimize exact mincut on real SNAP graphs, WASM and Node with independent validation Optimize exact mincut and directed road routing across Rust, Node and WASM Sep 15, 2026
@ruvnet ruvnet changed the title Optimize exact mincut and directed road routing across Rust, Node and WASM Optimize exact mincut, routing and RuField spatial awareness across Rust, Node and WASM Sep 16, 2026
@ruvnet
ruvnet merged commit 512d5d8 into main Sep 16, 2026
56 of 57 checks passed
@ruvnet
ruvnet deleted the fix/mincut-correctness-performance-20260915 branch September 16, 2026 03:33
ruvnet added a commit that referenced this pull request Sep 16, 2026
…fixes) (#987)

Manually applies the version bumps from dependabot PRs #975 and #957,
which couldn't be cleanly rebased (dependabot didn't respond to
@dependabot rebase, and both showed CONFLICTING after #986/#980/#944/#981
touched the same lockfile). Only the two resolved-package entries changed
in package-lock.json; neither is a direct dependency.

hono 4.13.1->4.13.7 fixes: XSS via unescaped strings in hono/jsx boundary
components (GHSA-hxh3-vqpv-xpqv), SSRF/cache-key confusion in query
parsing past URL fragments, an incomplete-fix follow-up for toSSG() path
traversal (CVE-2026-39408), and memory exhaustion via unbounded
dot-notation in parseBody().

fast-uri 3.1.4->3.1.7 fixes: authority injection via unvalidated port in
serialize(), host confusion via malformed IP-literal brackets, SSRF via
repeated hostname percent-decoding and malformed IPv6 normalization, and
host confusion via percent-encoded scheme normalization.

Closes #975, #957.


Claude-Session: https://claude.ai/code/session_01SjxUvZnyBdwtx4Y1jKAqt6
ruvnet added a commit that referenced this pull request Sep 16, 2026
…rtifacts (#990)

Publishing the PR #986 mincut work (exact Stoer-Wagner, directed routing,
RuField) surfaced three blockers.

1. ruvector-mincut-node and ruvector-mincut-wasm pinned
   `ruvector-mincut = "2.0"`. At publish time cargo strips the path dep, so
   that caret range resolves to the published 2.0.6 -- the OLD spanning-tree
   heuristic that #986 replaced because it is not exact. The bindings would
   have shipped built against the bug they were meant to fix. Now "2.3".

2. ruvector-graph-condense, ruvector-graph-condense-wasm and
   ruvector-perception pinned `ruvector-mincut = "2.2.3"`, a version that was
   never published (crates.io max is 2.0.6) and never will be (workspace is
   2.3.0). Now "2.3".

3. npm/packages/mincut-wasm declared main/types/exports/files over node/ and
   web/ directories that did not exist in git, and no workflow builds them,
   so `npm publish` could not produce a working package. Both targets are now
   built with wasm-pack and committed. The wasm-pack-generated .gitignore in
   each output dir is deliberately removed: npm honours it, and with it in
   place the tarball shipped 5 files (4 kB, no wasm at all) instead of 17
   (386 kB).

Verified: cargo check passes for both bindings against the 2.3 pin; the npm
package's own prepack gate passes; 9/9 package tests pass against the real
artifacts; and a tarball installed into a clean project computes the exact
min cut (6) and a directed route (cost 20) end to end.
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.

1 participant