Files
wifi-densepose/vendor/ruvector/docs/research/agentic-robotics/crate-review.md

49 KiB

Agentic Robotics Crate-by-Crate Deep Review

Date: 2026-02-27 Reviewer: Research Agent Source Location: /home/user/ruvector/crates/agentic-robotics-*/ Total Crates: 6 Total Lines of Rust: 2,635 (source + benchmarks)


Table of Contents

  1. Crate 1: agentic-robotics-core
  2. Crate 2: agentic-robotics-rt
  3. Crate 3: agentic-robotics-mcp
  4. Crate 4: agentic-robotics-embedded
  5. Crate 5: agentic-robotics-node
  6. Crate 6: agentic-robotics-benchmarks
  7. Cross-Crate Dependency Graph
  8. Overall Assessment
  9. Integration Roadmap for ruvector

Crate 1: agentic-robotics-core

Path: /home/user/ruvector/crates/agentic-robotics-core/ Line Count: 705 lines (669 source + 36 bench) Complexity Estimate: Low-Medium Code Quality Rating: B

File Inventory

File Lines Purpose
src/lib.rs 45 Root module, re-exports, init() function
src/message.rs 119 Message trait and concrete message types
src/publisher.rs 85 Generic typed publisher with stats tracking
src/subscriber.rs 91 Generic typed subscriber with crossbeam channels
src/service.rs 127 RPC service server (Queryable) and client (Service)
src/middleware.rs 66 Zenoh middleware abstraction (placeholder)
src/serialization.rs 107 CDR/JSON/rkyv serialization pipeline
src/error.rs 29 Error types using thiserror
benches/message_passing.rs 36 Criterion benchmark for publish + serialization

Purpose

ROS3 Core provides the foundational pub/sub messaging layer modeled after ROS2 but rewritten in Rust. It targets microsecond-scale determinism with Zenoh as the middleware transport (currently stubbed) and supports CDR, JSON, and rkyv serialization formats.

API Surface

Traits

pub trait Message: Serialize + for<'de> Deserialize<'de> + Send + Sync + 'static {
    fn type_name() -> &'static str;
    fn version() -> &'static str { "1.0" }
}

The Message trait is the central abstraction. It requires serde bounds plus Send + Sync + 'static for async safety. A blanket implementation exists for serde_json::Value, enabling generic JSON message passing.

Public Types

Type Module Description
Message (trait) message Core message trait with type_name/version
RobotState message position: [f64; 3], velocity: [f64; 3], timestamp: i64
Point3D message x/y/z as f32, Copy-able
PointCloud message Vec + Vec intensities + timestamp
Pose message position: [f64; 3], orientation: [f64; 4] (quaternion)
Publisher<T: Message> publisher Generic typed publisher with stats
Subscriber<T: Message> subscriber Generic typed subscriber with crossbeam channels
Queryable<Req, Res> service RPC server with handler function
Service<Req, Res> service RPC client (stub)
ServiceHandler<Req, Res> service Arc<dyn Fn(Req) -> Result<Res> + Send + Sync>
Zenoh middleware Zenoh session wrapper (placeholder)
ZenohConfig middleware mode, connect, listen configuration
Format serialization Enum: Cdr, Rkyv, Json
Serializer serialization Format-aware serializer wrapper
Error error Zenoh/Serialization/Connection/Timeout/Config/Io/Other
Result<T> error std::result::Result<T, Error>

Public Functions

Function Module Signature
init() lib fn init() -> Result<()> -- initializes tracing
serialize_cdr<T: Serialize> serialization fn(msg: &T) -> Result<Vec<u8>>
deserialize_cdr<T: Deserialize> serialization fn(data: &[u8]) -> Result<T>
serialize_rkyv<T: Serialize> serialization fn(msg: &T) -> Result<Vec<u8>> -- STUB, returns Err
serialize_json<T: Serialize> serialization fn(msg: &T) -> Result<String>
deserialize_json<T: Deserialize> serialization fn(data: &str) -> Result<T>

Architecture Analysis

Message Flow

Application Code
    |
    v
Publisher<T>.publish(&msg)
    |
    v
Serializer.serialize(msg) --> Format dispatch
    |           |           |
    v           v           v
  CDR         JSON        rkyv (stub)
    |
    v
[Wire: Zenoh placeholder -- no actual network send]
    |
    v
Stats update (messages_sent++, bytes_sent += len)

The publish path is: Publisher::publish() -> Serializer::serialize() -> stats update. There is no actual Zenoh network transmission -- the middleware layer (middleware.rs) is a placeholder that creates an Arc<RwLock<()>>. The publisher simply serializes and tracks byte counts.

Serialization Pipeline

Three formats are supported but at different maturity levels:

  • CDR (Common Data Representation): Fully functional via the cdr crate. Uses big-endian encoding (CdrBe). This is the default format and provides DDS-compatible wire representation.
  • JSON: Fully functional via serde_json. Used primarily for debugging and for the NAPI boundary in the node crate.
  • rkyv (zero-copy): Declared in derives (Archive, RkyvSerialize, RkyvDeserialize) on message types but the serialize_rkyv() function returns Err("rkyv serialization not fully implemented"). The rkyv derives are present on RobotState, Point3D, PointCloud, and Pose, so the infrastructure is prepared but the serialization function is incomplete.

Subscriber Architecture

The subscriber uses crossbeam::channel::unbounded() for message delivery. This is a multi-producer multi-consumer channel but in the current implementation, messages never actually arrive because there is no Zenoh transport connection. The recv_async() method wraps the blocking crossbeam::channel::recv() in tokio::task::spawn_blocking(), which is correct for bridging sync/async boundaries but adds thread pool overhead.

