fix: terminate cleanly on a broken stdout pipe across all family-emitting commands
GREEN for the broken-pipe RED test (c750b9f). Rust's runtime sets SIGPIPE to
SIG_IGN at startup, so a println! to a closed stdout pipe returned EPIPE and
panicked ("failed printing to stdout: Broken pipe", exit 101). Restore the
default SIGPIPE disposition once at the top of main() (cfg(unix), via
libc::signal) so a closed pipe terminates the process cleanly on SIGPIPE
(signal 13 / exit 141 — the conventional Unix CLI outcome, e.g. `yes | head`)
instead of panicking. One process-level reset covers every family-emitting
subcommand (sweep / mc / walkforward / runs family / generalize); the print
sites are untouched (minimal fix).
libc added as a direct aura-cli dependency — already transitive in Cargo.lock,
the standard vetted crate for signal disposition, admitted under the per-case
dependency policy.
Verified by the orchestrator: the broken-pipe test passes 6/6; `aura sweep | head`
exits 141 with no panic in stderr; cargo test --workspace green (0 failed);
clippy --workspace --all-targets -D warnings clean.
refs #146
This commit is contained in:
Generated
+1
@@ -57,6 +57,7 @@ dependencies = [
|
||||
"aura-registry",
|
||||
"aura-std",
|
||||
"data-server",
|
||||
"libc",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
@@ -29,3 +29,9 @@ serde = { workspace = true }
|
||||
# and the injected chart traces (window.AURA_TRACES);
|
||||
# admitted under the per-case dependency policy, same as aura-engine.
|
||||
serde_json = { workspace = true }
|
||||
# libc: restore the default SIGPIPE disposition at startup (see `fn main`) so a
|
||||
# closed stdout pipe (`aura sweep | head`, a closed UI pane) terminates the
|
||||
# process cleanly instead of panicking the runtime's SIG_IGN default into an
|
||||
# EPIPE. The standard vetted crate for signal disposition, already transitive in
|
||||
# Cargo.lock; admitted under the per-case dependency policy.
|
||||
libc = "0.2"
|
||||
|
||||
@@ -3082,6 +3082,15 @@ const USAGE: &str =
|
||||
"usage: aura run [--harness <sma|macd|stage1-r>] [--real <SYMBOL> [--from <ms>] [--to <ms>]] [--trace <name>] | aura chart <name> [--tap <t>] [--panels] | aura graph | aura sweep [--strategy <sma|momentum|stage1-r|stage1-breakout|stage1-meanrev>] [--real <SYMBOL> [--from <ms>] [--to <ms>]] [--name <n>|--trace <n>] | aura mc [--name <n>|--trace <n>] | aura mc --strategy stage1-r [--real <SYMBOL> [--from <ms>] [--to <ms>]] [--fast <csv>] [--slow <csv>] [--stop-length <csv>] [--stop-k <csv>] [--block-len <n>] [--resamples <n>] [--seed <n>] | aura walkforward [--strategy <sma|momentum|stage1-r|stage1-breakout|stage1-meanrev>] [--real <SYMBOL> [--from <ms>] [--to <ms>]] [--name <n>|--trace <n>] [--fast <csv>] [--slow <csv>] [--stop-length <csv>] [--stop-k <csv>] | aura generalize [--strategy stage1-r] --real <SYM1,SYM2,...> --fast <n> --slow <n> --stop-length <n> --stop-k <f> [--from <ms>] [--to <ms>] [--metric <r-metric>] [--name <n>] | aura runs families | aura runs family <id> [rank <metric>]";
|
||||
|
||||
fn main() {
|
||||
// Restore the default SIGPIPE disposition. Rust's runtime sets SIGPIPE to SIG_IGN
|
||||
// at startup, so a write to a closed stdout pipe (`aura sweep | head`, a closed UI
|
||||
// pane) returns EPIPE and panics in `println!` instead of terminating quietly on
|
||||
// SIGPIPE — the conventional Unix CLI behaviour. One reset covers every
|
||||
// family-emitting subcommand at once.
|
||||
#[cfg(unix)]
|
||||
unsafe {
|
||||
libc::signal(libc::SIGPIPE, libc::SIG_DFL);
|
||||
}
|
||||
// Collect argv and match the whole vector: every accepted form is exhaustive,
|
||||
// so an unexpected trailing token falls through to the usage-error path rather
|
||||
// than masquerading as a successful run (#16 strict reading).
|
||||
|
||||
Reference in New Issue
Block a user