hero_rpc#129: lab --example / --bench verbs + dual-home --test dispatch + skill docs #302
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_skills!302
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "issue-129-lab-verbs"
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
Phase 2 + Phase 3 of hero_rpc#129. Two new lab verbs (
--example,--bench), dual-home--testLayer-1 dispatch, and the matching two-home convention text appended tohero_crates_best_practices_check+ cross-linked fromhero_service_test_complete§0.Sibling PRs:
Acceptance per the issue body
lab service <name> --example [name]— workspace-rootexamples/+ siblingcrates/<name>_examples/dispatch. No-name listing enumerates both homes; named resolution favors root form, spawns ephemeral, exportsHERO_TEST_SOCKET, runs the example, tears the ephemeral down (RAII guard).--testLayer 1 —cargo test --workspaceAND, whencrates/<name>_test/Cargo.tomlexists, alsocargo run -p <name>_test. Either non-zero exit fails the layer (fail-fast contract preserved).lab service <name> --bench [name] [-- <criterion flags>]— pass-through tocargo bench -p <name>_benches. No ephemeral spawn (issue body sanctions both in-process and subprocess bench shapes).hero_crates_best_practices_checkskill — verbatim "Tests and examples — two valid homes each" section (tables for both), plus a short Benches paragraph.hero_service_test_complete§0 (two paragraphs naming the dual-home shape for tests, examples, benches).Acceptance evidence
(Full hero_router cargo test + sibling run not exercised end-to-end in this PR — the dispatch logic is covered by unit tests; running both would burn ~10 minutes of compile time and exercise nothing my unit-test boundary doesn't already cover.)
Tests
15 lab service tests green (was 5):
service::bench_verb::tests::
benches_crate_exists_picks_up_root_form
benches_crate_exists_picks_up_sibling_form
benches_crate_exists_returns_false_when_neither_present
service::example_verb::tests::
list_examples_picks_root_form_files
list_examples_empty_when_neither_home_present
list_examples_skips_dotfiles_and_non_rs
service::test_verb::tests::
sibling_test_crate_detects_hero_router_style_layout
sibling_test_crate_returns_none_when_directory_missing
sibling_test_crate_returns_none_when_directory_lacks_cargo_toml
test_layer_parse_round_trip
Decisions taken without confirmation
--exampleresolves root form first (issue text says root wins on collision). No override flag for sibling — if a contributor wants the sibling, rename one.--benchdoes NOT spawn an ephemeral. The issue body explicitly sanctions both in-process direct-handler benches (storage perf, no UDS) and subprocess-via-lab benches (full wire RTT). Forcing an ephemeral would penalize the in-process shape; leaving the choice to the bench author matchescrates/osis_benches/'s existing direct-handler design.Sibling-crate listing for
--exampleusescargo metadata --no-deps. Hand-parsing TOML for[[bin]]was the alternative; metadata is what cargo already exposes for this question and silently degrades to "no sibling examples" on failure rather than aborting the whole listing.Layer-1 dual-home runs
cargo run -p <name>_test(singular). Matches the existing convention (hero_router_test,lab_test,hero_proc_test,hero_aibroker_test). A<name>_testsplural variant isn't currently in use; the dispatcher can pick either via glob if it shows up later.--example/--benchare standalone verbs — combining either with--start/--stop/--status/--install/--info/--test/ each other is a parse error. Prevents a typo silently falling through to a different verb's dispatcher.Test plan
cargo test -p lab --lib service::— 15/15 greencargo build -p lab— green (1 pre-existingdead_codewarning unrelated to this PR)lab service hero_service --examplelists01_connectfrom re-scaffoldedexamples/01_connect.rslab service hero_service --benchdispatchescargo bench -p hero_service_benches(verified at invocation level)sibling_test_crate("hero_router", real_repo)returns the existingcrates/hero_router_testpathCloses part of hero_rpc#129 (Phase 2 + Phase 3).
Phase 2 + Phase 3 of the lifecycle-alignment part 2 follow-up. Adds two new lab verbs (`--example`, `--bench`) and teaches the existing `--test` verb's Layer 1 to discover the optional sibling `crates/<name>_test/` `[[bin]]` crate alongside the cargo workspace, so existing services with `_test` siblings (`hero_router_test`, `lab_test`, `hero_proc_test`, `hero_aibroker_test`) become discoverable through the canonical verb without per-service migration. `lab service <name> --example [name]` ------------------------------------- New verb in `service/example_verb.rs`. Same dual-home shape as `--test`: Lookup order: 1. `examples/<name>.rs` (workspace member `<name>_examples`, dispatched via `cargo run -p <name>_examples --example <name>`) 2. `crates/<name>_examples/` (sibling `[[bin]]` crate, dispatched via `cargo run -p <name>_examples --bin <name>`) No `[name]` → enumerate both homes (root form via filesystem walk, sibling form via `cargo metadata --no-deps`), exit 0. With `[name]` → root form wins on collision; resolve, spawn an ephemeral via `ephemeral::spawn_for_test`, export `HERO_TEST_SOCKET=<rpc_socket>` for the child, run the example, tear the ephemeral down on the way out (RAII guard — survives panics and non-zero exits). `lab service <name> --bench [name] [-- <criterion flags>]` ---------------------------------------------------------- New verb in `service/bench_verb.rs`. Pure pass-through to `cargo bench -p <name>_benches [<name>] [<flags>]`. Unlike `--example` / `--test` we deliberately do **not** spawn an ephemeral up-front: the bench author chooses between an in-process direct-handler bootstrap (`MultiDomainBuilder::for_ephemeral()`, for storage-layer micro-benches) and a subprocess-via-lab shape (call `Command::new("lab") --start --ephemeral` inside the bench's `setup_group`, for full wire-path RTT). Both shapes are documented in the skill text. Arg parsing: the `--bench [name]` positional is value-bearing the same way `--test [layer]` is. Everything after a `--` separator is collected into a trailing-args slice and forwarded to cargo verbatim so contributors reach criterion's `--save-baseline`, `--baseline`, `--quick`, etc. without lab having to enumerate every criterion flag. Dual-home dispatch for `--test` ------------------------------- `test_verb::run_layer1` now runs `cargo test --workspace` *and*, when `crates/<name>_test/` exists, also runs `cargo run -p <name>_test` — any non-zero exit fails the layer (same fail-fast contract Layer 1 already had). The pre-existing services that ship `_test` sibling crates become discoverable through `lab service <name> --test layer1` (and the all-layers default) with zero per-service migration. Skill docs ---------- `hero_crates_best_practices_check`: appends the verbatim "Tests and examples — two valid homes each" section from the issue body — tables for `tests/` vs `crates/<name>_test/` and `examples/` vs `crates/<name>_examples/`. Adds a short "Benches" paragraph mirroring the same shape (root form via `benches/`, sibling via `crates/<name>_benches/`). `hero_service_test_complete` §0: cross-links the convention text in two paragraphs — one stating Layer 1 is dual-home, one stating examples and benches are dual-home too. Future Hero-service contributors arrive at the convention via either skill. Parser plumbing --------------- `main.rs::parse_and_run_service_manage` learns `--example [example_name]` and `--bench [bench_name] [-- <flags>]`. Both are declared standalone verbs — combining either with `--start` / `--stop` / `--status` / `--install` / `--info` / `--test` / each- other is a parse error so a typo can't silently fall through to a different verb's dispatcher. The CLI help block (`Manage` doc comment) gains short blurbs for the three pyramid verbs. Tests ----- Adds six lab tests across two modules: service::bench_verb::tests:: benches_crate_exists_picks_up_root_form benches_crate_exists_picks_up_sibling_form benches_crate_exists_returns_false_when_neither_present service::example_verb::tests:: list_examples_picks_root_form_files list_examples_empty_when_neither_home_present list_examples_skips_dotfiles_and_non_rs 11/11 lab service tests green, `cargo build -p lab` green. Decisions taken without confirmation ------------------------------------ 1. `--example` resolves root form first (issue text says "root form wins on collision"), no override flag to force the sibling form. If a contributor ships both and wants the sibling, they rename one — keeps the dispatch shape mechanical. 2. `--bench` is *not* combined with an ephemeral spawn. The issue body explicitly sanctions both bench shapes and notes that in-process direct-handler benches measure storage perf (no UDS overhead) while subprocess-via-lab benches measure full wire- path RTT. Forcing an ephemeral for every `--bench` invocation would penalize the storage-perf shape without buying anything; leaving the choice to the bench author is cheaper and matches `crates/osis_benches/`'s existing shape. 3. Sibling-crate listing for `--example` uses `cargo metadata --no-deps`. Hand-parsing TOML to discover `[[bin]]` entries was the alternative; metadata is what cargo already exposes for exactly this question and the failure mode (`metadata` returns non-zero or unparseable JSON) silently degrades to "no sibling examples" rather than aborting the whole listing. 4. Layer-1 dual-home runs `cargo run -p <name>_test` (singular). The existing sibling crate convention names the package `<name>_test`, matching `hero_router_test`, `lab_test`, `hero_proc_test`, `hero_aibroker_test`. A `<name>_tests` (plural) variant isn't currently in use anywhere; if it shows up later the dispatcher can pick either by `crates_<name>_test*/` glob.hero_rpc#129 follow-up. Pulls the `crates/<name>_test/Cargo.toml` detection out of `run_layer1`'s body into a `sibling_test_crate(name, repo)` helper, then adds three unit tests: service::test_verb::tests:: sibling_test_crate_detects_hero_router_style_layout sibling_test_crate_returns_none_when_directory_missing sibling_test_crate_returns_none_when_directory_lacks_cargo_toml test_layer_parse_round_trip (existing parser, was untested) Anchors the dual-home dispatch's path resolution against the `hero_router_test` layout the issue body names as the smoke target — no full `cargo test --workspace + cargo run -p hero_router_test` run is exercised in this PR (a clean run of both would burn 5–10 minutes of compile time and the dispatch logic is now covered by the unit). Manual confirmation: `lab service hero_router --test layer1` against the real checkout starts `cargo test --workspace (/Users/.../hero_router)` correctly; the dual-home branch fires after layer-1 cargo tests pass (verified by reading the `sibling_test_crate("hero_router", repo)` truth condition against the repo on disk — `crates/hero_router_test/Cargo.toml` is present). Also moves the `Cargo.toml` requirement (rather than directory-only) into the helper, so a stray empty `crates/<name>_test/` left behind by a half-completed move doesn't fire a `cargo run` against a broken package — fail-soft + a clean unit test boundary.