The subscriber holds both a Receiver and a shared Arc<Sender> (_sender), which keeps the channel alive. The Clone implementation shares both the receiver and sender, enabling multiple concurrent readers -- though crossbeam's Receiver::clone() actually creates another consumer on the same channel, meaning messages are load-balanced (each message goes to one reader), not broadcast.

Service/RPC

The Queryable struct is a synchronous handler wrapped as Arc<dyn Fn(Req) -> Result<Res>>. Despite handle() being async fn, the actual handler execution is synchronous -- there is no .await in the handler call itself. The Service client is fully stubbed, always returning an error.

Dependency Analysis

Dependency Purpose Weight
zenoh (workspace) Middleware transport Heavy -- Zenoh pulls in many transitive deps
rustdds (workspace) DDS compatibility Heavy -- full DDS implementation
tokio (workspace) Async runtime Standard
serde + serde_json Serialization Standard
cdr (workspace) CDR binary encoding Light
rkyv (workspace) Zero-copy archives Medium
anyhow + thiserror Error handling Light
tracing + tracing-subscriber Logging Light
parking_lot (workspace) Fast mutexes/rwlocks Light
crossbeam (workspace) Lock-free channels Light

Notable: Both zenoh and rustdds are listed as dependencies but neither is actually used in the source code. They are workspace-level declarations for future integration. This inflates compile time and binary size significantly for no runtime benefit.

Code Quality Assessment

Test Coverage: 8 tests across 6 modules. Tests cover:

  • init() success path
  • RobotState default values and type_name
  • PointCloud default and type_name
  • Publisher publish + stats verification
  • Subscriber creation and try_recv (empty)
  • Queryable handler execution + stats
  • Service client creation
  • Zenoh session creation

Tests are present but shallow -- they only test the happy path and default construction. No tests for:

  • Serialization round-trips across all formats
  • Error paths (malformed data, channel disconnect)
  • Concurrent publisher/subscriber interaction
  • PointCloud with actual data
  • Pose message operations

Error Handling: Uses thiserror with 7 variant Error enum. Error propagation is clean with ? operator. The anyhow integration via #[from] on the Other variant provides a catch-all. However, serialize_rkyv() returns a string error instead of a proper rkyv-specific error.

Documentation: Module-level doc comments on all files. Individual function docs are present on public API methods. No examples in doc comments.

Safety: No unsafe code. All synchronization uses parking_lot (which has well-audited unsafe internally) and crossbeam. PhantomData usage is correct for zero-sized type markers.

Concerns:

  1. serialize_rkyv() is misleadingly typed -- it accepts T: Serialize (serde) not T: rkyv::Serialize, so it could never actually perform rkyv serialization.
  2. Publisher::publish() is async but contains no actual await points (serialization is sync, stats update is sync). The method could be synchronous.
  3. The Zenoh struct holds _config and _inner with underscore prefixes, indicating they are acknowledged as unused placeholders.
  4. tracing_subscriber::fmt().init() in init() will panic if called twice (standard tracing limitation). No guard against double-init.

Integration Points with ruvector

  1. PointCloud <-> Vector Data: PointCloud stores Vec<Point3D> (3D f32 vectors) and Vec<f32> intensities. This maps directly to ruvector's core vector storage. A thin adapter could expose PointCloud.points as a collection of 3-dimensional vectors for HNSW indexing, nearest-neighbor search, or GNN node features.

  2. Message Trait for Distributed Vectors: The Message trait could be implemented on ruvector's core types (e.g., embedding vectors, search results) to enable pub/sub distribution of vector operations across nodes.

  3. Serialization Synergy: ruvector already has its own serialization needs. The CDR format could be used for DDS-compatible vector streaming (e.g., real-time sensor embeddings). The rkyv format, once completed, aligns with ruvector's zero-copy philosophy.

  4. Publisher/Subscriber for Vector Streaming: Real-time embedding pipelines (sensor data -> encoder -> vector -> HNSW insert) could use the pub/sub pattern with typed publishers for specific vector dimensions.


Crate 2: agentic-robotics-rt

Path: /home/user/ruvector/crates/agentic-robotics-rt/ Line Count: 512 lines (483 source + 29 bench) Complexity Estimate: Medium Code Quality Rating: B-

File Inventory

File Lines Purpose
src/lib.rs 60 RTPriority enum, re-exports
src/executor.rs 157 Dual-runtime executor (high/low priority)
src/scheduler.rs 121 BinaryHeap priority scheduler
src/latency.rs 145 HDR histogram latency tracking
benches/latency.rs 29 Criterion benchmarks

Purpose

Provides a dual-runtime real-time execution framework. The core idea is to maintain two separate Tokio runtimes: a high-priority runtime with 2 worker threads for sub-millisecond deadline tasks (control loops), and a low-priority runtime with 4 worker threads for relaxed-deadline tasks (planning, perception). Tasks are routed between runtimes based on their deadline requirements.

Architecture

Dual-Runtime Design

                    ROS3Executor
                   /            \
        tokio_rt_high          tokio_rt_low
        (2 threads)            (4 threads)
        "ros3-rt-high"         "ros3-rt-low"
              |                      |
     deadline < 1ms           deadline >= 1ms
     (control loops)          (planning tasks)

