lab service --start --ephemeral leaks PATH_VAR/PATH_BUILD/PATH_CODE into the child + acquire chatter pollutes --json stdout #299

Open
opened 2026-05-25 10:29:10 +00:00 by timur · 0 comments
Owner

Context

lab service <name> --start --ephemeral --json overrides PATH_ROOT on the spawned child (so hero_var_dir() → scratch) but leaves PATH_VAR / PATH_BUILD / PATH_CODE inherited from the parent. herolib_core::base::path_var() checks PATH_VAR first and only falls back to $PATH_ROOT/var, so resolve_socket_dir() resolves to $HOME/hero/var/sockets — the shared path — even though OSIS storage correctly lands under scratch.

Result: the child happily binds $HOME/hero/var/sockets/<svc>/rpc.sock while lab waits for <scratch>/var/sockets/<svc>/rpc.sock, hits the 5s deadline, and bails with stderr tail: <empty> (the banner that would reveal the mismatch only ever lands in stdout.log, which lab doesn't surface).

Reproducible by following the post-#138 / hero_service#12 E2E flow on a contributor box that exports PATH_VAR=$HOME/hero/var (the canonical lab user init setup):

cd hero_service
PATH=$HOME/.local/bin:$PATH \
  PATH_ROOT=$HOME/hero PATH_VAR=$HOME/hero/var \
  PATH_BUILD=$HOME/hero/build PATH_CODE=$HOME/hero/code \
  cargo test --workspace --test greeter_e2e -- --test-threads=1

Each test panics with ephemeral socket <scratch>/var/sockets/hero_service/rpc.sock did not come up within 5s.

A second, smaller bug compounds the first: acquire_binary writes its using installed … / installed from Forge → … progress lines to stdout, so even when the spawn succeeds the JSON envelope lab --json emits is preceded by chatter — serde_json::from_slice on the test driver side rejects it.

Goals

  • crates/lab/src/service/ephemeral.rs::spawn_inner clears PATH_VAR / PATH_BUILD / PATH_CODE (alongside the existing HERO_SOCKET_DIR / INTEGRATIONTEST removal) so the child's path resolvers honour the single PATH_ROOT pivot.
  • Spawn-timeout failure messages tail both stdout.log and stderr.log (the startup banner that fingerprints env-pivot bugs lives in stdout).
  • acquire_binary's progress chatter (using installed, installed from Forge) routes to stderr so --json stdout stays a single line.
  • cargo test --workspace --test greeter_e2e (hero_service @ fe8c78ad) goes 5/5 green on a stock contributor environment.
## Context `lab service <name> --start --ephemeral --json` overrides `PATH_ROOT` on the spawned child (so `hero_var_dir()` → scratch) but leaves `PATH_VAR` / `PATH_BUILD` / `PATH_CODE` inherited from the parent. `herolib_core::base::path_var()` checks `PATH_VAR` *first* and only falls back to `$PATH_ROOT/var`, so `resolve_socket_dir()` resolves to `$HOME/hero/var/sockets` — the shared path — even though OSIS storage correctly lands under scratch. Result: the child happily binds `$HOME/hero/var/sockets/<svc>/rpc.sock` while lab waits for `<scratch>/var/sockets/<svc>/rpc.sock`, hits the 5s deadline, and bails with `stderr tail: <empty>` (the banner that would reveal the mismatch only ever lands in `stdout.log`, which lab doesn't surface). Reproducible by following the post-#138 / hero_service#12 E2E flow on a contributor box that exports `PATH_VAR=$HOME/hero/var` (the canonical `lab user init` setup): ``` cd hero_service PATH=$HOME/.local/bin:$PATH \ PATH_ROOT=$HOME/hero PATH_VAR=$HOME/hero/var \ PATH_BUILD=$HOME/hero/build PATH_CODE=$HOME/hero/code \ cargo test --workspace --test greeter_e2e -- --test-threads=1 ``` Each test panics with `ephemeral socket <scratch>/var/sockets/hero_service/rpc.sock did not come up within 5s`. A second, smaller bug compounds the first: `acquire_binary` writes its ` using installed …` / ` installed from Forge → …` progress lines to **stdout**, so even when the spawn succeeds the JSON envelope `lab --json` emits is preceded by chatter — `serde_json::from_slice` on the test driver side rejects it. ## Goals - `crates/lab/src/service/ephemeral.rs::spawn_inner` clears `PATH_VAR` / `PATH_BUILD` / `PATH_CODE` (alongside the existing `HERO_SOCKET_DIR` / `INTEGRATIONTEST` removal) so the child's path resolvers honour the single `PATH_ROOT` pivot. - Spawn-timeout failure messages tail **both** `stdout.log` and `stderr.log` (the startup banner that fingerprints env-pivot bugs lives in stdout). - `acquire_binary`'s progress chatter (`using installed`, `installed from Forge`) routes to stderr so `--json` stdout stays a single line. - `cargo test --workspace --test greeter_e2e` (hero_service @ `fe8c78ad`) goes 5/5 green on a stock contributor environment.
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_skills#299
No description provided.