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

224 lines
9.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`.