The ROS3Executor creates two independent Tokio multi-threaded runtimes during construction. The routing decision in spawn_rt() is simple: if deadline.0 < Duration::from_millis(1), the task goes to the high-priority runtime; otherwise it goes to the low-priority runtime. This is a coarse-grained approach -- the actual Tokio scheduler within each runtime does not respect priorities, so the "high-priority" runtime is simply a smaller, dedicated thread pool.

Priority System

Two overlapping priority systems exist:

  1. RTPriority (in lib.rs): 5-level enum (Background=0, Low=1, Normal=2, High=3, Critical=4). Supports From<u8> conversion with saturation at Critical for values >= 4.

  2. Priority (in executor.rs): Simple newtype wrapper Priority(pub u8). Used by the executor's spawn_rt().

The spawn_rt() method converts Priority(u8) to RTPriority via .into() for debug logging, but the priority value is never actually used for scheduling. Only the deadline threshold determines runtime assignment. The PriorityScheduler instance is stored in the executor but never consulted during spawn.

PriorityScheduler

The scheduler maintains a BinaryHeap<ScheduledTask> with ordering: higher RTPriority first, then earlier deadline (reverse chronological within same priority). The Ord implementation is correct for a max-heap with priority-first, deadline-second ordering.

However, the scheduler is entirely disconnected from the executor. The schedule() method creates ScheduledTask entries with Instant::now() + deadline and auto-incrementing task_id, but the executor never calls schedule() or next_task(). The scheduler exists as infrastructure for a future implementation.

LatencyTracker

The most complete component. Uses hdrhistogram::Histogram<u64> with 3 significant digits for microsecond-precision latency tracking. Key features:

  • Thread-safe: Histogram wrapped in Arc<Mutex<Histogram>> (parking_lot mutex)
  • Non-blocking record: record() uses try_lock() -- measurements are silently dropped if the mutex is contended, preventing latency measurement from introducing latency
  • RAII measurement: LatencyMeasurement guard records elapsed time on drop
  • Rich statistics: LatencyStats provides min, max, mean, p50, p90, p99, p99.9 percentiles
  • Display implementation: Human-readable output with units

API Surface

Public Types

Type Module Description
RTPriority lib 5-level priority enum (Background..Critical)
ROS3Executor executor Dual-runtime task executor
Priority executor Priority(pub u8) newtype
Deadline executor Deadline(pub Duration) newtype with From<Duration>
PriorityScheduler scheduler BinaryHeap-based priority task queue
ScheduledTask scheduler Task entry with priority, deadline, task_id
LatencyTracker latency HDR histogram-based latency tracker
LatencyStats latency Statistics snapshot (count, min, max, mean, percentiles)
LatencyMeasurement latency RAII drop guard for automatic timing

Key Methods

// Executor
impl ROS3Executor {
    pub fn new() -> Result<Self>
    pub fn spawn_rt<F: Future>(&self, priority: Priority, deadline: Deadline, task: F)
    pub fn spawn_high<F: Future>(&self, task: F)     // Priority(3), 500us deadline
    pub fn spawn_low<F: Future>(&self, task: F)      // Priority(1), 100ms deadline
    pub fn spawn_blocking<F, R>(&self, f: F) -> JoinHandle<R>
    pub fn high_priority_runtime(&self) -> &Runtime
    pub fn low_priority_runtime(&self) -> &Runtime
}

// Scheduler
impl PriorityScheduler {
    pub fn new() -> Self
    pub fn schedule(&mut self, priority: RTPriority, deadline: Duration) -> u64
    pub fn next_task(&mut self) -> Option<ScheduledTask>
    pub fn pending_tasks(&self) -> usize
    pub fn clear(&mut self)
}

// Latency
impl LatencyTracker {
    pub fn new(name: impl Into<String>) -> Self
    pub fn record(&self, duration: Duration)
    pub fn stats(&self) -> LatencyStats
    pub fn reset(&self)
    pub fn measure(&self) -> LatencyMeasurement
}

Dependency Analysis

Dependency Purpose Weight
agentic-robotics-core (path) Core types Internal
tokio (workspace) Async runtimes Standard
parking_lot (workspace) Fast mutexes Light
crossbeam (workspace) Lock-free primitives Light -- unused in source
rayon (workspace) Data parallelism Medium -- unused in source
anyhow (workspace) Error handling Light
thiserror (workspace) Error derives Light -- unused in source
tracing (workspace) Logging Light
hdrhistogram (workspace) Latency histograms Light

Notable: crossbeam, rayon, and thiserror are declared as dependencies but not used in any source file. The agentic-robotics-core dependency is declared but also not directly used -- no imports from it exist in the rt crate's source.

Code Quality Assessment

Test Coverage: 5 tests across 3 modules:

  • RTPriority u8 conversion round-trip
  • Executor creation success
  • Spawn high priority (no completion verification -- uses thread::sleep then no assertion)
  • Scheduler priority ordering (3-task dequeue order)
  • LatencyTracker record + stats verification
  • LatencyMeasurement RAII guard

The test_spawn_high_priority test is effectively a no-op -- it spawns a task and sleeps but never checks the completed AtomicBool's final value.

Error Handling: The Default implementation for ROS3Executor calls .expect() which will panic on failure. This is appropriate for a default constructor but could be surprising.

Safety: No unsafe code. All thread safety via Arc<Mutex<>> and Arc<AtomicBool>.

Concerns:

  1. The PriorityScheduler is completely disconnected from the ROS3Executor. The scheduler is created and stored but never used for routing decisions.
  2. The 1ms deadline threshold is hardcoded with no configuration mechanism.
  3. Creating two full Tokio runtimes (6 threads total) is heavyweight. On a system with few cores, this could cause contention.
  4. The spawn_rt() return type is () -- callers cannot await completion or get results from spawned tasks. Only spawn_blocking() returns a JoinHandle.
  5. ScheduledTask.task_id is a u64 counter that will overflow after 2^64 tasks. Not practically concerning but worth noting the design assumes a monotonic non-wrapping counter.

