Files
Aura/docs/plans/0101-normalize-cli-usage-casing.md
T
Brummel ab7f0b0650 plan: 0101 normalize CLI usage-message casing
One lockstep task: 10 byte-exact literal edits (6 lowercase usage: flips,
4 bare closures gain the 'Usage: aura ' prefix, mc built-in gets the program
name in both alternatives) + the single casing-sensitive pin flip in
cli_run.rs, then build / targeted test / full suite / clippy / grep gates /
diff-shape gate / sweep smoke.

refs #179
2026-07-02 12:39:29 +02:00

9.2 KiB
Raw Blame History

Normalize CLI usage-message casing — Implementation Plan

Parent spec: docs/specs/0101-normalize-cli-usage-casing.md

For agentic workers: REQUIRED SUB-SKILL: use the implement skill to run this plan. Steps use - [ ] checkboxes for tracking.

Goal: Normalize every hand-rolled CLI usage line to the single house style Usage: aura <verb> … (10 literal edits) and flip the one casing-sensitive test pin in lockstep — cosmetic only, no behaviour change (issue #179).

Architecture: All edits are byte-substitutions inside existing string literals on existing exit-2 usage paths; emission channels (stderr via the aura: convention), exit codes, and control flow stay byte-identical. The lockstep unit is indivisible: the mc built-in literal (site #6) and the cli_run.rs pin must move together or the suite goes red, so this plan is one task.

Tech Stack: crates/aura-cli (clap v4 derive CLI), Rust string literals, cargo test integration suite cli_run.rs.


Files this plan creates or modifies:

  • Modify: crates/aura-cli/src/graph_construct.rs:191 — site #1 casing flip
  • Modify: crates/aura-cli/src/main.rs:3991,4187,4272,4288,4346,4386,4424,4465,4503 — sites #2#10
  • Test: crates/aura-cli/tests/cli_run.rs:1409 — the single casing-sensitive pin flips lowercase "usage""Usage"

Off-limits (do not touch): every other string in crates/aura-cli (refusal diagnostics, the already-conforming run_args_from literal at main.rs:4012), all other test bytes, and the fieldtests/ corpus (its old exact-equality usage pins are out-of-workspace by design and stay byte-identical).


Task 1: House-style normalization + lockstep pin flip

Files:

  • Modify: crates/aura-cli/src/graph_construct.rs:191
  • Modify: crates/aura-cli/src/main.rs:3991,4187,4272,4288,4346,4386,4424,4465,4503
  • Test: crates/aura-cli/tests/cli_run.rs:1409

Each edit below is exact: old is the complete current line (verified unique in its file), new is the complete replacement line. Only the shown bytes change. Note sites #7 and #9 contain a Unicode ellipsis () inside [--axis …] — preserve it verbatim.

  • Step 1: Site #1 — graph_construct.rs:191 (introspect_cmd)

old:

            "aura: usage: aura graph introspect --vocabulary | --node <T> | --unwired | --content-id"

new:

            "aura: Usage: aura graph introspect --vocabulary | --node <T> | --unwired | --content-id"
  • Step 2: Site #2 — main.rs:3991 (run_data_from, let-binding)

old:

    let usage = "usage: aura run <blueprint.json> [--params <json-cell-array>] [--seed <n>] [--real <SYMBOL> [--from <ms>] [--to <ms>]]";

new:

    let usage = "Usage: aura run <blueprint.json> [--params <json-cell-array>] [--seed <n>] [--real <SYMBOL> [--from <ms>] [--to <ms>]]";
  • Step 3: Site #3 — main.rs:4187 (dispatch_run, inline eprintln, verbatim twin of #2 with baked aura: )

old:

                eprintln!("aura: usage: aura run <blueprint.json> [--params <json-cell-array>] [--seed <n>] [--real <SYMBOL> [--from <ms>] [--to <ms>]]");

new:

                eprintln!("aura: Usage: aura run <blueprint.json> [--params <json-cell-array>] [--seed <n>] [--real <SYMBOL> [--from <ms>] [--to <ms>]]");
  • Step 4: Site #4 — main.rs:4272 (dispatch_runs)

old:

                eprintln!("aura: usage: aura runs family <id> [rank <metric>]");

new:

                eprintln!("aura: Usage: aura runs family <id> [rank <metric>]");
  • Step 5: Site #5 — main.rs:4465 (dispatch_mc, blueprint branch; gains the program name)

old:

            let usage = "usage: mc <blueprint.json> --seeds <n> [--name <n>]";

new:

            let usage = "Usage: aura mc <blueprint.json> --seeds <n> [--name <n>]";
  • Step 6: Site #6 — main.rs:4503 (dispatch_mc, built-in branch; BOTH |-separated alternatives gain the program name)

old:

            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();

new:

            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();
  • Step 7: Site #7 — main.rs:4288 (dispatch_sweep, blueprint branch; bare → prefixed; keep the byte)

old:

            let usage = || "sweep <blueprint.json> --axis <name>=<csv> [--axis …] [--name <n> | --trace <n>] [--real <SYM> [--from <ms>] [--to <ms>]]".to_string();

new:

            let usage = || "Usage: aura sweep <blueprint.json> --axis <name>=<csv> [--axis …] [--name <n> | --trace <n>] [--real <SYM> [--from <ms>] [--to <ms>]]".to_string();
  • Step 8: Site #8 — main.rs:4346 (dispatch_sweep, built-in branch; bare → prefixed)

old:

            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();

new:

            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();
  • Step 9: Site #9 — main.rs:4386 (dispatch_walkforward, blueprint branch; bare → prefixed; keep the byte)

old:

            let usage = || "walkforward <blueprint.json> --axis <name>=<csv> [--axis …] [--select <argmax|plateau:mean|plateau:worst>] [--name <n>]".to_string();

new:

            let usage = || "Usage: aura walkforward <blueprint.json> --axis <name>=<csv> [--axis …] [--select <argmax|plateau:mean|plateau:worst>] [--name <n>]".to_string();
  • Step 10: Site #10 — main.rs:4424 (dispatch_walkforward, built-in branch; bare → prefixed)

old:

            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();

new:

            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();
  • Step 11: Lockstep pin flip — cli_run.rs:1409 (test mc_rejects_real_flag_with_usage_exit_2)

Only the predicate substring flips; the panic-message argument keeps its lowercase "usage" verbatim.

old:

    assert!(stderr.contains("usage"), "mc --real stderr must carry usage: {stderr:?}");

new:

    assert!(stderr.contains("Usage"), "mc --real stderr must carry usage: {stderr:?}");
  • Step 12: Build gate

Run: cargo build --workspace Expected: clean compile, 0 errors, 0 warnings introduced.

  • Step 13: Targeted pin test

Run: cargo test -p aura-cli --test cli_run mc_rejects_real_flag_with_usage_exit_2 Expected: 1 passed; 0 failed (exactly one test matches the filter).

  • Step 14: Full-suite gate

Run: cargo test --workspace Expected: green, 0 failures across all targets. Any failure other than a test this plan did not touch going red means an edit strayed outside the normative table — fix the edit, never a pin.

  • Step 15: Lint gate

Run: cargo clippy --workspace --all-targets -- -D warnings Expected: clean, 0 warnings.

  • Step 16: Literal grep gates

Run: grep -rn '"usage:' crates/aura-cli/src/ Expected: no output (exit 1 — zero hits).

Run: grep -rn 'aura: usage:' crates/aura-cli/src/ Expected: no output (exit 1 — zero hits).

Run: grep -rn 'Usage: aura' crates/aura-cli/src/ | wc -l Expected: 11 (the 10 edited sites + the untouched conforming run_args_from literal at main.rs:4012).

  • Step 17: Diff-shape gate

Run: git diff --stat Expected: exactly 3 files changed — crates/aura-cli/src/main.rs, crates/aura-cli/src/graph_construct.rs, crates/aura-cli/tests/cli_run.rs (plus this plan/spec under docs/ if listed); no fieldtests/ path, no other test file.

  • Step 18: Smoke (worked example from the spec)

Run: cargo run -q -p aura-cli -- sweep --strategy bogus; echo "exit=$?" Expected stderr line: aura: 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>] Expected exit code line: exit=2.