Generator: unify SDK ↔ server types and seeding (single source of truth) (#117) #118
No reviewers
Labels
No labels
prio_critical
prio_low
type_bug
type_contact
type_issue
type_lead
type_question
type_story
type_task
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
lhumina_code/hero_rpc!118
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "issue-117-unify-types"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Implements hero_rpc#117 — unifies SDK ↔ server types and seeding behind a single source of truth.
generate_rust_structspath as the server'stypes.rs, soRecipe/OTime/OCur/OLocation/OAddressresolve to a single canonical type on both sides. Server-managed timestamps moved fromu64toOTime.<Name>Inputemitted alongside<Name>for every rootobject. The user-supplied surface dropssid/created_at/updated_at; an auto-emittedimpl From<&<Name>> for <Name>Inputlets callers round-trip an existing row into an update.new(input) -> sidandset(sid, input) -> (). Wire trait, OSIS handler API, and the JSON-RPC dispatcher all move to the new shape together. The old conflatedset(data)is gone; so are_new_from_otoml/_new_from_json(replaced by the typed-SDK seeder).hero_rpc_osis::rpc::bootstrap::{run, run_for_test, RunningServer}. Recipe_server'smain.rscollapses from ~100 lines of inline spin-up to a singlebootstrap::run::<OsisRecipes>(...)call. Tests, benches, and runnable examples reuse the same path viarun_for_test(gated behindtest-supportfeature).crates/osis/src/seed/deleted. TOML/JSON ingest moves to the typed SDK'sseed::{blank, random, from_dir}(emitted into each scaffolded SDK by the newseed_emit.rscodegen).greeting.new(GreetingInput) -> sidround-trips against an in-process server, thengreeting.set(sid, GreetingInput)updates in place. Old "OTime caveat block" deleted.docs/adr/002-single-source-of-truth-types-and-seeding.mdcodifies the five rules. Linked from README; companion link landed inhero_skillsPR.Companion PRs
OTime::now()to non-wasm targets so the unified type compiles in browser WASM.hero_osis_seedbinary +--seed-dirstartup hook.hero_service_scaffold.All four squash-merge into
development.Acceptance verification
cargo check --workspaceclean.cargo build --workspaceinexamples/recipe_serverclean.cargo run -p hero_walkthroughruns end-to-end:greeting.new(GreetingInput{name:"world", message:"Hello, Hero!"}) -> "0:0:0001", thengreeting.set("0:0:0001", GreetingInput{...})updates in place,greeting.list_fullshows the updated row.RecipesClient::recipe_new(client, None, RecipeInput::default()).awaitreturns a sid.RecipesClient::recipe_set(client, None, sid, RecipeInput { name: "x".into(), ..Default::default() }).awaitupdates the row.RecipesClient::recipe_get(client, None, sid).awaitreturns a Recipe withcreated_at: OTime(deserialises cleanly).grepconfirms no duplicate type emissions across the codegen (the SDK trait file and the server'stypes.rsresolveOTimeto the sameherolib_otoml::OTime).hero_osis_seedbinary +crates/osis/src/seed/are gone.Known follow-ups (not blocking #117)
cargo check --target wasm32-unknown-unknown -p hero_recipes_sdk— fails because hero_rpc2's transitivetokiopulls inmiofor the default feature set. The SDK's WASM transport story is its own thread; tracking under a follow-up.ServiceInfoso/healthand/.well-known/heroservice.jsonnow return defaults instead of the per-service identity. Behavior delta, not a regression — flagged for a small follow-up that takesOption<ServiceInfo>.seed_dir: Option<String>field (crates/osis/src/rpc/server.rs:137) is unreachable after the seed module deletion but still compiles. Dead-code cleanup deferred.Test plan
cargo check --workspace(clean)cargo build --workspacefor hero_rpc +examples/recipe_server(clean)cargo run -p hero_walkthrough(live end-to-end)The `hero_rpc_osis::seed` module bypassed the typed SDK and POSTed TOML-derived JSON straight to the JSON-RPC endpoint. It was driven by the standalone `hero_osis_seed` binary in hero_osis (being deleted in parallel) and called from a deprecated `--seed-dir` startup hook on `hero_osis_server`. After hero_rpc#117 the only blessed seeding path is the typed-SDK helper emitted alongside each `<service>_sdk` crate (`<crate>::seed::{blank, random, from_dir}`). This commit removes the legacy module. - delete crates/osis/src/seed/{mod.rs,seeder.rs} - drop `pub mod seed;` from crates/osis/src/lib.rs ADR landed at docs/adr/002-single-source-of-truth-types-and-seeding.md. Refs: hero_rpc#117- rpc2_adapter::extract_data: forward params verbatim for `new` too (was emitting an empty string, which broke the new `<type>_rpc_new(params)` shape introduced by the codegen split). `new` and `set` now share the same "whole params object stringified" path; the OSchema-emitted dispatcher pulls fields out by name. - examples/walkthrough/src/main.rs: * step 6 calls `greeting.new` with `{"data": GreetingInput}` and gets back the assigned sid, then `greeting.set` with `{"sid", "data"}` to update in place — exercising the full new CRUD shape end-to-end. * `DemoApp::handle_rpc_call` gains a real `"new"` arm (sid + timestamp assignment) and the `"set"` arm switches to load-then-overlay (was deserializing the entire Greeting from `data`). - docs/adr/002-single-source-of-truth-types-and-seeding.md (new) — codifies the five rules: one type per OSchema definition; WASM gating at the primitive layer (herolib_otoml::OTime); server-managed fields excluded from the input surface; CRUD split into new/set; typed-SDK seeder is the only blessed seeding path. Linked from README.md. Refs: hero_rpc#117Schemas that use only `otime` (or no OTOML primitives at all besides the auto-injected `created_at` / `updated_at` on rootobjects) previously pulled in `OAddress` / `OCur` / `OLocation` unconditionally — the codegen used a single bool ("any OTOML at all?") to gate the import line. After hero_rpc#117 moved server-managed timestamps onto `OTime`, the import line is wider than necessary on most schemas and downstream crates see unused-import warnings. Switch to per-primitive `needs_primitive(target)` so the emitted line only includes the names that actually appear. For the recipe_server example schema (`Recipe`, `Collection` — only OTime referenced) the import line collapses from `use herolib_otoml::{OTime, OCur, OLocation, OAddress, OtomlSerialize};` to `use herolib_otoml::{OTime, OtomlSerialize};` The wasm-twin emitter (`RustWasmStructGenerator`) still uses the old `needs_otoml_types()` predicate via `generate_builtin_types`; that path is kept compiling with `#[allow(dead_code)]` on the unused helpers. Refs: hero_rpc#117