Skip to main content

Crate and workspace graph

The Cargo workspace separates domain logic, tag I/O, persistence, and adapters. The frontend and documentation site are pnpm workspace members rather than Rust crates.

ComponentKindRole and dependency boundary
bhtune-coreRust libraryDomain model, MRFT state machine, and tuning calculations. It has no I/O, async runtime, or clock reads.
bhtune-driverRust libraryDefines the Driver tag-I/O interface and provides OPC DA, simulator, and replay implementations. Its production interface is separate from the MRFT domain types.
bhtune-dbRust libraryProvides the SQLite schema, migrations, and typed repository operations. It uses core model types and is the persistence boundary for the adapters.
bhtune-runtimeRust libraryOwns configuration resolution, database bootstrap, logging, retention, driver setup, shared tune orchestration and safety, history operations, OPC helpers, and sample export serialization. Its source and direct dependencies use the core, driver, and database libraries, not either adapter; transport crates pulled by the OPC DA gRPC client are not exposed through its API.
bhtuneRust package (bhtune_cli library, bhtune binary)Adapts command-line arguments and terminal interaction to the shared runtime for headless tuning, simulation, history, and OPC diagnostic commands.
bhtune-serverRust library and bhtune-server binaryProvides the Axum HTTP API, OpenAPI document, SSE run stream, and browser-asset handler. It adapts HTTP requests and responses to the shared runtime; it does not depend on the CLI.
bhtune-test-supportUnpublished Rust test libraryShared mock gRPC bridge for driver, CLI, and server tests; never a product or release artifact.
frontend/pnpm packageReact and TypeScript browser interface. It calls the server API through the generated OpenAPI client; it is not a Rust crate.
website/pnpm packageDocusaurus site built from the repository's docs/ directory. It is separate from the runtime binaries.

The six product crates are distinct from test infrastructure. fuzz/ and tests/opcda-yokogawa-fixture/ are separate Cargo workspaces, not product members. The server is a product even though its package is not published to crates.io.

The main runtime paths are:

Entry pointRuntime path
CLIbhtune binary -> bhtune_cli library (bhtune package) -> bhtune-runtime -> bhtune-core + bhtune-driver + bhtune-db
BrowserReact SPA -> HTTP/SSE -> bhtune-server -> bhtune-runtime -> shared application services
DocumentationDocusaurus site -> repository docs/

An HTTP-started tune runs inside bhtune-server through the shared runtime; the server does not call the CLI library or launch a second bhtune process. The CLI can run independently of the server. The website has no runtime dependency on either adapter.

Dependency boundaries​

The core is dependency-minimal, not dependency-free: parsing its embedded TOML catalog and deriving optional schemas do not perform runtime I/O. Network calls, clock reads, asynchronous orchestration, and persistence belong outside it. See the engine and time model.

Runtime services expose application-owned inputs and outcomes. CLI argument types and prompts stay in bhtune; HTTP requests, framework types, and OpenAPI aggregation stay in the server. Transport crates can occur transitively through the OPC DA client without becoming runtime API types. Neither adapter is the other's application-service dependency.

Only bhtune-driver has the production opcda-bridge dependency. Packaged builds use its published crates.io release, not a git dependency or local source override. Shared dependencies belong in the workspace manifest when a second crate needs them, not as unused reservations.

Driver seam​

Driver deals in tags and raw string values, not MRFT domain types. Connection, operation, and unsupported errors remain distinct. A controller-rejected write is a successful transport response containing WriteOutcome, not a fabricated transport failure; an accepted write is not proof of physical MV actuation.

The OPC DA client uses tokio::sync::Mutex because its guard crosses asynchronous calls. The simulator uses std::sync::Mutex because its state changes do not suspend. These are different synchronization requirements, not interchangeable implementations to unify.

Gateway metadata and registered-server discovery are pre-connection helpers: they need a gateway host but no selected OPC ProgID, so they are not methods on a connected driver. Browse sessions, hierarchy keys, continuation tokens, and exact ItemIDs remain gateway-owned; see OPC browse and search.

The runtime topology shows where these components run. See the Rust API reference for crate-level source documentation.