WIP: OSIS serving → openrpc_server! + serve_rpc_domains (#154/#155) #156

Closed
timur wants to merge 6 commits from feature/osis-multidomain-serve into development
Owner

OSIS serving → hero_lib openrpc_server! + serve_rpc_domains (#154 / #155)

Migrates OSIS multi-domain serving off the bespoke HeroOsisServer/rpc2_adapter stack onto Kristof's openrpc_server! macro + serve_rpc_domains. Generator-side migration complete; verified at the generator level (lib + 151 unit tests green) and scaffold output validated via a locally-rebuilt lab.

What lands

  • chunk 1 0164e33OsisObject/DBTyped String-sid storage foundation (39 db tests).
  • 2a 8ba3eff — generated wire types + OsisObject impl → Option<String> shape.
  • 2b-core 760ed90 — generator emits #[async_trait] impl <Stem>Api for Osis<Domain> + impl OsisObject; deletes handle_rpc/_rpc_*/OsisAppRpcHandler/_new (−1,389 lines, resolves #155).
  • 2b-scaffold 1fad2b7 — server main.rs/Cargo → openrpc_server! + serve_domains.
  • 2b-layout a6f50d7osis_<domain>/ module layout + inherent service methods on Osis<Domain>.

⚠️ NOT ready to merge yet — draft for review

The OSIS migration is mid-flight; hold the merge until:

  • _find query-lowering is wired (currently returns empty).
  • End-to-end CRM build is unblocked — currently gated upstream of OSIS: hero_indexer_sdk's db.create(name,schema) violates herolib_derive's one-input rule (needs hero_indexer's own migration); hero_theme 301s on fetch.
  • SDK/admin/web emitters aligned to the new wire; chunk 3 (delete crates/osis legacy serving) + chunk 5 (regenerate hero_osis, 15 domains).

Full record + exact remaining steps on #154.

🤖 Generated with Claude Code

## OSIS serving → hero_lib `openrpc_server!` + `serve_rpc_domains` (#154 / #155) Migrates OSIS multi-domain serving off the bespoke `HeroOsisServer`/`rpc2_adapter` stack onto Kristof's `openrpc_server!` macro + `serve_rpc_domains`. **Generator-side migration complete; verified at the generator level (lib + 151 unit tests green) and scaffold output validated via a locally-rebuilt `lab`.** ### What lands - **chunk 1** `0164e33` — `OsisObject`/`DBTyped` String-sid storage foundation (39 db tests). - **2a** `8ba3eff` — generated wire types + `OsisObject` impl → `Option<String>` shape. - **2b-core** `760ed90` — generator emits `#[async_trait] impl <Stem>Api for Osis<Domain>` + `impl OsisObject`; deletes `handle_rpc`/`_rpc_*`/`OsisAppRpcHandler`/`_new` (−1,389 lines, resolves #155). - **2b-scaffold** `1fad2b7` — server `main.rs`/Cargo → `openrpc_server!` + `serve_domains`. - **2b-layout** `a6f50d7` — `osis_<domain>/` module layout + inherent service methods on `Osis<Domain>`. ### ⚠️ NOT ready to merge yet — draft for review The OSIS migration is mid-flight; **hold the merge** until: - `_find` query-lowering is wired (currently returns empty). - End-to-end CRM build is unblocked — currently gated **upstream of OSIS**: `hero_indexer_sdk`'s `db.create(name,schema)` violates herolib_derive's one-input rule (needs hero_indexer's own migration); `hero_theme` 301s on fetch. - SDK/admin/web emitters aligned to the new wire; chunk 3 (delete `crates/osis` legacy serving) + chunk 5 (regenerate hero_osis, 15 domains). Full record + exact remaining steps on #154. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Multi-domain OSIS services whose domains define same-named rootobjects
(e.g. `Contact` in both identity and business) collide when all domains
are merged into one jsonrpsee module on a single rpc.sock: `contact.new
was already registered`.

`serve_domains()` instead binds one `rpc_<domain>.sock` per domain (under
the service socket dir), registering each domain's CRUD/service methods
into its own module — so same-named rootobjects never collide. Mirrors the
per-domain-socket topology of `hero_lifecycle::serve_rpc_domains`, over the
hero_rpc2 transport the OSIS handlers register onto. Each domain socket
carries the mandatory endpoints + `rpc.discover`.

`serve()` (single merged socket) stays for single-domain / non-overlapping
services like the CRM example.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the storage layer onto String sids so it operates directly on the
openrpc_server!-generated wire types (sid: Option<String>), removing the
SmartId/storage-type impedance ahead of the generator rewrite (decision A).

- OsisObject: sid()->String, set_sid(String); empty string ⇒ unsaved (create).
- DBTyped<T>: object_path/get/delete/exists key on &str; list()->Vec<String>;
  set() mints on empty sid; id_new()->Result<String> (SmartId stays the
  minting algorithm, stored/keyed as its string form).
- rhai.rs DynamicObject + db/tests.rs updated to the String-sid surface.

cargo check -p hero_rpc_osis green on default/rpc/rhai; 39 db tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Foundation for adopting hero_lib openrpc_server!: the generated core wire
types and their OsisObject impl now use the macro's wire shape (decision A,
String sids), matching chunk-1's OsisObject trait.

- rust_struct.rs generate_struct: root-object server-managed fields are now
  `sid/created_at/updated_at: Option<String>` (was SmartId/OTime), with
  skip_serializing_if. Drops the now-unneeded SmartId import + the
  has_root_objects-driven OTime import (OTime only on explicit `time` fields).
- rust_struct.rs generate_osis_impl_block: OsisObject impl emits the String-sid
  surface (sid()->self.sid.clone().unwrap_or_default(); set_sid(Some(..))).
- schemas/openrpc.rs: fix 5 pre-existing stale test calls (to_openrpc() returns
  Value, not Result) so the generator suite runs.

Generator lib compiles; 151 generator unit tests pass. NOTE: WIP within chunk 2
— the server emission (rust_osis.rs) still emits SmartId/OTime CRUD, so a
regenerated consumer won't compile until the serving rewrite lands next.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rewrite rust_osis.rs to emit the hero_lib openrpc_server! shape instead of the
bespoke serving. Per domain it now emits:

- `impl OsisObject for <Type>` on the macro-generated wire types (String-sid
  surface; indexed_fields_json via serde_json::to_value — uniform numeric/bool/
  string/enum/Option handling, no per-kind classifier).
- the `Osis<Domain>` handler struct (per-rootobject DBTyped + per-domain
  indexer + service handlers) with new()/create()/init_handlers().
- `#[async_trait] impl <Stem>Api for Osis<Domain>` — CRUD bodies backed by
  DBTyped + indexer write-through (get→GetOutput field map; set upsert taking
  the full object, mint on empty sid; delete/list/list_full/exists), errors→
  RpcError; service methods bridge to the contributor <Service>Trait handler.

DELETED: handle_rpc, the _rpc_* dispatchers, RpcRequest/RpcResponse,
generate_osis_app_rpc_handler, generate_service_rpc_methods, the bespoke
_new/_set(sid,data) CRUD, OSCHEMA_SOURCE emission. (#155: no _new, _set upsert.)

Trait/identifier derivation matches the macro: domain mod = snake(domain);
stem = pascal(first service name); per-method structs = pascal(fn)+{Input,Output}.

Generator lib compiles; 151 generator unit tests pass. NOTE still WIP within
chunk 2: (a) _find returns empty (TODO: lower FindParams→indexer query);
(b) imports `use crate::<dom>::*` / `use super::rpc::*` are provisional pending
the scaffold layout (macro mod must not clash with a same-named dir module);
(c) scaffold main.rs (openrpc_server! + serve_domains), Cargo deps, per-domain
service.toml, and CRM regen still to land.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
generate_server_main_rs now emits the hero_lib serving entry point:
- `herolib_derive::openrpc_server!(spec="../<name>/schemas", service_toml=
  "service.toml", save_openrpc_dir="generated/openrpc")` at the crate root
  (generates wire types + <Stem>Api trait + per-domain router + serve_domains).
- one `#[path="osis_<domain>/mod.rs"] mod osis_<domain>;` per domain — kept out
  of the macro's crate-root `mod <domain>` namespace to avoid the collision.
- `serve_domains(osis_<d>::Osis<D>::create(&format!("{root}/<d>"), 0)?, …)`
  in sorted-domain (macro parameter) order.

Server Cargo.toml: +herolib_derive, +herolib_oschema_server, +async-trait;
−hero_rpc2, −jsonrpsee, −herolib_sid. Scaffold main.rs tests updated to assert
the new shape. Generator lib + 151 tests green.

NOTE WIP: build/emit must still write the generated OSIS impl + contributor
rpc under src/osis_<domain>/ to match this main.rs; rust_rpc service model +
_find lowering + CRM regen still pending.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Completes the server-side generator migration so the emitted server crate
matches the new main.rs (openrpc_server! + serve_domains):

- rust_osis.rs: serve_domains takes the handler by value, so drop the
  Arc/handler/init_handlers machinery — create() returns Self; service-method
  trait arms delegate to inherent `self.<method>(..)` (no handler back-ref).
- rust_rpc.rs (contributor rpc.rs): emit inherent `async fn <method>(&self,..)
  -> Result<T, RpcError>` stubs on Osis<Domain> (graceful "not yet implemented"
  Err) + the lifecycle triggers; drop the <Service>Trait/<Service>Handler
  indirection. Imports use crate::<domain>::* (macro wire types) + super::osis.
- generate/rust_server.rs: write osis_<domain>/{osis.rs, rpc.rs (scaffold-once),
  mod.rs barrel} instead of <domain>/generated/{server,rpc,mod}.rs — the module
  is named osis_<domain> so it never collides with the macro's crate-root
  mod <domain>. Drops the super::core path-rewrites + generated/rpc.rs emission.
- build/emit/rust_server.rs: server lib.rs no longer declares per-domain
  modules (the binary's main.rs mounts osis_<domain> via #[path]; the macro
  owns mod <domain>).

Generator lib + 151 tests green. Validated via a locally-rebuilt `lab`
(hero_skills, patched to this tree): scaffolding now emits the new main.rs +
osis_crm layout. End-to-end CRM build is currently blocked UPSTREAM of OSIS by
ecosystem skew — hero_indexer_sdk's `db.create(name, schema)` violates
herolib_derive's new one-input rule, and hero_theme 301s on fetch — both
outside this generator's scope (tracked on #154).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
timur closed this pull request 2026-06-04 10:28:00 +00:00
Author
Owner

Closing — superseded. This was the approach-A (String-sid) OSIS serving exploration. We deliberately chose approach B (SmartId / spec-pure wire + *Store), which is now on development (emitter synced to the current openrpc_server! macro + the hero_db storage backend). The approach-A branch is preserved as tag backup/osis-multidomain-serve-approachA if ever needed. development is the single source of truth.

Closing — superseded. This was the **approach-A** (String-sid) OSIS serving exploration. We deliberately chose **approach B** (SmartId / spec-pure wire + `*Store`), which is now on `development` (emitter synced to the current `openrpc_server!` macro + the hero_db storage backend). The approach-A branch is preserved as tag `backup/osis-multidomain-serve-approachA` if ever needed. development is the single source of truth.
Some checks failed
Test / test (pull_request) Failing after 1s

Pull request closed

Sign in to join this conversation.
No reviewers
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!156
No description provided.