Merge hero_rpc_openrpc into hero_rpc2 — single error type + transport surface #146

Open
opened 2026-05-28 15:45:43 +00:00 by timur · 0 comments
Owner

Background

We currently ship two crates that serve overlapping roles in the JSON-RPC stack:

  • hero_rpc_openrpc — older runtime; defines OpenRpcError, OpenRpcTransport, the HTTP-over-UDS transport, and various spec helpers.
  • hero_rpc2 — newer runtime introduced in hero_rpc#142 (3f53db8); defines Client, ClientT, ClientError, ToRpcParams, the canonical UDS-HTTP client + server transport, plus the with_discover/with_service_info macros.

The post-#142 openrpc_client! macro emits code that routes through hero_rpc2 (returns Result<T, hero_rpc2::ClientError>). But many downstream consumers were written against the older hero_rpc_openrpc::OpenRpcError shape and now break on every ? site that composes a generated SDK call with a caller-side return type.

Concrete breakage already triaged in this thread

  1. hero_indexer_sdk — needed hero_rpc2 + herolib_core deps added; pushed as 463f4e9.
  2. hero_proc_sdk — needed the same dep addition + pub use hero_rpc_openrpc::OpenRpcError as HeroProcRpcApiError swapped to pub use hero_rpc2::ClientError as HeroProcRpcApiError. Pushed as a quick alias patch; see openrpc_client/mod.rs for the TODO referencing this issue.
  3. hero_admin_lib — uses the old transport path; admin/server binaries hang at startup against the latest hero_rpc — separate issue.

Each time we add a new SDK consumer (every Hero service gets one), the same dance repeats. The duplicate types are the symptom; the disease is that we have two crates trying to be the JSON-RPC runtime.

Proposal

Fold hero_rpc_openrpc into hero_rpc2 — make hero_rpc2 the single source of truth for:

  • ClientError (drop OpenRpcError)
  • ClientT / Client / ClientBuilder
  • UDS-HTTP transport (connect_http, serve_http)
  • ToRpcParams adapter
  • with_discover / with_service_info builder methods
  • OpenRPC spec types currently in hero_rpc_openrpc::spec (move under hero_rpc2::spec)
  • The [features = "transport"] flag becomes the default surface in hero_rpc2.

After the fold:

  • hero_rpc_openrpc crate is deleted from the workspace.
  • Every consumer's Cargo.toml drops hero_rpc_openrpc and adds (if not already) hero_rpc2.
  • Every use hero_rpc_openrpc::* becomes use hero_rpc2::*.
  • Every OpenRpcError becomes ClientError.
  • The pub use … as HeroProcRpcApiError aliases in downstream SDKs collapse to pub use hero_rpc2::ClientError as HeroProcRpcApiError (or just drop the alias entirely and have the SDK return the canonical type).

Affected repos (initial scan)

  • lhumina_code/hero_rpc — delete crate, update internal Cargo.tomls + re-exports
  • lhumina_code/hero_proc — update hero_proc_sdk + hero_proc_server
  • lhumina_code/hero_indexer — update hero_indexer_sdk + server
  • lhumina_code/hero_website_framework — update hero_admin_lib (depends on the old transport)
  • lhumina_code/hero_skillslab re-exports hero_rpc_openrpc in a few places; update
  • Every service crate that has a _sdk (hero_books, hero_aibroker, hero_logic, hero_db, hero_code, hero_auth, hero_voice, hero_router, …)

Migration sequence

  1. In hero_rpc: move all hero_rpc_openrpc::* items into hero_rpc2::*. Add #[deprecated] re-exports in hero_rpc_openrpc pointing at the new paths so downstreams compile against either version during the transition.
  2. Per consumer SDK: update Cargo.toml to drop hero_rpc_openrpc, fix imports, push to dev branch.
  3. In hero_rpc: delete the hero_rpc_openrpc crate + workspace member entry once every consumer is migrated.

Out of scope

  • The runtime wire format does not change.
  • Generated _sdk crates (via openrpc_client! macro) need no manual edits — the macro already emits hero_rpc2-shaped code.
  • This is a rename + delete refactor, not an API redesign.

Why the alias quick-fix isn't the long-term answer

Every new downstream consumer of openrpc_client! needs to declare both hero_rpc2 AND hero_rpc_openrpc in deps (the macro expansion uses one, the hand-written builders use the other). Folding the crates makes the dep set match the import set, eliminates the alias dance, and removes ~2000 lines of duplicated transport code from the tree.

Acceptance criteria

  • hero_rpc_openrpc crate no longer exists on origin/development.
  • Every Hero service repo builds clean against origin/development of hero_rpc with no hero_rpc_openrpc in its Cargo.toml.
  • The deprecated re-exports in hero_rpc_openrpc are gone (they were transitional).
