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
9.2 KiB
Normalize CLI usage-message casing — Implementation Plan
Parent spec:
docs/specs/0101-normalize-cli-usage-casing.mdFor agentic workers: REQUIRED SUB-SKILL: use the
implementskill 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 bakedaura:)
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(testmc_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.