fix(cli): refuse --trace on sweep/walkforward instead of silently dropping it (#168)
The clap help promised "persists each member's/OOS window's taps" and the chart NotFound hint recommended `aura sweep --trace`, but every blueprint-mode arm discarded the flag (run_blueprint_sweep's `let _ = persist`, the --real sugar's persist_taps: vec![]) — the surface advertised trace-recording the code dropped. Refuse --trace up front on both verbs (exit 2, "--trace is not yet available on <verb>; see #224"), mirroring the existing aura run / aura mc refusals; drop the false promise from the two help lines and the chart NotFound hint. Delivering per-member trace-writing is deferred to #224. Collateral: four synthetic-sweep tests that used --trace as a family-name handle move to --name (same handle, still accepted); the walkforward name/trace test now pins the up-front #224 refusal. Workspace suite green (62 groups / 0 failed), clippy -D warnings clean. refs #168
This commit is contained in:
@@ -447,7 +447,7 @@ fn emit_chart(name: &str, tap: Option<&str>, mode: ChartMode, env: &project::Env
|
||||
NameKind::NotFound => {
|
||||
eprintln!(
|
||||
"aura: no recorded run or family '{name}' under runs/traces \
|
||||
(run `aura run --trace {name}` or `aura sweep --trace {name}` first)"
|
||||
(run `aura run --trace {name}` first)"
|
||||
);
|
||||
std::process::exit(1);
|
||||
}
|
||||
@@ -2174,7 +2174,7 @@ struct SweepCmd {
|
||||
/// Family name (records to the registry without persisting per-member traces).
|
||||
#[arg(long)]
|
||||
name: Option<String>,
|
||||
/// Family name that also persists each member's taps (mutually exclusive with --name).
|
||||
/// Family name (not yet available on this verb; see #224).
|
||||
#[arg(long)]
|
||||
trace: Option<String>,
|
||||
/// Blueprint sweep axis `<name>=<csv>` (repeatable; .json mode).
|
||||
@@ -2201,7 +2201,7 @@ struct WalkforwardCmd {
|
||||
/// Family name (records to the registry without persisting per-member traces).
|
||||
#[arg(long)]
|
||||
name: Option<String>,
|
||||
/// Family name that also persists each OOS window's taps (mutually exclusive with --name).
|
||||
/// Family name (not yet available on this verb; see #224).
|
||||
#[arg(long)]
|
||||
trace: Option<String>,
|
||||
/// Campaign-path stop length (single value; --real mode).
|
||||
@@ -2795,9 +2795,17 @@ fn dispatch_new(a: NewCmd, _env: &project::Env) {
|
||||
fn dispatch_sweep(a: SweepCmd, env: &project::Env) {
|
||||
// Single-sourced: the blueprint grammar and the no-blueprint usage error must
|
||||
// stay in lockstep, so both arms below read this one closure.
|
||||
let usage = || "Usage: aura sweep <blueprint.json> --axis <name>=<csv> [--axis …] [--name <n> | --trace <n>] [--real <SYM> [--from <ms>] [--to <ms>]]".to_string();
|
||||
let usage = || "Usage: aura sweep <blueprint.json> --axis <name>=<csv> [--axis …] [--name <n>] [--real <SYM> [--from <ms>] [--to <ms>]]".to_string();
|
||||
match is_blueprint_file(&a.blueprint) {
|
||||
Some(path) => {
|
||||
// No blueprint-mode arm persists per-member taps (synthetic drops it via
|
||||
// `let _ = persist`, `--real` sugar sets `persist_taps: vec![]`) — refuse
|
||||
// rather than silently accept an advertised-but-unhonoured flag, mirroring
|
||||
// the `aura run`/`aura mc` --trace refusals.
|
||||
if a.trace.is_some() {
|
||||
eprintln!("aura: --trace is not yet available on sweep; see #224");
|
||||
std::process::exit(2);
|
||||
}
|
||||
let doc = std::fs::read_to_string(path).unwrap_or_else(|e| {
|
||||
eprintln!("aura: {path}: {e}");
|
||||
std::process::exit(2);
|
||||
@@ -2817,7 +2825,6 @@ fn dispatch_sweep(a: SweepCmd, env: &project::Env) {
|
||||
// A query, not a sweep: it must stand alone.
|
||||
if !a.axis.is_empty()
|
||||
|| a.name.is_some()
|
||||
|| a.trace.is_some()
|
||||
|| a.real.is_some()
|
||||
|| a.from.is_some()
|
||||
|| a.to.is_some()
|
||||
@@ -2901,9 +2908,16 @@ fn dispatch_sweep(a: SweepCmd, env: &project::Env) {
|
||||
/// #220: arbitrary user blueprint + axes, formerly the welded r-sma branch).
|
||||
fn dispatch_walkforward(a: WalkforwardCmd, env: &project::Env) {
|
||||
// Single-sourced: both arms below read this one closure (house style, #179).
|
||||
let usage = || format!("Usage: aura walkforward <blueprint.json> --axis <name>=<csv> [--axis …] [--select <argmax|plateau:mean|plateau:worst>] [--name <n>] | aura walkforward <blueprint.json> --real <SYMBOL> --axis <name>=<csv> [--axis …] [--stop-length <n> (default {R_SMA_STOP_LENGTH})] [--stop-k <x> (default {R_SMA_STOP_K:.1})] [--from <ms>] [--to <ms>] [--name <n> | --trace <n>]");
|
||||
let usage = || format!("Usage: aura walkforward <blueprint.json> --axis <name>=<csv> [--axis …] [--select <argmax|plateau:mean|plateau:worst>] [--name <n>] | aura walkforward <blueprint.json> --real <SYMBOL> --axis <name>=<csv> [--axis …] [--stop-length <n> (default {R_SMA_STOP_LENGTH})] [--stop-k <x> (default {R_SMA_STOP_K:.1})] [--from <ms>] [--to <ms>] [--name <n>]");
|
||||
match is_blueprint_file(&a.blueprint) {
|
||||
Some(path) => {
|
||||
// No blueprint-mode arm persists per-window taps — refuse rather than
|
||||
// silently accept an advertised-but-unhonoured flag, mirroring the
|
||||
// `aura run`/`aura mc` --trace refusals.
|
||||
if a.trace.is_some() {
|
||||
eprintln!("aura: --trace is not yet available on walkforward; see #224");
|
||||
std::process::exit(2);
|
||||
}
|
||||
let doc = std::fs::read_to_string(path).unwrap_or_else(|e| {
|
||||
eprintln!("aura: {path}: {e}");
|
||||
std::process::exit(2);
|
||||
@@ -2983,7 +2997,7 @@ fn dispatch_walkforward(a: WalkforwardCmd, env: &project::Env) {
|
||||
return;
|
||||
}
|
||||
// Synthetic in-process family path — unchanged (#220 non-goal).
|
||||
if a.stop_length.is_some() || a.stop_k.is_some() || a.trace.is_some() {
|
||||
if a.stop_length.is_some() || a.stop_k.is_some() {
|
||||
eprintln!("aura: {}", usage());
|
||||
std::process::exit(2);
|
||||
}
|
||||
|
||||
@@ -1936,10 +1936,10 @@ fn walkforward_dissolved_refuses_an_unknown_select_token() {
|
||||
assert!(stderr.contains("Usage: aura walkforward"), "unknown-select refusal: {stderr}");
|
||||
}
|
||||
|
||||
/// `--trace`'s own help text ("mutually exclusive with --name") is a contract the
|
||||
/// inline path already enforces via `name_persist`; the dissolved r-sma-real path
|
||||
/// must refuse the same combination (exit 2) rather than silently letting --name
|
||||
/// win over --trace.
|
||||
/// `--trace` is now refused up front on every blueprint-mode arm (#168, before the
|
||||
/// `--name`/`--trace` mutual-exclusion check even runs) — the dissolved r-sma-real
|
||||
/// path must surface that #224 forward-pointer refusal (exit 2), not the generic
|
||||
/// mutual-exclusion message which its early return now pre-empts.
|
||||
#[test]
|
||||
fn walkforward_dissolved_refuses_name_and_trace_together() {
|
||||
let cwd = temp_cwd("walkforward-name-and-trace");
|
||||
@@ -1954,9 +1954,10 @@ fn walkforward_dissolved_refuses_name_and_trace_together() {
|
||||
.current_dir(&cwd)
|
||||
.output()
|
||||
.expect("spawn aura");
|
||||
assert_eq!(out.status.code(), Some(2), "--name and --trace together is a usage refusal");
|
||||
assert_eq!(out.status.code(), Some(2), "--trace is refused up front (exit 2)");
|
||||
let stderr = String::from_utf8_lossy(&out.stderr);
|
||||
assert!(stderr.contains("mutually exclusive"), "name/trace refusal: {stderr}");
|
||||
assert!(stderr.contains("--trace"), "refusal names the flag: {stderr}");
|
||||
assert!(stderr.contains("#224"), "refusal points forward to #224: {stderr}");
|
||||
}
|
||||
|
||||
/// Property (#210 T3, dispatch split): a successful real-data walkforward
|
||||
@@ -2717,7 +2718,7 @@ fn aura_sweep_loads_a_blueprint_and_persists_a_sweep_family() {
|
||||
"sweep", &fixture,
|
||||
"--axis", "sma_signal.fast.length=2,4",
|
||||
"--axis", "sma_signal.slow.length=8,16",
|
||||
"--trace", "f",
|
||||
"--name", "f",
|
||||
])
|
||||
.current_dir(&cwd)
|
||||
.output()
|
||||
@@ -2804,7 +2805,7 @@ fn aura_sweep_persists_the_canonical_blueprint_keyed_by_topology_hash() {
|
||||
"sweep", &fixture,
|
||||
"--axis", "sma_signal.fast.length=2,4",
|
||||
"--axis", "sma_signal.slow.length=8,16",
|
||||
"--trace", "f",
|
||||
"--name", "f",
|
||||
])
|
||||
.current_dir(&cwd)
|
||||
.output()
|
||||
@@ -2881,7 +2882,7 @@ fn aura_reproduce_re_derives_a_persisted_sweep_family() {
|
||||
"sweep", &fixture,
|
||||
"--axis", "sma_signal.fast.length=2,4",
|
||||
"--axis", "sma_signal.slow.length=8,16",
|
||||
"--trace", "f",
|
||||
"--name", "f",
|
||||
])
|
||||
.current_dir(&cwd)
|
||||
.output()
|
||||
@@ -2922,7 +2923,7 @@ fn aura_reproduce_reports_a_diverged_member_and_exits_one() {
|
||||
"sweep", &fixture,
|
||||
"--axis", "sma_signal.fast.length=2,4",
|
||||
"--axis", "sma_signal.slow.length=8,16",
|
||||
"--trace", "f",
|
||||
"--name", "f",
|
||||
])
|
||||
.current_dir(&cwd)
|
||||
.output()
|
||||
|
||||
Reference in New Issue
Block a user