polish(cli): normalize usage-message casing to the clap house style
Every hand-rolled usage line now reads 'Usage: aura <verb> ...' — capital prefix plus the program name, the shape clap itself and the built-in run branch already spoke. 10 literal edits: 6 lowercase 'usage:' flips (graph introspect, run blueprint x2, runs family, mc blueprint, mc built-in), 4 bare closures gain the prefix (sweep/walkforward, blueprint + built-in branches); the mc built-in line names the program in both |-separated alternatives. Refusal diagnostics, the conforming run_args_from literal, clap output, and the fieldtests corpus stay byte-identical; exit codes keep the usage=2 / runtime=1 partition. Lockstep pin: the single casing-sensitive assertion (mc --real) flips to capital 'Usage'. Three additive regression tests pin the house style itself (bare-closure prefix, both mc alternatives, mc blueprint branch) — the pre-existing pins checked only verb tokens / a single Usage occurrence; deviation from the spec's no-new-test-bytes wording recorded on the issue. Verification: cargo test --workspace rc=0 (cli_run 133 passed), clippy -D warnings clean, grep gates exact (zero lowercase 'usage:' literals; 11 'Usage: aura' source lines), smoke 'aura sweep --strategy bogus' prints the house-style line and exits 2. closes #179
This commit is contained in:
@@ -188,7 +188,7 @@ pub fn introspect_cmd(cmd: crate::GraphIntrospectCmd) {
|
||||
+ cmd.content_id as usize;
|
||||
if count != 1 {
|
||||
eprintln!(
|
||||
"aura: usage: aura graph introspect --vocabulary | --node <T> | --unwired | --content-id"
|
||||
"aura: Usage: aura graph introspect --vocabulary | --node <T> | --unwired | --content-id"
|
||||
);
|
||||
std::process::exit(2);
|
||||
}
|
||||
|
||||
@@ -3988,7 +3988,7 @@ fn is_blueprint_file(arg: &Option<String>) -> Option<&str> {
|
||||
/// mirroring the old `parse_blueprint_run_args` window guard (`--from`/`--to`
|
||||
/// require `--real`; empty symbol rejected). Refuses in place (stderr + exit 2).
|
||||
fn run_data_from(real: Option<&str>, from: Option<i64>, to: Option<i64>) -> RunData {
|
||||
let usage = "usage: aura run <blueprint.json> [--params <json-cell-array>] [--seed <n>] [--real <SYMBOL> [--from <ms>] [--to <ms>]]";
|
||||
let usage = "Usage: aura run <blueprint.json> [--params <json-cell-array>] [--seed <n>] [--real <SYMBOL> [--from <ms>] [--to <ms>]]";
|
||||
match real {
|
||||
Some(s) if !s.is_empty() => RunData::Real { symbol: s.to_string(), from, to },
|
||||
Some(_) => {
|
||||
@@ -4184,7 +4184,7 @@ fn dispatch_run(a: RunCmd) {
|
||||
|| a.slip_vol_mult.is_some()
|
||||
|| a.carry_per_cycle.is_some()
|
||||
{
|
||||
eprintln!("aura: usage: aura run <blueprint.json> [--params <json-cell-array>] [--seed <n>] [--real <SYMBOL> [--from <ms>] [--to <ms>]]");
|
||||
eprintln!("aura: Usage: aura run <blueprint.json> [--params <json-cell-array>] [--seed <n>] [--real <SYMBOL> [--from <ms>] [--to <ms>]]");
|
||||
std::process::exit(2);
|
||||
}
|
||||
let doc = std::fs::read_to_string(path).unwrap_or_else(|e| {
|
||||
@@ -4269,7 +4269,7 @@ fn dispatch_runs(a: RunsCmd) {
|
||||
(None, None) => runs_family(&id, None),
|
||||
(Some("rank"), Some(m)) => runs_family(&id, Some(&m)),
|
||||
_ => {
|
||||
eprintln!("aura: usage: aura runs family <id> [rank <metric>]");
|
||||
eprintln!("aura: Usage: aura runs family <id> [rank <metric>]");
|
||||
std::process::exit(2);
|
||||
}
|
||||
},
|
||||
@@ -4285,7 +4285,7 @@ fn dispatch_reproduce(a: ReproduceCmd) {
|
||||
fn dispatch_sweep(a: SweepCmd) {
|
||||
match is_blueprint_file(&a.blueprint) {
|
||||
Some(path) => {
|
||||
let usage = || "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> | --trace <n>] [--real <SYM> [--from <ms>] [--to <ms>]]".to_string();
|
||||
let doc = std::fs::read_to_string(path).unwrap_or_else(|e| {
|
||||
eprintln!("aura: {path}: {e}");
|
||||
std::process::exit(2);
|
||||
@@ -4343,7 +4343,7 @@ fn dispatch_sweep(a: SweepCmd) {
|
||||
run_blueprint_sweep(&doc, &axes, &name, persist, DataSource::from_choice(data));
|
||||
}
|
||||
None => {
|
||||
let usage = || "sweep [--strategy <sma|momentum|r-sma|r-breakout|r-meanrev>] [--real <SYMBOL> [--from <ms>] [--to <ms>]] [--name <n> | --trace <n>] [--fast <csv>] [--slow <csv>] [--stop-length <csv>] [--stop-k <csv>] [--channel <csv>] [--window <csv>] [--band-k <csv>]".to_string();
|
||||
let usage = || "Usage: aura sweep [--strategy <sma|momentum|r-sma|r-breakout|r-meanrev>] [--real <SYMBOL> [--from <ms>] [--to <ms>]] [--name <n> | --trace <n>] [--fast <csv>] [--slow <csv>] [--stop-length <csv>] [--stop-k <csv>] [--channel <csv>] [--window <csv>] [--band-k <csv>]".to_string();
|
||||
if a.blueprint.is_some() || !a.axis.is_empty() || a.list_axes {
|
||||
eprintln!("aura: {}", usage());
|
||||
std::process::exit(2);
|
||||
@@ -4383,7 +4383,7 @@ fn dispatch_sweep(a: SweepCmd) {
|
||||
fn dispatch_walkforward(a: WalkforwardCmd) {
|
||||
match is_blueprint_file(&a.blueprint) {
|
||||
Some(path) => {
|
||||
let usage = || "walkforward <blueprint.json> --axis <name>=<csv> [--axis …] [--select <argmax|plateau:mean|plateau:worst>] [--name <n>]".to_string();
|
||||
let usage = || "Usage: aura walkforward <blueprint.json> --axis <name>=<csv> [--axis …] [--select <argmax|plateau:mean|plateau:worst>] [--name <n>]".to_string();
|
||||
let doc = std::fs::read_to_string(path).unwrap_or_else(|e| {
|
||||
eprintln!("aura: {path}: {e}");
|
||||
std::process::exit(2);
|
||||
@@ -4421,7 +4421,7 @@ fn dispatch_walkforward(a: WalkforwardCmd) {
|
||||
run_blueprint_walkforward(&doc, &axes, &name, DataSource::Synthetic, select);
|
||||
}
|
||||
None => {
|
||||
let usage = || "walkforward [--strategy <sma|momentum|r-sma|r-breakout|r-meanrev>] [--real <SYMBOL> [--from <ms>] [--to <ms>]] [--name <n> | --trace <n>] [--fast <csv>] [--slow <csv>] [--stop-length <csv>] [--stop-k <csv>] [--select <argmax|plateau:mean|plateau:worst>]".to_string();
|
||||
let usage = || "Usage: aura walkforward [--strategy <sma|momentum|r-sma|r-breakout|r-meanrev>] [--real <SYMBOL> [--from <ms>] [--to <ms>]] [--name <n> | --trace <n>] [--fast <csv>] [--slow <csv>] [--stop-length <csv>] [--stop-k <csv>] [--select <argmax|plateau:mean|plateau:worst>]".to_string();
|
||||
if a.blueprint.is_some() || !a.axis.is_empty() {
|
||||
eprintln!("aura: {}", usage());
|
||||
std::process::exit(2);
|
||||
@@ -4462,7 +4462,7 @@ fn dispatch_walkforward(a: WalkforwardCmd) {
|
||||
fn dispatch_mc(a: McCmd) {
|
||||
match is_blueprint_file(&a.blueprint) {
|
||||
Some(path) => {
|
||||
let usage = "usage: mc <blueprint.json> --seeds <n> [--name <n>]";
|
||||
let usage = "Usage: aura mc <blueprint.json> --seeds <n> [--name <n>]";
|
||||
let doc = std::fs::read_to_string(path).unwrap_or_else(|e| {
|
||||
eprintln!("aura: {path}: {e}");
|
||||
std::process::exit(2);
|
||||
@@ -4500,7 +4500,7 @@ fn dispatch_mc(a: McCmd) {
|
||||
run_blueprint_mc(&doc, n_seeds, &name, DataSource::Synthetic);
|
||||
}
|
||||
None => {
|
||||
let usage = || "usage: mc [--name <n>|--trace <n>] | mc --strategy r-sma [--real <SYMBOL> [--from <ms>] [--to <ms>]] [--fast <csv>] [--slow <csv>] [--stop-length <csv>] [--stop-k <csv>] [--block-len <n>] [--resamples <n>] [--seed <n>]".to_string();
|
||||
let usage = || "Usage: aura mc [--name <n>|--trace <n>] | aura mc --strategy r-sma [--real <SYMBOL> [--from <ms>] [--to <ms>]] [--fast <csv>] [--slow <csv>] [--stop-length <csv>] [--stop-k <csv>] [--block-len <n>] [--resamples <n>] [--seed <n>]".to_string();
|
||||
if a.blueprint.is_some() || a.seeds.is_some() {
|
||||
eprintln!("aura: {}", usage());
|
||||
std::process::exit(2);
|
||||
|
||||
@@ -1406,7 +1406,7 @@ fn mc_rejects_real_flag_with_usage_exit_2() {
|
||||
assert_eq!(out.status.code(), Some(2), "mc --real must exit 2; status: {:?}", out.status);
|
||||
assert!(out.stdout.is_empty(), "mc --real must not emit a run on stdout: {:?}", out.stdout);
|
||||
let stderr = String::from_utf8_lossy(&out.stderr);
|
||||
assert!(stderr.contains("usage"), "mc --real stderr must carry usage: {stderr:?}");
|
||||
assert!(stderr.contains("Usage"), "mc --real stderr must carry usage: {stderr:?}");
|
||||
// the exclusion is total: no `runs/` registry write either.
|
||||
assert!(!dir.join("runs").exists(), "mc --real must not start a real run");
|
||||
|
||||
@@ -1447,6 +1447,85 @@ fn family_window_flag_without_real_refuses_with_usage_exit_2() {
|
||||
}
|
||||
}
|
||||
|
||||
/// Property (house style, #179): every hand-rolled usage line reads
|
||||
/// `Usage: aura <verb> …` — capital `Usage:` plus the program name inside the
|
||||
/// grammar. `sweep`/`walkforward`'s built-in-branch usage closures were bare
|
||||
/// (`"sweep [--strategy …]"`, no prefix, no program name) before cycle 0101; a
|
||||
/// regression that drops the prefix again would NOT be caught by the older
|
||||
/// `family_window_flag_without_real_refuses_with_usage_exit_2` pin above, which
|
||||
/// only checks for the verb token and `--real` — not the `Usage: aura` lead-in.
|
||||
/// An unknown `--strategy` name reaches this same closure on both commands, so
|
||||
/// it is the smallest trigger for each.
|
||||
#[test]
|
||||
fn builtin_branch_usage_lines_lead_with_the_house_style_prefix() {
|
||||
for (args, verb) in [(&["sweep", "--strategy", "bogus"][..], "sweep"), (&["walkforward", "--strategy", "bogus"][..], "walkforward")] {
|
||||
let dir = temp_cwd("builtin_usage_prefix");
|
||||
let out = Command::new(BIN)
|
||||
.args(args)
|
||||
.current_dir(&dir)
|
||||
.output()
|
||||
.unwrap_or_else(|e| panic!("spawn aura {args:?}: {e}"));
|
||||
assert_eq!(out.status.code(), Some(2), "`aura {args:?}` must exit 2; status: {:?}", out.status);
|
||||
let stderr = String::from_utf8_lossy(&out.stderr);
|
||||
let want = format!("aura: Usage: aura {verb} ");
|
||||
assert!(stderr.starts_with(&want), "`aura {args:?}` stderr must lead with {want:?}: {stderr:?}");
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
}
|
||||
|
||||
/// Property (house style, #179): the built-in `mc` usage line carries TWO
|
||||
/// `|`-separated grammar alternatives, and BOTH name the program (`aura mc …`),
|
||||
/// not just the first. This is the one lockstep-pinned site
|
||||
/// (`mc_rejects_real_flag_with_usage_exit_2` above), but that pin only checks
|
||||
/// for a single `"Usage"` occurrence — a regression that fixed only the first
|
||||
/// alternative (leaving `… | mc --strategy r-sma …` unprefixed) would still
|
||||
/// pass it. `--seeds` with no blueprint file is the built-in branch's own
|
||||
/// grammar violation, reaching this exact literal.
|
||||
#[test]
|
||||
fn mc_builtin_usage_names_the_program_in_both_alternatives() {
|
||||
let dir = temp_cwd("mc_usage_both_alts");
|
||||
let out = Command::new(BIN)
|
||||
.args(["mc", "--seeds", "3"])
|
||||
.current_dir(&dir)
|
||||
.output()
|
||||
.expect("spawn aura mc --seeds");
|
||||
assert_eq!(out.status.code(), Some(2), "mc --seeds without a blueprint must exit 2; status: {:?}", out.status);
|
||||
let stderr = String::from_utf8_lossy(&out.stderr);
|
||||
assert!(
|
||||
stderr.contains("Usage: aura mc [--name"),
|
||||
"first alternative must name the program: {stderr:?}"
|
||||
);
|
||||
assert!(
|
||||
stderr.contains("| aura mc --strategy r-sma"),
|
||||
"second alternative must ALSO name the program: {stderr:?}"
|
||||
);
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
/// Property (house style, #179): `mc`'s loaded-blueprint branch usage line
|
||||
/// also normalizes to `Usage: aura mc <blueprint.json> …` — before cycle 0101
|
||||
/// it was fully lowercase and carried no program name (`"usage: mc
|
||||
/// <blueprint.json> …"`). Reusing `sma_signal.json` (an existing closed
|
||||
/// blueprint fixture) only to reach the dispatch branch; omitting `--seeds`
|
||||
/// is this branch's own grammar violation.
|
||||
#[test]
|
||||
fn mc_over_a_blueprint_usage_names_the_program() {
|
||||
let dir = temp_cwd("mc_blueprint_usage_prefix");
|
||||
let fixture = format!("{}/tests/fixtures/sma_signal.json", env!("CARGO_MANIFEST_DIR"));
|
||||
let out = Command::new(BIN)
|
||||
.args(["mc", &fixture])
|
||||
.current_dir(&dir)
|
||||
.output()
|
||||
.expect("spawn aura mc <blueprint.json>");
|
||||
assert_eq!(out.status.code(), Some(2), "mc <blueprint.json> without --seeds must exit 2; status: {:?}", out.status);
|
||||
let stderr = String::from_utf8_lossy(&out.stderr);
|
||||
assert!(
|
||||
stderr.contains("aura: Usage: aura mc <blueprint.json>"),
|
||||
"stderr must lead with the house-style, program-named usage: {stderr:?}"
|
||||
);
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
/// Property: `aura chart <family>` overlays one series per family member, labelled
|
||||
/// by member key. The built-in sweep grid is fast∈{2,3} × slow∈{4,5} = 4 members;
|
||||
/// each member key appears as a series name in the injected AURA_TRACES.
|
||||
|
||||
Reference in New Issue
Block a user