Skip to content

fix(cli): preserve eval runtime failure stdout and exit codes#947

Merged
slepp merged 2 commits intomainfrom
eval/runtime-failure-output-contract
Apr 11, 2026
Merged

fix(cli): preserve eval runtime failure stdout and exit codes#947
slepp merged 2 commits intomainfrom
eval/runtime-failure-output-contract

Conversation

@slepp
Copy link
Copy Markdown
Contributor

@slepp slepp commented Apr 11, 2026

Summary

  • preserve pre-failure stdout and child exit codes for hew eval runtime failures
  • apply the same runtime-failure contract to --target wasm32-wasi so native and WASM paths stay aligned
  • add focused native and WASM eval e2e regressions for stdout preservation and exit-code propagation

Validation

  • cargo test -p hew-cli --test eval_e2e
  • cargo test -p hew-cli

slepp added 2 commits April 10, 2026 22:46
When a compiled Hew program exits non-zero during `hew eval`, any stdout
produced before the failure was silently discarded and `hew eval` always
exited 1 regardless of the child's actual exit code.

Changes:
- `process.rs`: Add `exit_code: i32` to `BinaryRunOutcome::Failed`;
  populated from `ExitStatus::code().unwrap_or(1)` at the wait site.
- `eval/repl.rs`: Add `RuntimeFailure { stdout, exit_code }` to both
  `CompiledEvalError` and `CliEvalError`.  `run_inprocess_compiled` now
  returns `RuntimeFailure` instead of swallowing stdout; child stderr is
  written directly to the parent's stderr at that layer.  All three
  `CompiledEvalError → CliEvalError` mapping sites and the interactive
  `handle_interactive_input` handler are updated exhaustively.
- `eval/mod.rs`: `exit_eval_error` handles `RuntimeFailure` by printing
  captured stdout then calling `std::process::exit(exit_code)` so the
  child's exit code is propagated rather than hard-coded to 1.
- `test_runner/runner.rs`: Exhaustive pattern update for the new field
  (`exit_code` is not used by the test runner; ignored with `..`).
- `tests/eval_e2e.rs`: Three focused regression tests covering (1) inline
  eval exit-code propagation, (2) file-mode exit-code propagation, and (3)
  file-mode pre-failure stdout preservation.
…ntract

The native eval path was fixed in the previous commit to preserve
pre-failure stdout and propagate the child exit code via
`RuntimeFailure`.  The WASM path (`hew eval --target wasm32-wasi`)
had the same bug: `WasiCapturedOutcome::Failed` carried only `stderr`
and mapped to `CompiledEvalError::Message`, so `exit_eval_error` took
the generic branch and always exited 1 while stdout was discarded.

Changes:
- `wasi_runner.rs`: Add `stdout: String` and `exit_code: i32` to
  `WasiCapturedOutcome::Failed`; `run_module_captured` now forwards them
  from the underlying `BinaryRunOutcome::Failed` fields (already present
  after the previous fix).
- `eval/repl.rs`: `run_wasm_eval_compiled` maps
  `WasiCapturedOutcome::Failed` to `CompiledEvalError::RuntimeFailure`
  (writing the module's stderr directly to parent stderr, identical to
  the native path), so the propagation chain through `CliEvalError` and
  `exit_eval_error` works for WASM without further changes.
- `tests/eval_e2e.rs`: Three focused WASM parity regressions mirroring
  the native tests: (1) inline WASM exit-code propagation, (2) file-mode
  WASM exit-code propagation, (3) file-mode WASM pre-failure stdout.
@slepp slepp merged commit 5cce17f into main Apr 11, 2026
13 checks passed
@slepp slepp deleted the eval/runtime-failure-output-contract branch April 11, 2026 05:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant