fix(runner, campaign): contain synthetic member panics like the real path (GREEN)
The #272 containment recipe (SilencedPanic + catch_unwind + panic_message) is exposed from aura-campaign as catch_member_panic and applied at the bare-member seam in the synthetic family builders: blueprint_sweep_family contains per-point, resolves the lowest enumeration index's fault after the sweep joins (thread-order- independent, C1), and exits deliberately with the aura: warning: class marker + exit 3 (C14) instead of the raw panic/exit-101 escape; blueprint_sweep_over captures instead of exiting (it runs inside the per-window walkforward parallel closure — an on-the-spot exit would race across windows) and hands the resolved fault up. Fault prose reuses member_fault_prose; the real path's containment is untouched. Deliberate residue, both tracked: blueprint_mc_family's member call site keeps the bare run (empirical probe of the reachable surface follows this commit; a reachable escape goes the same RED-first way), and the new eprintln+exit(3) site in aura-runner joins the #297 process::exit inventory (noted there) rather than fighting M4's future RunnerError propagation now. Both RED e2es green; workspace suite green via the mini-verify; clippy -D warnings clean on the touched crates. refs #278
This commit is contained in:
@@ -830,6 +830,19 @@ fn panic_message(payload: Box<dyn std::any::Any + Send>) -> String {
|
||||
.unwrap_or_else(|| "member panicked (non-string payload)".to_string())
|
||||
}
|
||||
|
||||
/// The `SilencedPanic` + `catch_unwind` + `panic_message` recipe above
|
||||
/// (this module's three call sites), exposed for reuse by a member-run caller
|
||||
/// OUTSIDE this crate that drives a bare member run without going through
|
||||
/// `execute` (#278: the synthetic blueprint sweep/walk-forward family
|
||||
/// builders in `aura-runner`, which share this exact bare-member seam but
|
||||
/// carry no #272 fault boundary of their own). Returns the panic payload's
|
||||
/// best-effort message on containment; `AssertUnwindSafe` is the same
|
||||
/// judgement documented on `panic_message` above.
|
||||
pub fn catch_member_panic<R>(f: impl FnOnce() -> R) -> Result<R, String> {
|
||||
let _silence = SilencedPanic::enter();
|
||||
std::panic::catch_unwind(std::panic::AssertUnwindSafe(f)).map_err(panic_message)
|
||||
}
|
||||
|
||||
/// Assemble the (CellOutcome, CellRealization) pair for a cell that failed at a
|
||||
/// stage (#272): the realized stage prefix survives in `stages`, `families`/
|
||||
/// `selections` carry whatever already-persisted stages produced (empty for a
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
|
||||
mod exec;
|
||||
pub use exec::{
|
||||
execute, member_fault_prose, CampaignOutcome, CellOutcome, StageFamily, StageSelectionOut,
|
||||
catch_member_panic, execute, member_fault_prose, CampaignOutcome, CellOutcome, StageFamily,
|
||||
StageSelectionOut,
|
||||
};
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
Reference in New Issue
Block a user