lab publish CI broken: openrpc_client! rejects {str: any} inputs from #140 (Rule 2) #142

Closed
opened 2026-06-08 15:43:13 +00:00 by mahmoud · 1 comment
Owner

Summary

After merging #140 (feat(jobs): restore typed inputs end-to-end) into development, the lab publish CI fails to build. lab depends on hero_proc_sdk as a git dependency, and the SDK's openrpc_client! macro now rejects the schema introduced by #140:

error: proc macro panicked
  --> crates/hero_proc_sdk/src/openrpc_client/mod.rs:22:1
   = help: message: Schema::to_openrpc: schema violates the method-input contract:
     - type `JobCreate` uses the `any` type, which is forbidden ... See /openrpc_principles, Rule 2.
     - type `RunSpec` uses the `any` type, which is forbidden ... See /openrpc_principles, Rule 2.

This cascades into ~9 E0432 unresolved-import errors (HeroProcClient_, JobCreate, RunSpec, Action, etc.) because codegen aborts, and the whole hero_proc_sdk lib fails to compile — breaking every downstream consumer (lab, admin, examples).

Root cause

#140 modeled per-invocation typed inputs as a free-form map using the any value type, in two oschema types:

  • crates/hero_proc_server/oschema/jobs/40_run.oschemaRunSpec.inputs: {str: any}
  • crates/hero_proc_server/oschema/jobs/30_job.oschemaJobCreate.inputs: {str: any}

{str: any} generates HashMap<String, serde_json::Value>. The openrpc_server! codegen tolerated this, so #140 built and tested green locally against the server, but the openrpc_client! codegen enforces openrpc principles Rule 2, which forbids any entirely (no constructor, no typed accessors, no compile-time check). The enforcement was tightened (see stopgap/openrpc-enforcement-b1), so the client-side build that lab performs now hard-fails.

Fix

Re-model inputs without any, using the existing in-repo precedent: Action.input_schema is already a str holding a JSON document (a JSON Schema). Model inputs the same way — a str holding a JSON object — instead of {str: any}:

  • RunSpec.inputs: str — JSON object string of per-invocation typed values; "" = none
  • JobCreate.inputs: str — JSON object string; "" = none

This preserves all documented §1.5 behavior with zero engine changes: the server parses the string into a serde_json::Value and feeds the unchanged apply_inputs/template.rs engine, so {{var}}/{{nested.path}} traversal, natural number/bool rendering, and HERO_INPUT_<UPPER> injection all keep working. The typed SDK builder API (.input(k, v: impl Into<serde_json::Value>) / .inputs(map)) is unchanged — the SDK serializes the map to a JSON string at the wire boundary.

Scope of changes

  • oschema: 2 fields {str: any} -> str (the only two any usages in the tree).
  • Regenerate crates/hero_proc_server/openrpc/openrpc_jobs.json.
  • Server jobs_impl.rs: parse req.inputs/spec.inputs JSON string -> Value (was to_value).
  • SDK factory.rs / builders.rs: serialize the builder's input map -> JSON string when constructing RunSpec/JobCreate.
  • Tests / examples: pass inputs as a JSON string literal.

Acceptance criteria

  • hero_proc_sdk compiles (both openrpc_server! and openrpc_client! codegen pass — no Rule 2 violation).
  • lab builds against the SDK git dependency (CI publish job green).
  • Typed inputs still render {{var}}/{{nested.path}}; numbers/bools render naturally; unresolved placeholders stay literal.
  • HERO_INPUT_<UPPER> still injected for non-ai interpreters.
  • input_schema still persists and round-trips.
  • No-inputs path unchanged (empty string short-circuits).
  • cargo build + cargo clippy -D warnings clean for the feature crates.

Notes

  • Regression from #140; development HEAD 14ee3ea is affected.
  • No behavior change intended versus #140 other than the wire encoding of inputs (map -> JSON string), which is invisible through the SDK builder API.