Integration Points with ruvector

  1. Attention Mechanism Scheduling: ruvector's attention computations (flash attention, multi-head attention) have different latency profiles. The dual-runtime pattern could route real-time inference (< 1ms deadline) to the high-priority pool while batch retraining goes to the low-priority pool.

  2. GNN Inference RT: Graph neural network forward passes for time-sensitive applications (e.g., real-time recommendation) could use spawn_high() to guarantee dedicated thread resources.

  3. LatencyTracker for Vector Search: The HDR histogram tracker would be valuable for monitoring HNSW search latency distributions in production. The RAII measure() guard pattern integrates cleanly with ruvector's search functions.

  4. Priority-Based Query Routing: The scheduler design (once connected) could route vector queries by importance -- critical real-time queries to dedicated threads, background batch queries to the shared pool.


Crate 3: agentic-robotics-mcp

Path: /home/user/ruvector/crates/agentic-robotics-mcp/ Line Count: 506 lines Complexity Estimate: Medium Code Quality Rating: B+

File Inventory

File Lines Purpose
src/lib.rs 349 MCP types, McpServer, request handling, tests
src/server.rs 56 ServerBuilder, helper functions
src/transport.rs 101 StdioTransport + conditional SSE transport

Purpose

Implements a Model Context Protocol (MCP) 2025-11 compliant server. MCP enables AI assistants (like Claude) to interact with external tools via a standardized JSON-RPC 2.0 protocol. This crate exposes robot capabilities as MCP tools, with both stdio and SSE (Server-Sent Events) transport options.

Architecture

Request Handling Pipeline

Transport (stdio or SSE)
    |
    v
JSON-RPC 2.0 Parse --> McpRequest
    |
    v
McpServer.handle_request()
    |
    +-- "initialize"   --> protocol version + capabilities
    +-- "tools/list"    --> enumerate registered tools
    +-- "tools/call"    --> dispatch to registered handler
    +-- <unknown>       --> -32601 Method Not Found

The server maintains a HashMap<String, (McpTool, ToolHandler)> behind Arc<RwLock<>> (tokio RwLock). Tool registration is async due to the write lock. Request handling reads the tool map with a read lock for tool listing and invocation.

Transport Layer

Stdio Transport: Reads line-delimited JSON from stdin, writes responses to stdout. The main loop is:

  1. Read line from stdin via AsyncBufReadExt
  2. Parse as McpRequest
  3. Dispatch to McpServer::handle_request()
  4. Serialize response to JSON
  5. Write to stdout with newline delimiter and flush

SSE Transport (feature-gated behind sse): Uses axum with two routes:

  • POST /mcp: Accepts JSON McpRequest, returns JSON McpResponse
  • GET /mcp/stream: Returns SSE stream (currently only sends a "connected" event)

The SSE implementation is minimal -- it does not implement bidirectional communication or event streaming for ongoing operations.

API Surface

Public Types

Type Module Description
McpTool lib name, description, input_schema (JSON Value)
McpRequest lib jsonrpc, id, method, params -- JSON-RPC 2.0 request
McpResponse lib jsonrpc, id, result, error -- JSON-RPC 2.0 response
McpError lib code (i32), message, optional data
ToolResult lib content: Vec, optional is_error flag
ContentItem lib Tagged enum: Text, Resource, Image
ToolHandler lib Arc<dyn Fn(Value) -> Result<ToolResult> + Send + Sync>
McpServer lib Main server with tool registry
ServerInfo lib name, version, description
ServerBuilder server Builder pattern for McpServer
StdioTransport transport Stdio-based transport

Key Methods

impl McpServer {
    pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self
    pub async fn register_tool(&self, tool: McpTool, handler: ToolHandler) -> Result<()>
    pub async fn handle_request(&self, request: McpRequest) -> McpResponse
}

impl ServerBuilder {
    pub fn new(name: impl Into<String>) -> Self
    pub fn version(mut self, version: impl Into<String>) -> Self
    pub fn build(self) -> McpServer
}

impl StdioTransport {
    pub fn new(server: McpServer) -> Self
    pub async fn run(&self) -> Result<()>
}

// Helper functions
pub fn tool<F>(f: F) -> ToolHandler
pub fn text_response(text: impl Into<String>) -> ToolResult
pub fn error_response(error: impl Into<String>) -> ToolResult

Constants

pub const MCP_VERSION: &str = "2025-11-15";

Protocol Compliance

The implementation covers the core MCP 2025-11 operations:

  • initialize: Returns protocol version, capabilities (tools + resources), server info
  • tools/list: Returns all registered tools
  • tools/call: Dispatches to handler by name with arguments

Missing MCP features:

  • resources/list, resources/read -- resources capability declared but not implemented
  • prompts/list, prompts/get -- not implemented
  • notifications/initialized -- server does not handle the post-init notification
  • sampling -- not implemented
  • Tool annotations (readOnlyHint, destructiveHint, openWorldHint)

Error codes used:

  • -32601: Method not found (standard JSON-RPC)
  • -32602: Invalid params (standard JSON-RPC)
  • -32000: Tool execution failure (server error range)

Dependency Analysis

