Merge main into the clap-adoption cycle — re-integrate the two parallel CLI fixes
main advanced with two `fix(cli)` commits (dec0780,6a775f7) landed by a parallel session while the clap adoption (cycles 0098/0099) was built from780d823. Both touch behaviour the clap migration rewrote or sits beside; this merge preserves them rather than letting the rewrite silently drop them: -dec0780(open-blueprint guard, #176): `aura run <open blueprint.json>` must refuse with a clean exit 2, never a `compile_with_params` arity panic (exit 101). The fix lived in the old hand-rolled `run` .json-arm, which the clap migration replaced — re-integrated into `dispatch_run`'s .json branch (the same `blueprint_axis_probe().param_space()` check + "closed blueprint" diagnostic). -6a775f7(walkforward axis-once, #177): axis validation hoisted to a single dispatch-boundary pre-flight, in the execution fn `blueprint_walkforward_family` — which the migration did not touch, so it auto-merged unchanged. Both fixes are verified by their own RED tests (`aura_run_rejects_an_open_blueprint_without_panicking`, `aura_walkforward_emits_an_unknown_axis_rejection_once`), and both are consistent with this cycle's iteration-2 exit-code classification: an open blueprint and an unknown axis are argument faults, so usage errors → exit 2. The conflict was confined to `fn main` in crates/aura-cli/src/main.rs (the clap `Cli::parse()` dispatch vs the old argv `match`); resolved to the clap side plus the re-integrated guard. cli_run.rs auto-merged (their two new tests + this cycle's renegotiated pins). Verified green (orchestrator, this session): cargo build --workspace, cargo clippy --workspace --all-targets -- -D warnings, and cargo test --workspace all clean.
This commit is contained in:
@@ -3002,9 +3002,25 @@ fn blueprint_walkforward_family(
|
||||
let space = blueprint_axis_probe(doc).param_space();
|
||||
let topo = topology_hash(&blueprint_from_json(doc, &|t| std_vocabulary(t))
|
||||
.expect("doc parse-validated at the dispatch boundary; reload is infallible"));
|
||||
// Validate the `--axis` grid ONCE at the dispatch boundary, mirroring `aura sweep`
|
||||
// (which resolves its axes a single time before any member runs). `walk_forward` fans
|
||||
// the per-window closure out across the windows in parallel, so a `BindError` raised
|
||||
// *inside* the closure would `eprintln!`+`exit(2)` from several windows before any one
|
||||
// exit lands — a racy, duplicated rejection (#177). Axis resolution is window-agnostic,
|
||||
// so pre-flighting the first IS window here surfaces the error exactly once (it fails in
|
||||
// `resolve_axes`, before any member runs); a per-window resolve then cannot re-raise.
|
||||
let first_is = WindowRoller::new(span, is_len, oos_len, step, RollMode::Rolling)
|
||||
.expect("roller config validated just above")
|
||||
.next()
|
||||
.expect("roller yields >= 1 window (validated above)")
|
||||
.is;
|
||||
if let Err(e) = blueprint_sweep_over(doc, axes, first_is.0, first_is.1, data) {
|
||||
eprintln!("aura: {e:?}");
|
||||
std::process::exit(2);
|
||||
}
|
||||
walk_forward(roller, space.clone(), |w: WindowBounds| {
|
||||
let (is_family, lattice) = blueprint_sweep_over(doc, axes, w.is.0, w.is.1, data)
|
||||
.unwrap_or_else(|e| { eprintln!("aura: {e:?}"); std::process::exit(2); });
|
||||
.expect("axes validated in the dispatch-boundary pre-flight");
|
||||
let (best, selection) = match select_winner(&is_family, "sqn_normalized", select, Some(&lattice)) {
|
||||
Ok(v) => v,
|
||||
Err(msg) => { eprintln!("aura: {msg}"); std::process::exit(2); }
|
||||
@@ -4129,6 +4145,18 @@ fn dispatch_run(a: RunCmd) {
|
||||
eprintln!("aura: {path}: {e:?}");
|
||||
std::process::exit(2);
|
||||
});
|
||||
// Refuse an open (free-knob) blueprint at the dispatch boundary, mirroring
|
||||
// `blueprint_mc_family`'s closed-guard: `run` bootstraps over the EMPTY point, so a
|
||||
// free knob would panic in `compile_with_params` — reject it clean instead (#176).
|
||||
let free = blueprint_axis_probe(&doc).param_space();
|
||||
if !free.is_empty() {
|
||||
eprintln!(
|
||||
"aura: run requires a closed blueprint (no free parameters); {} free knob(s) — \
|
||||
bind them or use `aura sweep --axis`",
|
||||
free.len()
|
||||
);
|
||||
std::process::exit(2);
|
||||
}
|
||||
let params = match a.params.as_deref() {
|
||||
Some(j) => parse_param_cells(j).unwrap_or_else(|m| {
|
||||
eprintln!("aura: {m}");
|
||||
|
||||
Reference in New Issue
Block a user