## Summary After merging #140 (`feat(jobs): restore typed inputs end-to-end`) into `development`, the **lab publish CI fails to build**. `lab` depends on `hero_proc_sdk` as a git dependency, and the SDK's `openrpc_client!` macro now rejects the schema introduced by #140: ``` error: proc macro panicked --> crates/hero_proc_sdk/src/openrpc_client/mod.rs:22:1 = help: message: Schema::to_openrpc: schema violates the method-input contract: - type `JobCreate` uses the `any` type, which is forbidden ... See /openrpc_principles, Rule 2. - type `RunSpec` uses the `any` type, which is forbidden ... See /openrpc_principles, Rule 2. ``` This cascades into ~9 `E0432` unresolved-import errors (`HeroProcClient_`, `JobCreate`, `RunSpec`, `Action`, etc.) because codegen aborts, and the whole `hero_proc_sdk` lib fails to compile — breaking every downstream consumer (`lab`, admin, examples). ## Root cause #140 modeled per-invocation typed inputs as a free-form map using the `any` value type, in two oschema types: - `crates/hero_proc_server/oschema/jobs/40_run.oschema` — `RunSpec.inputs: {str: any}` - `crates/hero_proc_server/oschema/jobs/30_job.oschema` — `JobCreate.inputs: {str: any}` `{str: any}` generates `HashMap<String, serde_json::Value>`. The `openrpc_server!` codegen tolerated this, so #140 built and tested green locally against the server, but the **`openrpc_client!` codegen enforces openrpc principles Rule 2**, which forbids `any` entirely (no constructor, no typed accessors, no compile-time check). The enforcement was tightened (see `stopgap/openrpc-enforcement-b1`), so the client-side build that `lab` performs now hard-fails. ## Fix Re-model `inputs` without `any`, **using the existing in-repo precedent**: `Action.input_schema` is already a `str` holding a JSON document (a JSON Schema). Model `inputs` the same way — a `str` holding a JSON object — instead of `{str: any}`: - `RunSpec.inputs: str` — JSON object string of per-invocation typed values; `""` = none - `JobCreate.inputs: str` — JSON object string; `""` = none This preserves **all** documented §1.5 behavior with zero engine changes: the server parses the string into a `serde_json::Value` and feeds the unchanged `apply_inputs`/`template.rs` engine, so `{{var}}`/`{{nested.path}}` traversal, natural number/bool rendering, and `HERO_INPUT_<UPPER>` injection all keep working. The typed SDK builder API (`.input(k, v: impl Into<serde_json::Value>)` / `.inputs(map)`) is unchanged — the SDK serializes the map to a JSON string at the wire boundary. ## Scope of changes - oschema: 2 fields `{str: any}` -> `str` (the only two `any` usages in the tree). - Regenerate `crates/hero_proc_server/openrpc/openrpc_jobs.json`. - Server `jobs_impl.rs`: parse `req.inputs`/`spec.inputs` JSON string -> `Value` (was `to_value`). - SDK `factory.rs` / `builders.rs`: serialize the builder's input map -> JSON string when constructing `RunSpec`/`JobCreate`. - Tests / examples: pass `inputs` as a JSON string literal. ## Acceptance criteria - [ ] `hero_proc_sdk` compiles (both `openrpc_server!` and `openrpc_client!` codegen pass — no Rule 2 violation). - [ ] `lab` builds against the SDK git dependency (CI publish job green). - [ ] Typed inputs still render `{{var}}`/`{{nested.path}}`; numbers/bools render naturally; unresolved placeholders stay literal. - [ ] `HERO_INPUT_<UPPER>` still injected for non-ai interpreters. - [ ] `input_schema` still persists and round-trips. - [ ] No-inputs path unchanged (empty string short-circuits). - [ ] `cargo build` + `cargo clippy -D warnings` clean for the feature crates. ## Notes - Regression from #140; `development` HEAD `14ee3ea` is affected. - No behavior change intended versus #140 other than the wire encoding of `inputs` (map -> JSON string), which is invisible through the SDK builder API.
Author
Owner

Already mentioned in #143

Already mentioned in https://forge.ourworld.tf/lhumina_code/hero_proc/issues/143
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_proc#142
No description provided.