Dependency Purpose Weight
agentic-robotics-core (path) Core types Internal -- not imported in source
tokio (workspace) Async runtime + IO Standard
serde + serde_json JSON-RPC serialization Standard
anyhow (workspace) Error handling Light
thiserror (workspace) Error derives Light -- unused in source
tracing (workspace) Logging Light -- unused in source
axum (optional, sse feature) HTTP server Medium
tokio-stream (optional, sse feature) Stream utilities Light

Notable: agentic-robotics-core, thiserror, and tracing are declared but not imported or used. The crate is functionally independent of the core crate.

Code Quality Assessment

Test Coverage: 3 async tests in lib.rs:

  • test_mcp_initialize: Verifies initialize response has result, no error
  • test_mcp_list_tools: Registers one tool, verifies list returns it
  • test_mcp_call_tool: Registers echo tool, calls it, verifies success

Tests are well-structured and test the full request/response cycle. No tests for:

  • Error paths (missing tool, invalid params, malformed request)
  • Transport layer (stdio, SSE)
  • Concurrent tool registration and invocation

Error Handling: Uses JSON-RPC error codes correctly. The handle_call_tool method has proper null checks for params and tool name. The ToolHandler returns anyhow::Result which is caught and converted to MCP error responses.

Documentation: Good module-level docs. The lib.rs doc comment accurately describes the MCP version and transport options.

Safety: No unsafe code. Uses tokio::sync::RwLock (not parking_lot) for the tool registry, which is correct since the lock is held across .await points in handle_request.

Concerns:

  1. ContentItem::Resource uses mimeType (camelCase) as a Rust field name instead of idiomatic mime_type with #[serde(rename = "mimeType")]. This works but violates Rust naming conventions.
  2. The tool handler Arc<dyn Fn(Value) -> Result<ToolResult>> is synchronous. Long-running tool operations will block the server's async runtime. Should be Arc<dyn Fn(Value) -> BoxFuture<Result<ToolResult>>> for proper async support.
  3. serde_json::to_value(result).unwrap() in handle_call_tool can panic if ToolResult serialization fails. Should use ? or map to an error response.
  4. The stdio transport error handling on parse failure uses eprintln! instead of returning a JSON-RPC error response to the caller.

Integration Points with ruvector

  1. Vector Search as MCP Tool: ruvector's HNSW search could be exposed as an MCP tool:

    {
      "name": "vector_search",
      "description": "Search for nearest neighbors in vector space",
      "input_schema": {
        "type": "object",
        "properties": {
          "query": { "type": "array", "items": { "type": "number" } },
          "k": { "type": "integer" },
          "ef_search": { "type": "integer" }
        }
      }
    }
    
  2. GNN Inference as MCP Tool: Expose graph neural network forward passes for agentic reasoning about graph-structured data.

  3. Attention Computation as MCP Tool: Multi-head attention or flash attention could be exposed for external AI systems to use ruvector's optimized attention kernels.

  4. Embedding Generation: Wrap ruvector's encoding capabilities as MCP tools for real-time embedding generation from sensor data.


Crate 4: agentic-robotics-embedded

Path: /home/user/ruvector/crates/agentic-robotics-embedded/ Line Count: 41 lines Complexity Estimate: Minimal Code Quality Rating: C

File Inventory

File Lines Purpose
src/lib.rs 41 Priority enum + config struct

Purpose

Intended to provide embedded systems support using Embassy and RTIC frameworks. Currently contains only configuration types and an enum -- no actual embedded runtime integration.

API Surface

Public Types

Type Description
EmbeddedPriority 4-level enum: Low=0, Normal=1, High=2, Critical=3
EmbeddedConfig tick_rate_hz: u32 (default 1000), stack_size: usize (default 4096)

Current State

This crate is a skeleton. The Cargo.toml declares:

  • agentic-robotics-core as a dependency (unused)
  • serde, anyhow, thiserror as dependencies (unused)
  • embassy and rtic as feature flags that enable nothing (the actual embassy-executor and rtic dependencies are commented out)

The EmbeddedPriority enum overlaps with RTPriority from the rt crate but with only 4 levels instead of 5 (missing Background). There is no conversion between them.

Dependency Analysis

Dependency Purpose Weight
agentic-robotics-core (path) Core types Unused
serde (workspace) Serialization Unused
anyhow (workspace) Error handling Unused
thiserror (workspace) Error derives Unused

All 4 dependencies are declared but none are imported or used in source code.

Code Quality Assessment

Test Coverage: 1 test verifying EmbeddedConfig::default() values.

Concerns:

  1. This crate provides no functionality beyond two simple types.
  2. The Embassy and RTIC dependencies are commented out, meaning the embassy and rtic feature flags are no-ops.
  3. The EmbeddedPriority enum is redundant with RTPriority from the rt crate.
  4. EmbeddedConfig fields are too generic -- tick_rate_hz and stack_size are meaningful only in the context of a real embedded runtime.

Integration Points with ruvector

  1. Edge Deployment: A completed embedded crate could enable deployment of ruvector-lite quantized models on embedded ARM/RISC-V devices. The config types would need to include memory constraints for vector storage, quantization levels, and inference batch sizes.

  2. Limited Utility Currently: In its current state, this crate provides no integration value. It would need significant development to support actual embedded runtimes.


Crate 5: agentic-robotics-node

Path: /home/user/ruvector/crates/agentic-robotics-node/ Line Count: 236 lines (233 source + 3 build.rs) Complexity Estimate: Medium Code Quality Rating: B+

File Inventory

File Lines Purpose
src/lib.rs 233 NAPI bindings: AgenticNode, AgenticPublisher, AgenticSubscriber
build.rs 3 napi-build setup

Purpose

