Audit alignment with hero_skills + assess migration to upgraded hero_rpc #41

Closed
opened 2026-05-19 23:44:38 +00:00 by timur · 4 comments
Owner

Context

Over the past week, Kristof did a substantial alignment pass on main to bring hero_logic in line with current Hero ecosystem standards. While that was happening, feature work was happening on side branches (feat/39-logic-model etc.) that don't yet have Kristof's fixes.

Meanwhile, hero_rpc and hero_skills got a major upgrade (parent META hero_skills#262 — now closed): canonical scaffolder, OSchema codegen with Python/JS/Rhai/Rust SDKs, hero_rpc2 trait pattern, service.toml as source of truth, hero_admin_lib for the admin UI, the new hero_service template repo as a clone-me reference.

Friend reported problems running hero_logic and concerns that skills/template/best-practices weren't being followed. This issue is the audit + reconciliation.

Kristof's recent alignment commits on main (reference)

  • 0b4e1cc — add service.toml manifests, use service_base!() macro, drop legacy build scripts
  • 165eeaa — pin Hero ecosystem deps to 0.6.0, normalize rust-version
  • be4afcd — graceful SIGTERM/SIGINT shutdown on _server
  • 4be2dc1 — wire Hero file logger into tracing on both binaries
  • b69697c — normalize rust-version + Axum 0.8 curly-brace routes
  • 470e464 — migrate path resolution to herolib_core::base helpers
  • 2ed6a80 — bump hero RPC/lib deps, add hero_service patch, drop herolib_ai + stale reports
  • 4158f97 — split hero_logic into _server, _sdk, _cli crates (canonical naming)
  • a854695 — migrate hero_logic_admin to hero_admin_lib patterns
  • 0b3b473hero_logic_admin routes use typed SDK client
  • 07ed752 — parallelize RPC calls in admin route handlers

Note: hero_lifecycle rename (was hero_service) happened in hero_rpc#55 after 2ed6a80. The patch reference may need flipping.

What to do

1. Verify main works end-to-end

From a clean clone of main:

  • cargo build --workspace clean
  • lab infocheck — 0 findings, 0 errors
  • lab service hero_logic --install builds and installs the 3 binaries (hero_logic, hero_logic_server, hero_logic_admin)
  • lab service hero_logic --start — server + admin bind their sockets
  • --info / --info --json on every binary returns the embedded service.toml
  • Smoke tests per hero_skills/skills/hero/service/hero_service_check_fix.md §7: /health, /openrpc.json non-empty, /.well-known/heroservice.json, JSON-RPC system.ping

If any of these fail, fix in main (or open a PR against main).

2. Audit against current canonical references

Compare hero_logic's main against:

Flag any divergences in a comment: missing pieces, stale dep refs (e.g. hero_servicehero_lifecycle rename), legacy patterns that should be migrated.

3. Assess migration to upgraded hero_rpc — read-only proposal

hero_logic currently uses traditional hand-rolled SDK + hand-written OpenRPC + Axum + Askama. The upgraded hero_rpc now generates all of that (server, SDK, OpenRPC spec, Rust/JS/Python/Rhai bindings) from an .oschema source of truth.

Don't migrate in this issue. Do evaluate:

  • Is hero_logic's RPC surface a good fit for OSchema codegen? (How complex are the types? Custom serialization? Streaming?)
  • What would the migration cost be — how much hand-written code gets replaced vs preserved?
  • Are there things hero_logic does that the codegen can't yet emit?
  • Worth opening as its own follow-up issue if migration looks viable.

Write the assessment as a comment on this issue. Do not actually migrate without sign-off.

Acceptance

  • Comment confirming main passes all the §1 checks (or PR opened with fixes against main if any failed).
  • Comment listing every divergence found in §2 + a fix recommendation per item.
  • Comment assessing the §3 OSchema migration — viable / not viable / out-of-scope, with reasoning.
  • Friend can run hero_logic from main end-to-end without surprises.

Out of scope

  • The feat/39-logic-model feature branch — separate concern; will be reconciled by merging main forward later.
  • Actually doing the hero_rpc OSchema migration — that's a follow-up if §3 says viable.
## Context Over the past week, Kristof did a substantial alignment pass on `main` to bring hero_logic in line with current Hero ecosystem standards. While that was happening, feature work was happening on side branches (`feat/39-logic-model` etc.) that don't yet have Kristof's fixes. Meanwhile, `hero_rpc` and `hero_skills` got a major upgrade (parent META [hero_skills#262](https://forge.ourworld.tf/lhumina_code/hero_skills/issues/262) — now closed): canonical scaffolder, OSchema codegen with Python/JS/Rhai/Rust SDKs, hero_rpc2 trait pattern, `service.toml` as source of truth, `hero_admin_lib` for the admin UI, the new [`hero_service` template repo](https://forge.ourworld.tf/lhumina_code/hero_service) as a clone-me reference. Friend reported problems running `hero_logic` and concerns that skills/template/best-practices weren't being followed. This issue is the audit + reconciliation. ## Kristof's recent alignment commits on `main` (reference) - [`0b4e1cc`](https://forge.ourworld.tf/lhumina_code/hero_logic/commit/0b4e1cc) — add `service.toml` manifests, use `service_base!()` macro, drop legacy build scripts - [`165eeaa`](https://forge.ourworld.tf/lhumina_code/hero_logic/commit/165eeaa) — pin Hero ecosystem deps to 0.6.0, normalize rust-version - [`be4afcd`](https://forge.ourworld.tf/lhumina_code/hero_logic/commit/be4afcd) — graceful SIGTERM/SIGINT shutdown on `_server` - [`4be2dc1`](https://forge.ourworld.tf/lhumina_code/hero_logic/commit/4be2dc1) — wire Hero file logger into tracing on both binaries - [`b69697c`](https://forge.ourworld.tf/lhumina_code/hero_logic/commit/b69697c) — normalize rust-version + Axum 0.8 curly-brace routes - [`470e464`](https://forge.ourworld.tf/lhumina_code/hero_logic/commit/470e464) — migrate path resolution to `herolib_core::base` helpers - [`2ed6a80`](https://forge.ourworld.tf/lhumina_code/hero_logic/commit/2ed6a80) — bump hero RPC/lib deps, add `hero_service` patch, drop `herolib_ai` + stale reports - [`4158f97`](https://forge.ourworld.tf/lhumina_code/hero_logic/commit/4158f97) — split hero_logic into `_server`, `_sdk`, `_cli` crates (canonical naming) - [`a854695`](https://forge.ourworld.tf/lhumina_code/hero_logic/commit/a854695) — migrate `hero_logic_admin` to `hero_admin_lib` patterns - [`0b3b473`](https://forge.ourworld.tf/lhumina_code/hero_logic/commit/0b3b473) — `hero_logic_admin` routes use typed SDK client - [`07ed752`](https://forge.ourworld.tf/lhumina_code/hero_logic/commit/07ed752) — parallelize RPC calls in admin route handlers Note: `hero_lifecycle` rename (was `hero_service`) happened in `hero_rpc#55` after `2ed6a80`. The patch reference may need flipping. ## What to do ### 1. Verify `main` works end-to-end From a clean clone of `main`: - `cargo build --workspace` clean - `lab infocheck` — 0 findings, 0 errors - `lab service hero_logic --install` builds and installs the 3 binaries (`hero_logic`, `hero_logic_server`, `hero_logic_admin`) - `lab service hero_logic --start` — server + admin bind their sockets - `--info` / `--info --json` on every binary returns the embedded `service.toml` - Smoke tests per `hero_skills/skills/hero/service/hero_service_check_fix.md` §7: `/health`, `/openrpc.json` non-empty, `/.well-known/heroservice.json`, JSON-RPC `system.ping` If any of these fail, fix in `main` (or open a PR against `main`). ### 2. Audit against current canonical references Compare hero_logic's `main` against: - [`hero_proc`](https://forge.ourworld.tf/lhumina_code/hero_proc) — canonical wiring reference - [`hero_service`](https://forge.ourworld.tf/lhumina_code/hero_service) — canonical template repo - [`hero_skills/skills/hero/service/*`](https://forge.ourworld.tf/lhumina_code/hero_skills/src/branch/development/skills/hero/service) — the standards Flag any divergences in a comment: missing pieces, stale dep refs (e.g. `hero_service` → `hero_lifecycle` rename), legacy patterns that should be migrated. ### 3. Assess migration to upgraded hero_rpc — read-only proposal hero_logic currently uses traditional hand-rolled SDK + hand-written OpenRPC + Axum + Askama. The upgraded `hero_rpc` now generates all of that (server, SDK, OpenRPC spec, Rust/JS/Python/Rhai bindings) from an `.oschema` source of truth. **Don't migrate** in this issue. **Do** evaluate: - Is hero_logic's RPC surface a good fit for OSchema codegen? (How complex are the types? Custom serialization? Streaming?) - What would the migration cost be — how much hand-written code gets replaced vs preserved? - Are there things hero_logic does that the codegen can't yet emit? - Worth opening as its own follow-up issue if migration looks viable. Write the assessment as a comment on this issue. Do not actually migrate without sign-off. ## Acceptance - Comment confirming `main` passes all the §1 checks (or PR opened with fixes against `main` if any failed). - Comment listing every divergence found in §2 + a fix recommendation per item. - Comment assessing the §3 OSchema migration — viable / not viable / out-of-scope, with reasoning. - Friend can run `hero_logic` from `main` end-to-end without surprises. ## Out of scope - The `feat/39-logic-model` feature branch — separate concern; will be reconciled by merging `main` forward later. - Actually doing the hero_rpc OSchema migration — that's a follow-up if §3 says viable.
Author
Owner

§1 — main end-to-end verification

Worked from a worktree of origin/main at 07ed752 on a branch audit-41. Three fixes were needed before main could clear the §1 checks; they're on audit-41 and I'll open them as a PR shortly.

What I found

Check Before fixes After fixes
cargo build --workspace (with sibling hero_website_framework) clean clean
cargo metadata from canonical lab coderoot (~/hero/code/hero_logic) failshero_admin_lib path dep needs sibling not present clean
lab infocheck 1 findinghero_logic_server missing service_base!() 0 findings, 3/3 crates clean
lab service hero_logic --install 3 failures — every --info check fails (root-caused by canonical clone being on development + path-dep failure + missing macro) clean, all 3 binaries installed
--info / --info --json per binary server+admin hang (15s timeout), CLI errors with clap server+admin print TOML/JSON and exit 0; CLI same
/health, /openrpc.json, /.well-known/heroservice.json on rpc.sock n/a (couldn't start) all pass — 57 methods declared, well-known JSON correctly identifies protocol = "openrpc"
/health, /.well-known/heroservice.json on admin.sock n/a both pass, admin returns protocol = "http"
JSON-RPC system.ping n/a not implementedhero_rpc_server (current OServer) doesn't register any system.* builtins. See open items below

Fixes landed on audit-41

  1. 8f51afdfix(server): use service_base!() macro. hero_logic_server/src/main.rs was hand-rolling the SERVICE_TOML + BUILD_NR consts the macro emits. lab infocheck flags any binary missing the macro call; replacing the hand-roll with use herolib_core::service_base; service_base!(); brings the server in line with the CLI and admin crates (both already used it). Diff: −17 +2.
  2. 8d035e4fix(deps): hero_admin_lib as git dep, not relative path. Root Cargo.toml had hero_admin_lib = { path = "../hero_website_framework/crates/hero_admin_lib" }. The canonical lab-managed coderoot at ~/hero/code/ has no sibling hero_website_framework clone, so cargo metadata fails out of the box. Switched to the git dep both hero_proc and the hero_service template use: { git = "https://forge.ourworld.tf/lhumina_code/hero_website_framework.git", branch = "development" }.
  3. 6499aacfix(service.toml): mirror hero_proc — each per-crate file is the full service. Each per-crate service.toml previously listed only its own binary. hero_proc's pattern (cli, server, admin all carry the same [[binaries]] list, differing only in [service.crate]) is what lab relies on: it reads <bin> --info --json from one binary and expects the full binary inventory back. Updated all three files. Also normalized hero_logic_admin's [service] block back to the canonical "Hero Logic" copy from the server — [service] describes the SERVICE, not the crate.

Open items not fixed on audit-41

These came up during §1 but are not hero_logic bugs — flagging here so they don't surprise the next reader.

  • lab service hero_logic --start still doesn't iterate companion binaries. hero_skills/crates/lab/src/service/service_manager.rs has a hardcoded SERVICE_MAP listing every known service's companion daemons (hero_proc[hero_proc_server, hero_proc_admin], etc.). hero_logic isn't in the map, so resolve_service("hero_logic") returns [hero_logic] (just the CLI), and --start bails with kind = "cli", not a long-running service. The code already carries a LONG-TERM TODO to replace SERVICE_MAP with dynamic discovery from each binary's embedded service.toml. Short-term fix: a one-line entry in SERVICE_MAP for hero_logic. Worth its own follow-up issue against hero_skills.
  • system.ping smoke test fails because hero_rpc_server doesn't register any system.* builtins. The skill hero_service_check_fix.md §7 expects POST /rpc {"method":"system.ping"} to succeed; hero_rpc2 adds it (see example/recipe_sdk_rpc2/tests/debug_curl.rs:18 registering system.ping), but the OServer that hero_logic_server runs on doesn't. This is a framework gap — either OServer needs a default system.ping, or §7 needs to acknowledge "system.* methods require hero_rpc2." Cross-references the §3 OSchema/hero_rpc2 migration question.
  • PATH_ROOT panic when hero_proc spawns the server. lab service hero_logic_server --start panics in herolib_core::base::paths::path_root() with PATH_ROOT is not set — run lab user init first. The user's ~/hero/cfg/ has no init.sh or hero_cfg.toml, so lab user init/shell-init was never run. hero_proc_server itself runs fine without PATH_ROOT because it never calls path_root(); hero_logic_server does, transitively via resolve_socket_dir → path_var → path_root. For verification I exported PATH_ROOT=~/hero and HERO_SOCKET_DIR=~/hero/var/sockets and started the binaries directly — all socket smoke tests then passed. Worth a docs note in hero_service_check_fix.md §7 that lab user init is a prerequisite, or a path_root() fallback to $HOME/hero when unset.

Manual smoke-test transcript (with PATH_ROOT/HERO_SOCKET_DIR set)

===rpc /health===
{"status":"ok","service":"hero_logic","version":"0.1.0","context_header":"X-Hero-Context"}

===rpc /openrpc.json — method count===
methods: 57   title: hero_logic

===rpc /.well-known/heroservice.json===
{"protocol":"openrpc","name":"hero_logic","title":"hero_logic","version":"0.1.0",...,"socket":"rpc"}

===rpc system.ping===
{"error":{"code":-32000,"message":"Unknown method: system.ping. Available: benchmark.*, example.*, play.*, workflow.*, workflowversion.*, logicservice.*"}}

===admin /health===
{"service":"hero_logic","status":"ok","version":"0.1.0"}

===admin /.well-known/heroservice.json===
{"protocol":"http","name":"hero_logic","title":"Hero Logic Admin UI","version":"0.1.0","socket":"admin"}

===admin / (HTML head)===
<!DOCTYPE html>… <title>Hero Logic</title>

Acceptance

PR opening against main for the three commits above. After that lands, main clears every §1 check that doesn't depend on the three external items above.

PR: #42

## §1 — `main` end-to-end verification Worked from a worktree of `origin/main` at `07ed752` on a branch `audit-41`. Three fixes were needed before `main` could clear the §1 checks; they're on `audit-41` and I'll open them as a PR shortly. ### What I found | Check | Before fixes | After fixes | |---|---|---| | `cargo build --workspace` (with sibling `hero_website_framework`) | clean | clean | | `cargo metadata` from canonical lab coderoot (`~/hero/code/hero_logic`) | **fails** — `hero_admin_lib` path dep needs sibling not present | clean | | `lab infocheck` | **1 finding** — `hero_logic_server` missing `service_base!()` | 0 findings, 3/3 crates clean | | `lab service hero_logic --install` | **3 failures** — every `--info` check fails (root-caused by canonical clone being on `development` + path-dep failure + missing macro) | clean, all 3 binaries installed | | `--info` / `--info --json` per binary | server+admin hang (15s timeout), CLI errors with clap | server+admin print TOML/JSON and exit 0; CLI same | | `/health`, `/openrpc.json`, `/.well-known/heroservice.json` on rpc.sock | n/a (couldn't start) | all pass — 57 methods declared, well-known JSON correctly identifies `protocol = "openrpc"` | | `/health`, `/.well-known/heroservice.json` on admin.sock | n/a | both pass, admin returns `protocol = "http"` | | JSON-RPC `system.ping` | n/a | **not implemented** — `hero_rpc_server` (current OServer) doesn't register any `system.*` builtins. See open items below | ### Fixes landed on `audit-41` 1. `8f51afd` — **`fix(server): use service_base!() macro`**. `hero_logic_server/src/main.rs` was hand-rolling the `SERVICE_TOML` + `BUILD_NR` consts the macro emits. `lab infocheck` flags any binary missing the macro call; replacing the hand-roll with `use herolib_core::service_base; service_base!();` brings the server in line with the CLI and admin crates (both already used it). Diff: −17 +2. 2. `8d035e4` — **`fix(deps): hero_admin_lib as git dep, not relative path`**. Root Cargo.toml had `hero_admin_lib = { path = "../hero_website_framework/crates/hero_admin_lib" }`. The canonical lab-managed coderoot at `~/hero/code/` has no sibling `hero_website_framework` clone, so `cargo metadata` fails out of the box. Switched to the git dep both `hero_proc` and the `hero_service` template use: `{ git = "https://forge.ourworld.tf/lhumina_code/hero_website_framework.git", branch = "development" }`. 3. `6499aac` — **`fix(service.toml): mirror hero_proc — each per-crate file is the full service`**. Each per-crate `service.toml` previously listed only its own binary. `hero_proc`'s pattern (cli, server, admin all carry the same `[[binaries]]` list, differing only in `[service.crate]`) is what `lab` relies on: it reads `<bin> --info --json` from one binary and expects the full binary inventory back. Updated all three files. Also normalized `hero_logic_admin`'s `[service]` block back to the canonical "Hero Logic" copy from the server — `[service]` describes the SERVICE, not the crate. ### Open items not fixed on `audit-41` These came up during §1 but are not hero_logic bugs — flagging here so they don't surprise the next reader. - **`lab service hero_logic --start` still doesn't iterate companion binaries.** `hero_skills/crates/lab/src/service/service_manager.rs` has a hardcoded `SERVICE_MAP` listing every known service's companion daemons (`hero_proc` → `[hero_proc_server, hero_proc_admin]`, etc.). `hero_logic` isn't in the map, so `resolve_service("hero_logic")` returns `[hero_logic]` (just the CLI), and `--start` bails with `kind = "cli", not a long-running service`. The code already carries a `LONG-TERM` TODO to replace `SERVICE_MAP` with dynamic discovery from each binary's embedded `service.toml`. Short-term fix: a one-line entry in `SERVICE_MAP` for `hero_logic`. Worth its own follow-up issue against `hero_skills`. - **`system.ping` smoke test fails because `hero_rpc_server` doesn't register any `system.*` builtins.** The skill `hero_service_check_fix.md` §7 expects `POST /rpc {"method":"system.ping"}` to succeed; `hero_rpc2` adds it (see `example/recipe_sdk_rpc2/tests/debug_curl.rs:18` registering `system.ping`), but the OServer that `hero_logic_server` runs on doesn't. This is a framework gap — either OServer needs a default `system.ping`, or §7 needs to acknowledge "system.* methods require hero_rpc2." Cross-references the §3 OSchema/hero_rpc2 migration question. - **`PATH_ROOT` panic when `hero_proc` spawns the server.** `lab service hero_logic_server --start` panics in `herolib_core::base::paths::path_root()` with `PATH_ROOT is not set — run lab user init first`. The user's `~/hero/cfg/` has no `init.sh` or `hero_cfg.toml`, so `lab user init`/`shell-init` was never run. `hero_proc_server` itself runs fine without `PATH_ROOT` because it never calls `path_root()`; `hero_logic_server` does, transitively via `resolve_socket_dir → path_var → path_root`. For verification I exported `PATH_ROOT=~/hero` and `HERO_SOCKET_DIR=~/hero/var/sockets` and started the binaries directly — all socket smoke tests then passed. Worth a docs note in `hero_service_check_fix.md` §7 that `lab user init` is a prerequisite, or a `path_root()` fallback to `$HOME/hero` when unset. ### Manual smoke-test transcript (with `PATH_ROOT`/`HERO_SOCKET_DIR` set) ``` ===rpc /health=== {"status":"ok","service":"hero_logic","version":"0.1.0","context_header":"X-Hero-Context"} ===rpc /openrpc.json — method count=== methods: 57 title: hero_logic ===rpc /.well-known/heroservice.json=== {"protocol":"openrpc","name":"hero_logic","title":"hero_logic","version":"0.1.0",...,"socket":"rpc"} ===rpc system.ping=== {"error":{"code":-32000,"message":"Unknown method: system.ping. Available: benchmark.*, example.*, play.*, workflow.*, workflowversion.*, logicservice.*"}} ===admin /health=== {"service":"hero_logic","status":"ok","version":"0.1.0"} ===admin /.well-known/heroservice.json=== {"protocol":"http","name":"hero_logic","title":"Hero Logic Admin UI","version":"0.1.0","socket":"admin"} ===admin / (HTML head)=== <!DOCTYPE html>… <title>Hero Logic</title> ``` ### Acceptance PR opening against `main` for the three commits above. After that lands, `main` clears every §1 check that doesn't depend on the three external items above. PR: https://forge.ourworld.tf/lhumina_code/hero_logic/pulls/42
Author
Owner

§2 — Divergence audit vs. hero_proc + hero_service template + hero_skills service skills

Reading order: I followed the META authority order (child issue comments > umbrella > skills > reference services). Reference snapshots used: hero_proc@f0ba646, hero_service@518448c, hero_skills@e95b7ec, hero_rpc@155768b, hero_lib@5b3e47a0 (all on origin/development as of audit time).

The findings are grouped by severity, each with a one-line fix recommendation.


A. Already-fixed in PR #42 (resurfaced for tracking)

These are §1 fixes I rolled into the PR; flagging here so the audit list is complete.

  1. hero_logic_server/src/main.rs was missing service_base!() — hand-rolled SERVICE_TOML + BUILD_NR consts instead of using the canonical macro. CLI + admin already used it. Fix: PR #42 commit 8f51afd.
  2. Root Cargo.toml used hero_admin_lib = { path = "../hero_website_framework/..." }hero_proc and the hero_service template both use a git dep on branch = "development". The relative path broke cargo metadata in the canonical lab coderoot. Fix: PR #42 commit 8d035e4.
  3. Per-crate service.toml files listed only their own binaryhero_proc's pattern (every per-crate file carries the full [[binaries]] list, only [service.crate] differs) is what lab reads from <bin> --info --json. Fix: PR #42 commit 6499aac.

B. Real divergences NOT in PR #42 — actionable

B1. Missing canonical CI workflow .forgejo/workflows/lab-publish.yaml

hero_proc just landed (f0ba646) the canonical lab-publish.yaml that hero_skills standardized on (see hero_skills#268). The commit message says explicitly: "Drop this file verbatim into any hero_ repo's .forgejo/workflows/ and it Just Works, provided the repo has FORGEJO_TOKEN in its Actions secrets."*

hero_logic has only the old build-linux.yaml (tag-triggered, manual BINARIES shell loop). It is the same template the META calls out as superseded.

Fix: copy hero_proc/.forgejo/workflows/lab-publish.yaml verbatim into hero_logic/.forgejo/workflows/lab-publish.yaml. Keep build-linux.yaml for now (per hero_proc's transition plan: it only fires on v* tags so it doesn't race with the push-to-main publish path).

B2. Stale, untracked src/logic/ at the repo root

There's a /src/logic/{rpc.rs, rpc_generated.rs, types.rs, types_generated.rs, osis_server_generated.rs} checked in at the workspace root. It is not a workspace member, no Cargo.toml references it, and the same generated files are duplicated under crates/hero_logic_server/src/logic/{core,server}/. Almost certainly a leftover from before the 4158f97 split into _server/_sdk/_cli crates.

Fix: git rm -r src/ from the repo root.

B3. lab service doesn't know about hero_logic (SERVICE_MAP entry missing)

Flagged in the §1 comment too — repeating here for the audit list. hero_skills/crates/lab/src/service/service_manager.rs::SERVICE_MAP enumerates every service lab service <name> --start knows about. hero_logic isn't there, so --start and --status resolve to just the CLI binary and bail.

Fix: PR against hero_skills adding ("hero_logic", "hero_logic", &["hero_logic_server", "hero_logic_admin"]) and the short alias ("logic", "hero_logic", &["hero_logic_server", "hero_logic_admin"]). The long-term TODO in that same file is to replace SERVICE_MAP with dynamic discovery from --info --json — that would let the §2-PR-42 service.toml work end-to-end without SERVICE_MAP upkeep. Worth a follow-up issue against hero_skills.

B4. PURPOSE.md uses unregistered short alias logic

PURPOSE.md documents:

lab service logic --install

logic is the short alias, but it isn't in SERVICE_MAP either (see B3). Even after B3 lands, the alias is only useful for lab users — Forgejo readers see the docs first.

Fix: change all lab service logic references in PURPOSE.md to lab service hero_logic (matches hero_proc's own PURPOSE.md style). Optional: keep logic as a short alias in SERVICE_MAP.

B5. No README.md

hero_service template and hero_proc both ship a README.md. hero_logic has only PURPOSE.md. README is the first thing rendered on the Forgejo project page.

Fix: add a minimal README.md pointing to PURPOSE.md + the lab service hero_logic lifecycle commands.

B6. No hero_logic_examples crate

The skill marks Examples as Optional, but both hero_proc (crates/hero_proc_examples) and the hero_service template (crates/hero_service_examples) ship one as a clone-me reference for end-users. hero_logic has none — friend would have nowhere to look for "how do I drive this from Rust."

Fix: stub crates/hero_logic_examples/ with one runnable examples/01_connect.rs mirroring hero_service_examples/examples/01_connect.rs. Low priority; add when there's an actual use case.

B7. [workspace.lints] block is absent

hero_proc/Cargo.toml carries a long [workspace.lints.clippy] allow list that suppresses noisy lints uniformly across the workspace. hero_logic has none — the workspace currently builds with 8 unused-code warnings (backend_online, play_detail_handler, pretty_json_or_string, rpc_call, etc.) that would be obvious clippy noise once lints are turned on.

Fix: copy hero_proc's [workspace.lints.clippy] block into hero_logic/Cargo.toml. Then either remove the truly-dead code (play_detail_handler, pretty_json_or_string, rpc_call, backend_online) or silence them with #[allow] if they're scaffolding for in-flight work.

B8. [workspace.package].version is unset

hero_proc declares version = "0.6.0" in [workspace.package]; each crate then uses version.workspace = true. hero_logic's [workspace.package] has no version field, so each crate hard-codes version = "0.1.0". Two consequences:

  • lab and admin's /health already report 0.1.0, but bumping requires touching three Cargo.tomls.
  • The crates can't be published independently from one workspace version pin.

Fix: add version = "0.1.0" to [workspace.package], change each crate's version = "0.1.0" to version.workspace = true.

B9. hero_admin_lib is not a workspace dep (just a Cargo.toml entry)

After PR #42 the root Cargo.toml declares hero_admin_lib = { git = "...", branch = "development" } in [workspace.dependencies], and crates/hero_logic_admin/Cargo.toml uses hero_admin_lib = { workspace = true } — that's fine and matches hero_proc.

Issue: the [workspace.dependencies] hero_admin_lib entry is now the ONLY dep without an explicit version = "0.6.0" pin (every other Hero ecosystem dep there does). Either pin or leave; hero_proc doesn't pin its hero_admin_lib git dep either, so this is fine — flagging for completeness.

No fix needed. Documented for the next reader.

B10. The inspector feature is enabled on hero_rpc_server and serves HTML at GET / of rpc.sock

crates/hero_logic_server/Cargo.toml: hero_rpc_server = { workspace = true, features = ["inspector"] }. That feature embeds an HTML inspector UI on the rpc socket's GET / route. hero_logic_admin already serves the admin UI on a separate admin.sock and embeds <hero-api-docs> from hero_admin_lib — same purpose, better integration. The inspector at rpc.sock's GET / is dead weight on a service that already ships a real admin.

(Not the deprecated hero_inspector crate — different concept. Still redundant.)

Fix: drop features = ["inspector"] from hero_logic_server's dep on hero_rpc_server. Saves the rust-embed + mime_guess deps. Verify nothing in admin proxies through it first.


C. Items the issue body asked about — already clean

Recording the negative findings so they don't get re-investigated.

  • [patch] reference to hero_service / hero_lifecycle rename — the issue body warned the patch "may need flipping." There is no [patch] section anywhere in hero_logic, and hero_service is not in any crate's deps. Already cleaned up (probably between 2ed6a80 and now). No action.
  • hero_inspector crate referencesgrep returns nothing. No action.
  • Makefile, scripts/*.sh, service_hero_logic.nu — none present. ✓
  • Socket pathshero_logic/rpc.sock and hero_logic/admin.sock. Conform to hero_sockets skill. ✓
  • _ui / _client legacy crate names — none. ✓
  • SIGTERM/SIGINT shutdown on all three binaries — landed in Kristof's be4afcd. ✓
  • Hero file logger wired through tracing — all three binaries wire HeroTracingLayer into the tracing_subscriber registry. ✓
  • Canonical service_base!() + validate_service_toml + handle_info_flag + print_startup_banner + prepare_sockets — present on every server/admin binary (after PR #42 for the server). ✓
  • hero_admin_lib admin patterns — admin uses hero_admin_lib::assets::shared_static_handler, hero_admin_lib::middleware::base_path_middleware, hero_admin_lib::routes::{health_response, heroservice_manifest}, hero_admin_lib::socket::bind_admin_socket. Conforms to hero_admin_connection_status / hero_ui_dashboard skills. ✓

Priority

If you only do three things from this list: B1 (canonical CI), B3 (lab SERVICE_MAP entry — pure unblocker), B2 (stale src/). The rest is polish.

## §2 — Divergence audit vs. `hero_proc` + `hero_service` template + `hero_skills` service skills Reading order: I followed the META authority order (child issue comments > umbrella > skills > reference services). Reference snapshots used: `hero_proc@f0ba646`, `hero_service@518448c`, `hero_skills@e95b7ec`, `hero_rpc@155768b`, `hero_lib@5b3e47a0` (all on `origin/development` as of audit time). The findings are grouped by severity, each with a one-line fix recommendation. --- ### A. Already-fixed in PR #42 (resurfaced for tracking) These are §1 fixes I rolled into the PR; flagging here so the audit list is complete. 1. **`hero_logic_server/src/main.rs` was missing `service_base!()`** — hand-rolled `SERVICE_TOML` + `BUILD_NR` consts instead of using the canonical macro. CLI + admin already used it. *Fix: PR #42 commit `8f51afd`.* 2. **Root `Cargo.toml` used `hero_admin_lib = { path = "../hero_website_framework/..." }`** — `hero_proc` and the `hero_service` template both use a git dep on `branch = "development"`. The relative path broke `cargo metadata` in the canonical lab coderoot. *Fix: PR #42 commit `8d035e4`.* 3. **Per-crate `service.toml` files listed only their own binary** — `hero_proc`'s pattern (every per-crate file carries the full `[[binaries]]` list, only `[service.crate]` differs) is what `lab` reads from `<bin> --info --json`. *Fix: PR #42 commit `6499aac`.* --- ### B. Real divergences NOT in PR #42 — actionable #### B1. Missing canonical CI workflow `.forgejo/workflows/lab-publish.yaml` `hero_proc` just landed (`f0ba646`) the canonical `lab-publish.yaml` that hero_skills standardized on (see hero_skills#268). The commit message says explicitly: *"Drop this file verbatim into any hero_* repo's `.forgejo/workflows/` and it Just Works, provided the repo has FORGEJO_TOKEN in its Actions secrets."* hero_logic has only the old `build-linux.yaml` (tag-triggered, manual `BINARIES` shell loop). It is the same template the META calls out as superseded. **Fix**: copy `hero_proc/.forgejo/workflows/lab-publish.yaml` verbatim into `hero_logic/.forgejo/workflows/lab-publish.yaml`. Keep `build-linux.yaml` for now (per hero_proc's transition plan: it only fires on `v*` tags so it doesn't race with the push-to-`main` publish path). #### B2. Stale, untracked `src/logic/` at the repo root There's a `/src/logic/{rpc.rs, rpc_generated.rs, types.rs, types_generated.rs, osis_server_generated.rs}` checked in at the workspace root. It is **not a workspace member**, no `Cargo.toml` references it, and the same generated files are duplicated under `crates/hero_logic_server/src/logic/{core,server}/`. Almost certainly a leftover from before the `4158f97` split into `_server`/`_sdk`/`_cli` crates. **Fix**: `git rm -r src/` from the repo root. #### B3. `lab service` doesn't know about `hero_logic` (`SERVICE_MAP` entry missing) Flagged in the §1 comment too — repeating here for the audit list. `hero_skills/crates/lab/src/service/service_manager.rs::SERVICE_MAP` enumerates every service `lab service <name> --start` knows about. `hero_logic` isn't there, so `--start` and `--status` resolve to just the CLI binary and bail. **Fix**: PR against `hero_skills` adding `("hero_logic", "hero_logic", &["hero_logic_server", "hero_logic_admin"])` and the short alias `("logic", "hero_logic", &["hero_logic_server", "hero_logic_admin"])`. The long-term TODO in that same file is to replace `SERVICE_MAP` with dynamic discovery from `--info --json` — that would let the §2-PR-42 service.toml work end-to-end without `SERVICE_MAP` upkeep. Worth a follow-up issue against `hero_skills`. #### B4. `PURPOSE.md` uses unregistered short alias `logic` `PURPOSE.md` documents: ``` lab service logic --install ``` `logic` is the short alias, but it isn't in `SERVICE_MAP` either (see B3). Even after B3 lands, the alias is only useful for `lab` users — Forgejo readers see the docs first. **Fix**: change all `lab service logic` references in `PURPOSE.md` to `lab service hero_logic` (matches `hero_proc`'s own `PURPOSE.md` style). Optional: keep `logic` as a short alias in `SERVICE_MAP`. #### B5. No `README.md` `hero_service` template and `hero_proc` both ship a `README.md`. `hero_logic` has only `PURPOSE.md`. README is the first thing rendered on the Forgejo project page. **Fix**: add a minimal `README.md` pointing to `PURPOSE.md` + the `lab service hero_logic` lifecycle commands. #### B6. No `hero_logic_examples` crate The skill marks Examples as Optional, but both `hero_proc` (`crates/hero_proc_examples`) and the `hero_service` template (`crates/hero_service_examples`) ship one as a clone-me reference for end-users. hero_logic has none — friend would have nowhere to look for "how do I drive this from Rust." **Fix**: stub `crates/hero_logic_examples/` with one runnable `examples/01_connect.rs` mirroring `hero_service_examples/examples/01_connect.rs`. Low priority; add when there's an actual use case. #### B7. `[workspace.lints]` block is absent `hero_proc/Cargo.toml` carries a long `[workspace.lints.clippy]` allow list that suppresses noisy lints uniformly across the workspace. `hero_logic` has none — the workspace currently builds with 8 unused-code warnings (`backend_online`, `play_detail_handler`, `pretty_json_or_string`, `rpc_call`, etc.) that would be obvious clippy noise once lints are turned on. **Fix**: copy `hero_proc`'s `[workspace.lints.clippy]` block into `hero_logic/Cargo.toml`. Then either remove the truly-dead code (`play_detail_handler`, `pretty_json_or_string`, `rpc_call`, `backend_online`) or silence them with `#[allow]` if they're scaffolding for in-flight work. #### B8. `[workspace.package].version` is unset `hero_proc` declares `version = "0.6.0"` in `[workspace.package]`; each crate then uses `version.workspace = true`. `hero_logic`'s `[workspace.package]` has no `version` field, so each crate hard-codes `version = "0.1.0"`. Two consequences: - `lab` and admin's `/health` already report `0.1.0`, but bumping requires touching three Cargo.tomls. - The crates can't be published independently from one workspace version pin. **Fix**: add `version = "0.1.0"` to `[workspace.package]`, change each crate's `version = "0.1.0"` to `version.workspace = true`. #### B9. `hero_admin_lib` is not a workspace dep (just a Cargo.toml entry) After PR #42 the root Cargo.toml declares `hero_admin_lib = { git = "...", branch = "development" }` in `[workspace.dependencies]`, and `crates/hero_logic_admin/Cargo.toml` uses `hero_admin_lib = { workspace = true }` — that's fine and matches hero_proc. Issue: the `[workspace.dependencies]` `hero_admin_lib` entry is now the ONLY dep without an explicit `version = "0.6.0"` pin (every other Hero ecosystem dep there does). Either pin or leave; `hero_proc` doesn't pin its `hero_admin_lib` git dep either, so this is fine — flagging for completeness. **No fix needed.** Documented for the next reader. #### B10. The `inspector` feature is enabled on `hero_rpc_server` and serves HTML at `GET /` of rpc.sock `crates/hero_logic_server/Cargo.toml`: `hero_rpc_server = { workspace = true, features = ["inspector"] }`. That feature embeds an HTML inspector UI on the rpc socket's `GET /` route. hero_logic_admin already serves the admin UI on a separate `admin.sock` and embeds `<hero-api-docs>` from `hero_admin_lib` — same purpose, better integration. The inspector at rpc.sock's `GET /` is dead weight on a service that already ships a real admin. (Not the deprecated `hero_inspector` crate — different concept. Still redundant.) **Fix**: drop `features = ["inspector"]` from `hero_logic_server`'s dep on `hero_rpc_server`. Saves the `rust-embed` + `mime_guess` deps. Verify nothing in admin proxies through it first. --- ### C. Items the issue body asked about — already clean Recording the negative findings so they don't get re-investigated. - **`[patch]` reference to `hero_service` / `hero_lifecycle` rename** — the issue body warned the patch "may need flipping." There is **no `[patch]` section anywhere in hero_logic**, and `hero_service` is not in any crate's deps. Already cleaned up (probably between `2ed6a80` and now). No action. - **`hero_inspector` crate references** — `grep` returns nothing. No action. - **`Makefile`, `scripts/*.sh`, `service_hero_logic.nu`** — none present. ✓ - **Socket paths** — `hero_logic/rpc.sock` and `hero_logic/admin.sock`. Conform to `hero_sockets` skill. ✓ - **`_ui` / `_client` legacy crate names** — none. ✓ - **SIGTERM/SIGINT shutdown on all three binaries** — landed in Kristof's `be4afcd`. ✓ - **Hero file logger wired through `tracing`** — all three binaries wire `HeroTracingLayer` into the `tracing_subscriber` registry. ✓ - **Canonical `service_base!()` + `validate_service_toml` + `handle_info_flag` + `print_startup_banner` + `prepare_sockets`** — present on every server/admin binary (after PR #42 for the server). ✓ - **`hero_admin_lib` admin patterns** — admin uses `hero_admin_lib::assets::shared_static_handler`, `hero_admin_lib::middleware::base_path_middleware`, `hero_admin_lib::routes::{health_response, heroservice_manifest}`, `hero_admin_lib::socket::bind_admin_socket`. Conforms to `hero_admin_connection_status` / `hero_ui_dashboard` skills. ✓ --- ### Priority If you only do three things from this list: **B1** (canonical CI), **B3** (lab `SERVICE_MAP` entry — pure unblocker), **B2** (stale `src/`). The rest is polish.
Author
Owner

§3 — OSchema / upgraded hero_rpc migration assessment (read-only)

TL;DR

Viable, low-risk, but not urgent. Recommend opening as its own follow-up issue and timing it for after hero_rpc#54/55/56 land so we migrate onto a settled target rather than a moving one.

The framing in the issue body — "hero_logic currently uses traditional hand-rolled SDK + hand-written OpenRPC + Axum + Askama" — is partly outdated. hero_logic is already on the OSchema codegen path; it's the older version of it. The "migration" is really an upgrade from the old codegen API to the new one, not a wholesale rewrite.


What hero_logic already has on the codegen side

Layer Today Source
Types OSchema-generated (types_generated.rs, types.rs for hand impls) crates/hero_logic_server/build.rs via OschemaBuildConfig::new().domain("logic", …).generate_server().nested_layout()
OSIS storage layer OSchema-generated (osis_server_generated.rs) same build.rs
RPC handlers (CRUD) OSchema-generated (rpc_generated.rs) same build.rs
RPC handlers (business logic) Hand-written (rpc.rs) 21 of the 57 methods (logicservice.*)
OpenRPC spec OSchema-generated (specs/openrpc.json) same build.rs
Rust SDK client Generated from openrpc.json via hero_rpc_derive::openrpc_client! macro crates/hero_logic_sdk/src/lib.rs
Admin RPC client Two clients side-by-side — typed LogicServiceClient for declared methods, hand-rolled LogicRpcClient for auto-generated OSIS CRUD (workflow.list, play.list, etc.) the SDK doesn't expose typed wrappers for crates/hero_logic_admin/src/{main,rpc_client}.rs

So hero_logic is sitting on roughly the codegen state hero_service@518448c (the canonical template) is on. The "hand-rolled" footprint that would shrink in a migration is small and well-located.

What's actually different in the upgraded path (per hero_service template + META #262)

Comparing hero_service@518448c (canonical template) and hero_logic@main:

  1. OschemaBuildConfig gains new fields that hero_logic doesn't use yet: sdk_dir, client_crate_dir, server_crate_dir, server_types_crate, sdk_types_crate, with_wasm(). The hero_service config splits types so a shared hero_service crate holds them, consumed by both hero_service_server and hero_service_sdk. Today hero_logic's types live duplicated in crates/hero_logic_server/src/logic/core/types_generated.rs (server) and would also appear in crates/hero_logic_sdk/ if the SDK ever needed them. This is the main structural change.
  2. Server bootstrap moves to HeroLifecycle + OServer::run_cli. hero_service template:
    let lifecycle = HeroLifecycle::new("hero_service_server", repo_url, "hero_service_server")
        .description("…");
    OServer::run_cli(lifecycle, |server, contexts, _seed_dir, _seed_domains| async move {
        server.register::<OsisCatalog>(ctx, "catalog").await?;
        Ok(())
    }).await
    
    vs hero_logic today:
    let config = OServerConfig::new().name(SERVICE_NAME).description(DESCRIPTION);
    let server = OServer::new(config).await?;
    server.register::<OsisLogic>("root", "logic").await?;
    server.run().await
    
    HeroLifecycle plugs into the renamed hero_lifecycle crate (was hero_service per hero_rpc#55).
  3. Codegen emits the typed CRUD wrappers that today hero_logic_admin's hand-rolled LogicRpcClient exists to paper over. Once those wrappers land, the entire rpc_client.rs (28 lines) and the comment in AppState::sdk() ("Raw transport — keep for the auto-generated OSIS CRUD whose typed wrappers don't live in the SDK yet") go away.
  4. JS / Rhai / Python SDK targets join the Rust SDK. hero_logic already commits crates/hero_logic_server/sdk/{js,python}/ — looks like an in-progress version of this already.
  5. with_wasm() adds the WASM-compatible type variants (types_wasm_generated.rs in hero_service template).
  6. hero_rpc2 (the second half of META's "hybrid hero_rpc + hero_rpc2" decision) is not part of this yet. hero_rpc#55 covers vendoring it. hero_service template doesn't use it either. So "migrate to upgraded hero_rpc" today does NOT mean "migrate to #[rpc(server, client)] macros" — that's a tier-after-tier follow-up.

What does NOT migrate

These stay untouched regardless of codegen path:

  • engine/ (Python executor, DAG runner) — pure domain code.
  • seed.rs + seed_flows/ — built-in flow definitions.
  • tracing_layer.rsHeroTracingLayer wires tracing into the Hero file logger.
  • services/ — auxiliary handlers.
  • crates/hero_logic_admin/templates/ (Askama) + 1719-line routes.rs — admin UI lives here, codegen doesn't touch it.
  • crates/hero_logic/src/main.rs — CLI clap tree, hand-written, calls the generated SDK but doesn't get generated itself.
  • The 21 hand-written logicservice.* methods (Python execution, span pushes, play lifecycle) — these have business logic OSchema CRUD wouldn't capture.

So the migration footprint is roughly: build.rs + src/main.rs of the server + reorganizing where generated types live + deleting admin/src/rpc_client.rs. Maybe ~300 LOC delta, plus path-dep adjustments.

What could block the migration

I looked for these specifically since the issue asked. Net: nothing fundamental.

Concern Verdict
Custom serialization (non-standard serde, binary formats) None. All types are vanilla derive Serialize/Deserialize over JSON.
Streaming or long-lived bidirectional RPC None. All 57 methods are request/response. service.toml has sse = false everywhere.
Unusual type shapes (recursive, generic, trait objects across RPC boundary) None spotted. Types are flat structs, vecs of structs, enums-as-string. The python_source b64-prefix encoding is handled in client code (hero_logic_sdk::decode_python_source), not in serde.
OServer features hero_logic depends on that the new path doesn't have inspector feature (HTML at GET / on rpc.sock) — but flagged in §2 audit as redundant since admin exists. Drop, don't migrate.
Context routing (X-Hero-Context header → typed HeroRequestContext) Not currently used by hero_logic. Would gain from migration but doesn't block.
Custom Axum middleware on the rpc.sock None — OServer::run does its own routing.

The one non-blocker but quirk worth noting: hero_logic's python_source field carries an optional b64: prefix because Python source with mixed newlines/quotes is annoying to round-trip cleanly through JSON. The decoder lives in hero_logic_sdk::decode_python_source. After migration this would need to remain a hand-written helper in the SDK (codegen won't infer it) — fine, but worth knowing the helper has to be preserved.

Cost estimate

Phase Effort Notes
build.rs upgrade to new OschemaBuildConfig fields 1–2 hours Mostly copy from hero_service template + adjust paths
Server main.rsHeroLifecycle::run_cli pattern 2–4 hours Adopt closure pattern; thread the seed-flow spawn through it
Reorganize types into shared hero_logic types crate (if we follow hero_service template's split) 4–8 hours Touches imports across _server, _sdk, _admin
Delete admin/src/rpc_client.rs + switch admin to typed wrappers everywhere 2–4 hours Depends on codegen emitting wrappers for workflow.list, play.list, example.list (currently the SDK gap)
Adopt JS / Rhai / Python SDK targets in sdk_dir 0–2 hours Already partially committed; mostly config
Validate end-to-end: full smoke + admin clicks 2 hours Existing tests should still pass

Total: roughly 1–2 days of focused work, single person. Reversible if anything blows up — the OschemaBuildConfig changes are additive and the runtime change is one main.rs.

Recommendation

  1. Open as its own follow-up issue against hero_logic, titled something like "Upgrade to hero_service template codegen pattern (HeroLifecycle + new OschemaBuildConfig)". Reference this comment for the assessment.
  2. Gate it on tier-3 of META #262 — specifically hero_rpc#54 (extend scaffolder), hero_rpc#55 (codegen alignment + hero_lifecycle rename + hero_rpc2 vendor), hero_rpc#56 (modularize generator). Doing the work before those land means iterating against a moving target; doing it after means a single clean PR onto a stable target with the hero_service template as the reference.
  3. Use this audit's PR #42 + the §2 cleanups (B1, B2, B7, B10) as the prerequisite tidy so the migration PR is purely about the codegen path, not mixed with naming/CI/lint cleanups.
  4. Do NOT wait for the full hero_rpc2 trait-macro vendoring (the half of META that owns #[rpc(server, client)]). That's a separate follow-up after hero_logic lands on the upgraded hero_rpc first; trying to do both in one migration triples the surface area.

The hand-rolled LogicRpcClient deletion alone makes this worth doing eventually — every new admin route currently has to choose between "typed SDK call" and "raw rpc_call JSON wrangling," and the choice depends on which methods the SDK happens to expose typed wrappers for. That's exactly the kind of split the upgraded codegen erases.

Out of scope for #41: actually doing any of the above. This comment is the assessment the acceptance asked for.

## §3 — OSchema / upgraded `hero_rpc` migration assessment (read-only) ### TL;DR **Viable, low-risk, but not urgent. Recommend opening as its own follow-up issue and timing it for *after* `hero_rpc#54/55/56` land** so we migrate onto a settled target rather than a moving one. The framing in the issue body — *"hero_logic currently uses traditional hand-rolled SDK + hand-written OpenRPC + Axum + Askama"* — is partly outdated. hero_logic is already on the OSchema codegen path; it's the *older* version of it. The "migration" is really an upgrade from the old codegen API to the new one, not a wholesale rewrite. --- ### What hero_logic already has on the codegen side | Layer | Today | Source | |---|---|---| | Types | OSchema-generated (`types_generated.rs`, `types.rs` for hand impls) | `crates/hero_logic_server/build.rs` via `OschemaBuildConfig::new().domain("logic", …).generate_server().nested_layout()` | | OSIS storage layer | OSchema-generated (`osis_server_generated.rs`) | same build.rs | | RPC handlers (CRUD) | OSchema-generated (`rpc_generated.rs`) | same build.rs | | RPC handlers (business logic) | Hand-written (`rpc.rs`) | 21 of the 57 methods (`logicservice.*`) | | OpenRPC spec | OSchema-generated (`specs/openrpc.json`) | same build.rs | | Rust SDK client | Generated from openrpc.json via `hero_rpc_derive::openrpc_client!` macro | `crates/hero_logic_sdk/src/lib.rs` | | Admin RPC client | **Two clients side-by-side** — typed `LogicServiceClient` for declared methods, hand-rolled `LogicRpcClient` for auto-generated OSIS CRUD (`workflow.list`, `play.list`, etc.) the SDK doesn't expose typed wrappers for | `crates/hero_logic_admin/src/{main,rpc_client}.rs` | So hero_logic is sitting on roughly the codegen state hero_service@`518448c` (the canonical template) is on. The "hand-rolled" footprint that would shrink in a migration is small and well-located. ### What's *actually* different in the upgraded path (per hero_service template + META #262) Comparing `hero_service@518448c` (canonical template) and `hero_logic@main`: 1. **`OschemaBuildConfig` gains new fields** that hero_logic doesn't use yet: `sdk_dir`, `client_crate_dir`, `server_crate_dir`, `server_types_crate`, `sdk_types_crate`, `with_wasm()`. The hero_service config splits types so a shared `hero_service` crate holds them, consumed by both `hero_service_server` and `hero_service_sdk`. Today hero_logic's types live duplicated in `crates/hero_logic_server/src/logic/core/types_generated.rs` (server) and would also appear in `crates/hero_logic_sdk/` if the SDK ever needed them. This is the main structural change. 2. **Server bootstrap moves to `HeroLifecycle` + `OServer::run_cli`**. hero_service template: ```rust let lifecycle = HeroLifecycle::new("hero_service_server", repo_url, "hero_service_server") .description("…"); OServer::run_cli(lifecycle, |server, contexts, _seed_dir, _seed_domains| async move { server.register::<OsisCatalog>(ctx, "catalog").await?; Ok(()) }).await ``` vs hero_logic today: ```rust let config = OServerConfig::new().name(SERVICE_NAME).description(DESCRIPTION); let server = OServer::new(config).await?; server.register::<OsisLogic>("root", "logic").await?; server.run().await ``` `HeroLifecycle` plugs into the renamed `hero_lifecycle` crate (was `hero_service` per hero_rpc#55). 3. **Codegen emits the typed CRUD wrappers** that today hero_logic_admin's hand-rolled `LogicRpcClient` exists to paper over. Once those wrappers land, the entire `rpc_client.rs` (28 lines) and the comment in `AppState::sdk()` ("Raw transport — keep for the auto-generated OSIS CRUD whose typed wrappers don't live in the SDK yet") go away. 4. **JS / Rhai / Python SDK targets** join the Rust SDK. hero_logic already commits `crates/hero_logic_server/sdk/{js,python}/` — looks like an in-progress version of this already. 5. **`with_wasm()` adds the WASM-compatible type variants** (`types_wasm_generated.rs` in hero_service template). 6. **hero_rpc2** (the second half of META's "hybrid hero_rpc + hero_rpc2" decision) is **not** part of this yet. hero_rpc#55 covers vendoring it. hero_service template doesn't use it either. So "migrate to upgraded hero_rpc" today does NOT mean "migrate to `#[rpc(server, client)]` macros" — that's a tier-after-tier follow-up. ### What does NOT migrate These stay untouched regardless of codegen path: - `engine/` (Python executor, DAG runner) — pure domain code. - `seed.rs` + `seed_flows/` — built-in flow definitions. - `tracing_layer.rs` — `HeroTracingLayer` wires `tracing` into the Hero file logger. - `services/` — auxiliary handlers. - `crates/hero_logic_admin/templates/` (Askama) + 1719-line `routes.rs` — admin UI lives here, codegen doesn't touch it. - `crates/hero_logic/src/main.rs` — CLI clap tree, hand-written, *calls* the generated SDK but doesn't get generated itself. - The 21 hand-written `logicservice.*` methods (Python execution, span pushes, play lifecycle) — these have business logic OSchema CRUD wouldn't capture. So the migration footprint is roughly: `build.rs` + `src/main.rs` of the server + reorganizing where generated types live + deleting `admin/src/rpc_client.rs`. Maybe ~300 LOC delta, plus path-dep adjustments. ### What could block the migration I looked for these specifically since the issue asked. Net: nothing fundamental. | Concern | Verdict | |---|---| | Custom serialization (non-standard serde, binary formats) | None. All types are vanilla derive `Serialize`/`Deserialize` over JSON. | | Streaming or long-lived bidirectional RPC | None. All 57 methods are request/response. `service.toml` has `sse = false` everywhere. | | Unusual type shapes (recursive, generic, trait objects across RPC boundary) | None spotted. Types are flat structs, vecs of structs, enums-as-string. The `python_source` b64-prefix encoding is handled in client code (`hero_logic_sdk::decode_python_source`), not in serde. | | OServer features hero_logic depends on that the new path doesn't have | `inspector` feature (HTML at `GET /` on rpc.sock) — but flagged in §2 audit as redundant since admin exists. Drop, don't migrate. | | Context routing (X-Hero-Context header → typed `HeroRequestContext`) | Not currently used by hero_logic. Would gain from migration but doesn't block. | | Custom Axum middleware on the rpc.sock | None — `OServer::run` does its own routing. | The one *non*-blocker but quirk worth noting: hero_logic's `python_source` field carries an optional `b64:` prefix because Python source with mixed newlines/quotes is annoying to round-trip cleanly through JSON. The decoder lives in `hero_logic_sdk::decode_python_source`. After migration this would need to remain a hand-written helper in the SDK (codegen won't infer it) — fine, but worth knowing the helper has to be preserved. ### Cost estimate | Phase | Effort | Notes | |---|---|---| | build.rs upgrade to new `OschemaBuildConfig` fields | 1–2 hours | Mostly copy from hero_service template + adjust paths | | Server `main.rs` → `HeroLifecycle::run_cli` pattern | 2–4 hours | Adopt closure pattern; thread the seed-flow spawn through it | | Reorganize types into shared `hero_logic` types crate (if we follow hero_service template's split) | 4–8 hours | Touches imports across `_server`, `_sdk`, `_admin` | | Delete `admin/src/rpc_client.rs` + switch admin to typed wrappers everywhere | 2–4 hours | Depends on codegen emitting wrappers for `workflow.list`, `play.list`, `example.list` (currently the SDK gap) | | Adopt JS / Rhai / Python SDK targets in `sdk_dir` | 0–2 hours | Already partially committed; mostly config | | Validate end-to-end: full smoke + admin clicks | 2 hours | Existing tests should still pass | Total: **roughly 1–2 days of focused work**, single person. Reversible if anything blows up — the OschemaBuildConfig changes are additive and the runtime change is one main.rs. ### Recommendation 1. **Open as its own follow-up issue against `hero_logic`**, titled something like *"Upgrade to hero_service template codegen pattern (HeroLifecycle + new OschemaBuildConfig)"*. Reference this comment for the assessment. 2. **Gate it on tier-3 of META #262** — specifically `hero_rpc#54` (extend scaffolder), `hero_rpc#55` (codegen alignment + `hero_lifecycle` rename + hero_rpc2 vendor), `hero_rpc#56` (modularize generator). Doing the work before those land means iterating against a moving target; doing it after means a single clean PR onto a stable target with the hero_service template as the reference. 3. **Use this audit's PR #42 + the §2 cleanups (B1, B2, B7, B10) as the prerequisite tidy** so the migration PR is purely about the codegen path, not mixed with naming/CI/lint cleanups. 4. **Do NOT** wait for the full hero_rpc2 trait-macro vendoring (the half of META that owns `#[rpc(server, client)]`). That's a separate follow-up after hero_logic lands on the upgraded `hero_rpc` first; trying to do both in one migration triples the surface area. The hand-rolled `LogicRpcClient` deletion alone makes this worth doing eventually — every new admin route currently has to choose between "typed SDK call" and "raw `rpc_call` JSON wrangling," and the choice depends on which methods the SDK happens to expose typed wrappers for. That's exactly the kind of split the upgraded codegen erases. **Out of scope for #41**: actually doing any of the above. This comment is the assessment the acceptance asked for.
Author
Owner

Closing — audit complete.

§1 fixes landed directly on main (commits 8f51afd, 8d035e4, 6499aac). PR #42 superseded by the direct merge.

§2 divergences broken out into:

  • hero_logic#43 — bundled cleanup (B1, B2, B4, B5, B7, B8, B10)
  • hero_skills#271 — add hero_logic to SERVICE_MAP (B3)
  • B6 (examples crate) deferred — low priority

§1 framework gaps filed:

  • hero_rpc#80 — OServer should register system.ping builtin
  • hero_skills#272 — document lab user init PATH_ROOT prerequisite (hero_proc#109 covers managed-daemon case)

§3 OSchema upgrade filed as hero_logic#44. Now unblocked from the hero_rpc side; do after #43 cleanup lands.

Closing — audit complete. **§1 fixes** landed directly on `main` (commits `8f51afd`, `8d035e4`, `6499aac`). PR #42 superseded by the direct merge. **§2 divergences** broken out into: - [hero_logic#43](https://forge.ourworld.tf/lhumina_code/hero_logic/issues/43) — bundled cleanup (B1, B2, B4, B5, B7, B8, B10) - [hero_skills#271](https://forge.ourworld.tf/lhumina_code/hero_skills/issues/271) — add hero_logic to SERVICE_MAP (B3) - B6 (examples crate) deferred — low priority **§1 framework gaps** filed: - [hero_rpc#80](https://forge.ourworld.tf/lhumina_code/hero_rpc/issues/80) — OServer should register `system.ping` builtin - [hero_skills#272](https://forge.ourworld.tf/lhumina_code/hero_skills/issues/272) — document `lab user init` PATH_ROOT prerequisite (hero_proc#109 covers managed-daemon case) **§3 OSchema upgrade** filed as [hero_logic#44](https://forge.ourworld.tf/lhumina_code/hero_logic/issues/44). Now unblocked from the hero_rpc side; do after #43 cleanup lands.
timur closed this issue 2026-05-20 05:57:02 +00:00
Sign in to join this conversation.
No labels
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_logic#41
No description provided.