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
This commit is contained in:
2026-07-02 12:39:29 +02:00
parent 7a386dc9bb
commit ab7f0b0650
@@ -0,0 +1,223 @@
# 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:
```rust
"aura: usage: aura graph introspect --vocabulary | --node <T> | --unwired | --content-id"
```
new:
```rust
"aura: Usage: aura graph introspect --vocabulary | --node <T> | --unwired | --content-id"
```
- [ ] **Step 2: Site #2 — `main.rs:3991` (`run_data_from`, let-binding)**
old:
```rust
let usage = "usage: aura run <blueprint.json> [--params <json-cell-array>] [--seed <n>] [--real <SYMBOL> [--from <ms>] [--to <ms>]]";
```
new:
```rust
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:
```rust
eprintln!("aura: usage: aura run <blueprint.json> [--params <json-cell-array>] [--seed <n>] [--real <SYMBOL> [--from <ms>] [--to <ms>]]");
```
new:
```rust
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:
```rust
eprintln!("aura: usage: aura runs family <id> [rank <metric>]");
```
new:
```rust
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:
```rust
let usage = "usage: mc <blueprint.json> --seeds <n> [--name <n>]";
```
new:
```rust
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:
```rust
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:
```rust
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:
```rust
let usage = || "sweep <blueprint.json> --axis <name>=<csv> [--axis …] [--name <n> | --trace <n>] [--real <SYM> [--from <ms>] [--to <ms>]]".to_string();
```
new:
```rust
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:
```rust
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:
```rust
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:
```rust
let usage = || "walkforward <blueprint.json> --axis <name>=<csv> [--axis …] [--select <argmax|plateau:mean|plateau:worst>] [--name <n>]".to_string();
```
new:
```rust
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:
```rust
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:
```rust
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:
```rust
assert!(stderr.contains("usage"), "mc --real stderr must carry usage: {stderr:?}");
```
new:
```rust
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`.