Provides Node.js/TypeScript bindings for the agentic-robotics-core pub/sub system via NAPI-RS. This enables JavaScript applications to create publishers and subscribers, publish JSON messages, and interact with the robotics middleware from Node.js.

Architecture

The crate uses the napi-derive macro system to generate N-API bindings. Three main types are exposed to JavaScript:

AgenticNode (factory)
    |
    +-- create_publisher(topic) --> AgenticPublisher
    |       |
    |       +-- publish(json_string)
    |       +-- get_topic()
    |       +-- get_stats() --> PublisherStats { messages, bytes }
    |
    +-- create_subscriber(topic) --> AgenticSubscriber
    |       |
    |       +-- try_recv() --> Option<String>
    |       +-- recv() --> String  (blocking via spawn_blocking)
    |       +-- get_topic()
    |
    +-- list_publishers() --> Vec<String>
    +-- list_subscribers() --> Vec<String>
    +-- get_name() --> String
    +-- get_version() --> String (static)

The NAPI boundary serializes all messages as JSON strings. The AgenticNode uses Publisher<serde_json::Value> with Format::Json explicitly (not CDR) because serde_json::Value cannot be CDR-serialized (CDR requires a fixed schema). This is a correct design decision for the JavaScript interop layer.

Internal state is managed with Arc<RwLock<HashMap<String, Arc<T>>>> for both publishers and subscribers, using tokio::sync::RwLock for async-safe access.

API Surface (NAPI-exported)

Class Method Async Returns
AgenticNode new(name) No (constructor) AgenticNode
AgenticNode get_name() No String
AgenticNode create_publisher(topic) Yes AgenticPublisher
AgenticNode create_subscriber(topic) Yes AgenticSubscriber
AgenticNode get_version() No (static) String
AgenticNode list_publishers() Yes Vec<String>
AgenticNode list_subscribers() Yes Vec<String>
AgenticPublisher publish(data) Yes void
AgenticPublisher get_topic() No String
AgenticPublisher get_stats() No PublisherStats
AgenticSubscriber get_topic() No String
AgenticSubscriber try_recv() Yes Option<String>
AgenticSubscriber recv() Yes String
PublisherStats (object) -- { messages: i64, bytes: i64 }

Dependency Analysis

Dependency Purpose Weight
agentic-robotics-core (path) Core pub/sub types Internal -- actually used
napi (workspace) N-API runtime Medium
napi-derive (workspace) Proc macros for #[napi] Medium (compile-time)
tokio (workspace) Async runtime Standard
serde + serde_json JSON at NAPI boundary Standard
anyhow (workspace) Error handling Light
napi-build (build-dep) Build script support Light (build-time)

This is the only non-benchmark crate that actually uses agentic-robotics-core types (Publisher, Subscriber) in its source code.

Code Quality Assessment

Test Coverage: 5 async tests:

  • Node creation and name verification
  • Publisher creation with topic verification
  • Publish JSON and stats verification (messages count = 1)
  • Subscriber creation with topic verification
  • List publishers after creating 2 publishers

Tests are clean and verify the full NAPI-exposed API surface. The publish test verifies end-to-end JSON serialization through the publisher.

Error Handling: NAPI errors are constructed via Error::from_reason() with descriptive messages. Both JSON parse errors and publish/receive errors are mapped to NAPI Error types. This is the correct pattern for NAPI bindings.

Documentation: Module-level doc comment. Function-level comments on all #[napi] methods.

Safety: #![deny(clippy::all)] is enabled -- the only crate with an explicit clippy directive. No unsafe code (NAPI-RS generates the necessary unsafe FFI internally).

Concerns:

  1. PublisherStats uses i64 instead of u64 because NAPI does not support unsigned 64-bit integers in JavaScript (BigInt would be needed). This means stats will overflow at 2^63 instead of 2^64. Acceptable for practical use.
  2. The try_recv() method is marked async but the underlying Subscriber::try_recv() is synchronous. The async wrapper adds unnecessary overhead for a non-blocking operation.
  3. The recv() method delegates to Subscriber::recv_async() which uses spawn_blocking internally. This works but creates a double-async layering that could be simplified.

Integration Points with ruvector

  1. Matches Existing NAPI Pattern: ruvector already has ruvector-node, ruvector-gnn-node, etc. The agentic-robotics-node crate follows the same NAPI-RS pattern with #[napi] macros, cdylib crate type, and napi-build build script. Integration would follow established conventions.

  2. Unified Node.js API: A combined NAPI module could expose both vector operations (search, insert, GNN inference) and robotics pub/sub in a single npm package, enabling Node.js applications to do real-time sensor data processing with ML inference.

  3. JSON Bridge: The JSON serialization at the NAPI boundary is compatible with ruvector's existing JSON-based APIs. Vector data could be passed as JSON arrays, matching the pattern already used here.


Crate 6: agentic-robotics-benchmarks

Path: /home/user/ruvector/crates/agentic-robotics-benchmarks/ Line Count: 635 lines (all bench code) Complexity Estimate: Low (benchmark harness code) Code Quality Rating: B-

File Inventory

File Lines Purpose
benches/message_serialization.rs 187 CDR/JSON ser/deser benchmarks, size comparison, scaling
benches/pubsub_latency.rs 193 Publisher/subscriber creation, latency, throughput
benches/executor_performance.rs 255 Executor creation, task spawning, scheduling overhead

Purpose

Comprehensive Criterion benchmark suite covering the core and rt crates. Provides performance characterization for serialization, pub/sub operations, and executor task management.

Benchmark Coverage

message_serialization.rs