## Background We currently ship two crates that serve overlapping roles in the JSON-RPC stack: - **`hero_rpc_openrpc`** — older runtime; defines `OpenRpcError`, `OpenRpcTransport`, the HTTP-over-UDS transport, and various spec helpers. - **`hero_rpc2`** — newer runtime introduced in hero_rpc#142 (`3f53db8`); defines `Client`, `ClientT`, `ClientError`, `ToRpcParams`, the canonical UDS-HTTP client + server transport, plus the `with_discover`/`with_service_info` macros. The post-#142 `openrpc_client!` macro **emits code that routes through `hero_rpc2`** (returns `Result<T, hero_rpc2::ClientError>`). But many downstream consumers were written against the older `hero_rpc_openrpc::OpenRpcError` shape and now break on every `?` site that composes a generated SDK call with a caller-side return type. ## Concrete breakage already triaged in this thread 1. **`hero_indexer_sdk`** — needed `hero_rpc2` + `herolib_core` deps added; pushed as `463f4e9`. 2. **`hero_proc_sdk`** — needed the same dep addition + `pub use hero_rpc_openrpc::OpenRpcError as HeroProcRpcApiError` swapped to `pub use hero_rpc2::ClientError as HeroProcRpcApiError`. Pushed as a quick alias patch; see openrpc_client/mod.rs for the TODO referencing this issue. 3. **`hero_admin_lib`** — uses the old transport path; admin/server binaries hang at startup against the latest hero_rpc — separate issue. Each time we add a new SDK consumer (every Hero service gets one), the same dance repeats. The duplicate types are the symptom; the disease is that we have two crates trying to be the JSON-RPC runtime. ## Proposal **Fold `hero_rpc_openrpc` into `hero_rpc2`** — make `hero_rpc2` the single source of truth for: - `ClientError` (drop `OpenRpcError`) - `ClientT` / `Client` / `ClientBuilder` - UDS-HTTP transport (`connect_http`, `serve_http`) - `ToRpcParams` adapter - `with_discover` / `with_service_info` builder methods - OpenRPC spec types currently in `hero_rpc_openrpc::spec` (move under `hero_rpc2::spec`) - The `[features = "transport"]` flag becomes the default surface in hero_rpc2. After the fold: - `hero_rpc_openrpc` crate is **deleted** from the workspace. - Every consumer's `Cargo.toml` drops `hero_rpc_openrpc` and adds (if not already) `hero_rpc2`. - Every `use hero_rpc_openrpc::*` becomes `use hero_rpc2::*`. - Every `OpenRpcError` becomes `ClientError`. - The `pub use … as HeroProcRpcApiError` aliases in downstream SDKs collapse to `pub use hero_rpc2::ClientError as HeroProcRpcApiError` (or just drop the alias entirely and have the SDK return the canonical type). ## Affected repos (initial scan) - `lhumina_code/hero_rpc` — delete crate, update internal `Cargo.toml`s + re-exports - `lhumina_code/hero_proc` — update hero_proc_sdk + hero_proc_server - `lhumina_code/hero_indexer` — update hero_indexer_sdk + server - `lhumina_code/hero_website_framework` — update hero_admin_lib (depends on the old transport) - `lhumina_code/hero_skills` — `lab` re-exports hero_rpc_openrpc in a few places; update - Every service crate that has a `_sdk` (hero_books, hero_aibroker, hero_logic, hero_db, hero_code, hero_auth, hero_voice, hero_router, …) ## Migration sequence 1. **In hero_rpc:** move all `hero_rpc_openrpc::*` items into `hero_rpc2::*`. Add `#[deprecated]` re-exports in hero_rpc_openrpc pointing at the new paths so downstreams compile against either version during the transition. 2. **Per consumer SDK:** update `Cargo.toml` to drop hero_rpc_openrpc, fix imports, push to dev branch. 3. **In hero_rpc:** delete the hero_rpc_openrpc crate + workspace member entry once every consumer is migrated. ## Out of scope - The runtime wire format does not change. - Generated `_sdk` crates (via `openrpc_client!` macro) need no manual edits — the macro already emits `hero_rpc2`-shaped code. - This is a **rename + delete** refactor, not an API redesign. ## Why the alias quick-fix isn't the long-term answer Every new downstream consumer of `openrpc_client!` needs to declare both `hero_rpc2` AND `hero_rpc_openrpc` in deps (the macro expansion uses one, the hand-written builders use the other). Folding the crates makes the dep set match the import set, eliminates the alias dance, and removes ~2000 lines of duplicated transport code from the tree. ## Acceptance criteria - `hero_rpc_openrpc` crate no longer exists on `origin/development`. - Every Hero service repo builds clean against `origin/development` of hero_rpc with no `hero_rpc_openrpc` in its `Cargo.toml`. - The deprecated re-exports in hero_rpc_openrpc are gone (they were transitional).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_blueprint#146
No description provided.