Benchmark Group Benchmarks Description
CDR Serialization RobotState, Pose, PointCloud_1k CDR encode with throughput tracking
CDR Deserialization RobotState, Pose CDR decode from pre-serialized bytes
JSON vs CDR CDR_serialize, JSON_serialize, CDR_deserialize, JSON_deserialize Head-to-head format comparison with size reporting
Message Size Scaling PointCloud at 100, 1K, 10K, 100K points Serialization scaling characteristics

Note: This benchmark file references a Pose struct with frame_id: String and a PointCloud with points: Vec<[f32; 3]> and frame_id: String. These differ from the actual types in agentic-robotics-core/src/message.rs where Pose has no frame_id field and PointCloud uses Vec<Point3D> not Vec<[f32; 3]>. This benchmark will not compile against the current core crate without modifications.

pubsub_latency.rs

Benchmark Group Benchmarks Description
Publisher Creation create_publisher Publisher construction overhead
Subscriber Creation create_subscriber Subscriber construction overhead
Publish Latency single_publish Single message publish time
Publish Throughput batch_publish (10, 100, 1000) Burst publishing at different batch sizes
End-to-End Latency pubsub_roundtrip Full publish cycle (no actual receive)
Serializer Comparison CDR_publish, JSON_publish Publish with different formats
Concurrent Publishers concurrent (1, 2, 4, 8) Multiple publisher scaling

Note: This benchmark references Publisher::new(topic, Serializer::Cdr) with a two-argument constructor and Serializer::Cdr enum variant. The actual core crate uses Publisher::new(topic) (single argument, defaults to CDR) and Serializer::new(Format::Cdr) (struct, not enum). These API mismatches mean this benchmark will not compile against the current core crate.

executor_performance.rs

Benchmark Group Benchmarks Description
Executor Creation create_executor Runtime initialization cost
Task Spawning spawn_high_priority, spawn_low_priority Per-task spawn overhead
Scheduler Overhead priority_low/high, deadline_check_fast/slow Scheduling decision cost
Task Distribution spawn_tasks (10, 100, 1000) Bulk task spawning with mixed priorities
Async Task Execution execute_sync_task, execute_with_yield Task execution overhead
Priority Handling mixed_priorities Interleaved priority levels
Deadline Distribution tight_deadlines, loose_deadlines High vs low priority runtime routing

Note: This benchmark references Priority::High, Priority::Medium, Priority::Low as enum variants and PriorityScheduler::should_use_high_priority(). The actual rt crate uses Priority(pub u8) as a newtype (not an enum) and PriorityScheduler has no should_use_high_priority() method. These API mismatches mean this benchmark will not compile against the current rt crate.

Dependency Analysis

Dependency Purpose Weight
agentic-robotics-core (path) Core types for benchmarking Internal
agentic-robotics-rt (path) RT types for benchmarking Internal
criterion 0.5 Benchmark framework Medium
tokio 1.40 Async runtime Standard
serde 1.0 Serialization Standard
serde_json 1.0 JSON Standard

Notable: Dependencies are specified with explicit versions (not workspace), unlike the other crates. This means they could drift from workspace versions. The crate has publish = false.

Code Quality Assessment

Compilation Status: The benchmarks will NOT compile against the current source crates due to multiple API mismatches:

  1. Pose struct fields differ (benchmarks expect frame_id, source has none)
  2. PointCloud field types differ (Vec<[f32; 3]> vs Vec<Point3D>)
  3. Publisher constructor signature differs (2-arg vs 1-arg)
  4. Serializer is used as an enum variant, not a struct
  5. Priority is used as an enum, not a newtype
  6. PriorityScheduler::should_use_high_priority() does not exist

This suggests the benchmarks were written against a different (possibly planned or previous) version of the API.

Benchmark Design: Despite the compilation issues, the benchmark structure is well-designed:

  • Uses Throughput::Bytes for size-aware benchmarking
  • Scaling benchmarks test across multiple orders of magnitude (100 to 100K points)
  • Concurrent publisher benchmarks test scaling characteristics
  • iter_custom is used correctly for measuring async operation latency
  • black_box is applied consistently to prevent dead code elimination

Concerns:

  1. The benchmark_task_distribution test creates a new ROS3Executor (with 6 threads) per iteration -- this is extremely expensive and will dominate the benchmark.
  2. futures::executor::block_on is used in pubsub benchmarks instead of Criterion's b.to_async() pattern. This adds overhead from blocking the thread.
  3. No warm-up or steady-state verification for executor benchmarks.

Integration Points with ruvector

  1. Combined Benchmark Suite: The benchmark patterns could be extended to test combined robotics + ML workloads: e.g., serialize PointCloud -> HNSW insert -> search -> publish results.

  2. Latency Profiling: The serialization benchmarks provide a template for benchmarking ruvector's own serialization paths (vector encoding, index persistence).

  3. Scaling Characterization: The message size scaling pattern (100 to 100K points) directly applies to benchmarking vector search with different collection sizes.


Cross-Crate Dependency Graph

agentic-robotics-benchmarks (publish=false)
    |
    +---> agentic-robotics-core
    +---> agentic-robotics-rt
                |
                +---> agentic-robotics-core

agentic-robotics-node
    |
    +---> agentic-robotics-core  (ACTUALLY USED)

agentic-robotics-mcp
    |
    +---> agentic-robotics-core  (declared but unused)

agentic-robotics-embedded
    |
    +---> agentic-robotics-core  (declared but unused)

agentic-robotics-rt
    |
    +---> agentic-robotics-core  (declared but unused)

Key observation: Only agentic-robotics-node actually imports and uses types from agentic-robotics-core. The other 3 crates (rt, mcp, embedded) declare it as a dependency but do not use it. The benchmarks crate references core types by the old crate name (ros3_core, ros3_rt), which suggests the crates were renamed from ros3-* to agentic-robotics-* but the benchmarks were not updated.


Overall Assessment

Summary Table

Crate Lines Tests Quality Compilable Maturity
core 705 8 B Yes Alpha -- middleware stubbed
rt 512 5 B- Yes Alpha -- scheduler disconnected
mcp 506 3 B+ Yes Beta -- core protocol working
embedded 41 1 C Yes Skeleton -- no functionality
node 236 5 B+ Yes (with napi) Alpha -- working NAPI bindings
benchmarks 635 0 B- No -- API mismatches Broken -- needs API updates

Total Metrics

  • Total source lines: 2,635 (including benchmarks)
  • Total tests: 22
  • Unsafe code: None across all crates
  • Broken crates: 1 (benchmarks -- API mismatches with current source)
  • Unused dependencies: 12 instances across all crates

Strengths

  1. Clean type design: The Message trait, Publisher<T>, Subscriber<T> generics are well-structured with proper Send/Sync/static bounds.
  2. Serialization flexibility: CDR + JSON + rkyv (future) covers binary efficiency, debugging, and zero-copy use cases.
  3. LatencyTracker: The HDR histogram-based latency tracker is production-quality with RAII guards and non-blocking recording.
  4. MCP implementation: The MCP server is the most complete component, with proper JSON-RPC 2.0 handling and a clean tool registration API.
  5. NAPI bindings: Follow established patterns and work correctly with JSON serialization at the boundary.

Weaknesses

  1. Placeholder code: Zenoh middleware, rkyv serialization, Service client, and embedded support are all stubs.
  2. Disconnected components: The PriorityScheduler is never used by the executor. The core crate is declared as a dependency by 4 crates but actually used by only 1.
  3. API drift: The benchmarks reference a different API surface than what exists in the source, indicating either the API changed after benchmarks were written or the benchmarks target a planned future API.
  4. Shallow testing: Tests cover happy paths only. No error path testing, no concurrent access testing, no integration tests across crates.
  5. Dependency bloat: zenoh and rustdds in core are heavyweight dependencies that are never used. Multiple crates declare crossbeam, rayon, thiserror, tracing without importing them.

Safety Assessment

Concern Status
Unsafe code None -- all crates are safe Rust
Thread safety Proper use of Arc, Mutex, RwLock throughout
Error handling thiserror/anyhow pattern, but some .unwrap() in MCP server
Panic risk Default::default() on ROS3Executor uses .expect()
Memory safety No raw pointers, no manual memory management
Input validation Minimal -- MCP server validates JSON structure but not content

Integration Roadmap for ruvector

Phase 1: Direct Utility (No modification needed)

  1. LatencyTracker adoption: Import agentic-robotics-rt::LatencyTracker into ruvector's profiling infrastructure for HDR histogram-based latency monitoring of HNSW search, GNN inference, and attention computation.

  2. MCP tool exposure: Use agentic-robotics-mcp::McpServer to expose ruvector capabilities as MCP tools:

    • vector_search -- HNSW nearest-neighbor queries
    • vector_insert -- Add vectors to collections
    • gnn_inference -- Graph neural network forward pass
    • attention_compute -- Multi-head/flash attention
    • collection_stats -- Index statistics and health

Phase 2: Adapter Layer (Thin wrappers)

  1. PointCloud <-> Vector adapter: Create a bidirectional conversion between PointCloud (robotics 3D sensor data) and ruvector's vector types. This enables real-time HNSW indexing of LiDAR/depth sensor data:

    impl From<&PointCloud> for Vec<[f32; 3]> { ... }
    impl From<Vec<[f32; 3]>> for PointCloud { ... }
    
  2. Message trait for vector types: Implement Message on ruvector's core vector/embedding types to enable pub/sub distribution.

  3. NAPI unification: Combine agentic-robotics-node with ruvector-node into a single npm package or create an interop layer.

Phase 3: Deep Integration (Architectural changes)

  1. Dual-runtime for ML workloads: Adapt the ROS3Executor pattern for ruvector:

    • High-priority runtime: Real-time inference queries (< 1ms SLA)
    • Low-priority runtime: Batch indexing, model training, compaction
    • Connect the PriorityScheduler to actually route tasks by deadline
  2. Zenoh-based distributed vectors: When the Zenoh middleware is completed, use it for distributed vector index replication (similar to ruvector-replication but over Zenoh instead of custom protocols).

  3. CDR serialization for vector wire format: Use CDR as the wire format for vector data in DDS-compatible robotics environments, enabling direct integration with ROS2 systems.

  1. LatencyTracker (immediate value, no risk)
  2. MCP tool exposure (high value for agentic workflows)
  3. PointCloud adapter (enables robotics use cases)
  4. NAPI unification (reduces maintenance burden)
  5. Dual-runtime (significant architectural benefit, higher risk)
  6. Zenoh distributed vectors (depends on Zenoh middleware completion)

Prerequisites Before Integration

  • Fix benchmark compilation errors (update to current API)
  • Remove unused dependencies from all crates (zenoh, rustdds, rayon, crossbeam where unused)
  • Connect PriorityScheduler to ROS3Executor
  • Complete rkyv serialization implementation or remove the stub
  • Add error path tests across all crates
  • Resolve the ros3_core/ros3_rt crate name references in benchmarks