# Normalize CLI usage-message casing — Design Spec **Date:** 2026-07-02 **Status:** Draft — awaiting sign-off (grounding-check gate; /boss auto-sign) **Authors:** orchestrator + Claude ## Goal Erase the three-way inconsistency in the aura CLI's hand-rolled usage messages (issue #179). After the clap adoption (#175), the binary speaks three styles at once: clap's own parse errors and one hand-rolled site say `Usage:` (capital), six hand-rolled sites say `usage:` (lowercase), and four hand-rolled closures carry no prefix word at all. This cycle normalizes every hand-rolled usage line to the single house style clap already speaks — **cosmetic only, no behaviour change**: exit codes, emission channels (stderr), and control flow are byte-for-byte preserved; only the usage-string literals and their casing-sensitive test pins move, in lockstep. Decision log (house-style shape, bare-closure inclusion, refusal exclusion, no de-dup refactor): issue #179, comment "Design reconciliation (specify)". ## Architecture ### The house style (normative) One rule: **every hand-rolled usage line reads `Usage: aura …`** — capital `Usage:` prefix and the program name included in the grammar, exactly the shape of the two already-conforming producers: - clap itself (derive API, `#[command(name = "aura")]`) renders `Usage: aura [OPTIONS]` on parse errors and `--help`; - the one already-capital hand-rolled site, the built-in `run` branch (`run_args_from`, `main.rs:4012`): `"Usage: aura run [--harness …] …"`. The emission convention around the literal is untouched: hand-rolled sites keep printing through the existing `eprintln!("aura: {…}")` / baked-in `aura: ` prefix, so the final stderr line reads `aura: Usage: aura …` — which is already today's output shape of the conforming `run_args_from` path. Exit codes keep the #175 partition (usage = 2, runtime = 1) at every touched site. ### Scope boundary **In scope (10 literal edits + 1 test-pin edit):** the 6 lowercase `usage:` literals, the 4 bare usage closures, and the single casing-sensitive test pin. **Out of scope (bytes preserved verbatim):** - The already-conforming site `run_args_from` (`main.rs:4012`) and all clap-generated output. - Every aura-specific refusal/diagnostic in the dispatch area — e.g. `"no recorded geometry for symbol …"`, `"walkforward requires >= 1 --axis to re-fit per window"`, the six `generalize` refusals, `"cost flags require an R-evaluator harness …"`, `"--harness is not valid with a blueprint file"`, `"--list-axes lists axes and takes no other flags"`, `"run/mc requires a closed blueprint …"`. A refusal is a diagnostic, not a usage line; clap itself keeps the two apart (`error: …` vs the `Usage:` block). - The duplicated run-blueprint usage literal (defined in `run_data_from` at `main.rs:3991`, verbatim inline copy in `dispatch_run` at `main.rs:4187`): both copies are normalized identically, but no shared constant is extracted — a de-dup refactor exceeds the cosmetic contract. - Historical fieldtest corpus text quoting an old usage line (`fieldtests/milestone-cost-model-graph/FINDINGS.md`) — the corpus is a tracked record, never retro-edited. - Rustdoc/comment prose saying "usage error" (no colon, not a message). ## Concrete code shapes ### Worked user-facing example (the acceptance evidence) Before (bare closure, built-in sweep): ```console $ aura sweep --strategy bogus aura: sweep [--strategy ] [--real [--from ] [--to ]] [--name | --trace ] [--fast ] [--slow ] [--stop-length ] [--stop-k ] [--channel ] [--window ] [--band-k ] $ echo $? 2 ``` After (house style; exit code unchanged): ```console $ aura sweep --strategy bogus aura: Usage: aura sweep [--strategy ] [--real [--from ] [--to ]] [--name | --trace ] [--fast ] [--slow ] [--stop-length ] [--stop-k ] [--channel ] [--window ] [--band-k ] $ echo $? 2 ``` And a lowercase site (mc, loaded-blueprint branch): ```console # before aura: usage: mc --seeds [--name ] # after aura: Usage: aura mc --seeds [--name ] ``` ### Normative literal edits (before → after, exact bytes) All in `crates/aura-cli` sources. Only the leading bytes of each literal change; the grammar tails (`…` below) are preserved verbatim from the current tree. | # | Site | Before (leading bytes) | After (leading bytes) | |---|------|------------------------|-----------------------| | 1 | `graph_construct.rs:191` (`introspect_cmd`) | `"aura: usage: aura graph introspect …"` | `"aura: Usage: aura graph introspect …"` | | 2 | `main.rs:3991` (`run_data_from`) | `"usage: aura run …"` | `"Usage: aura run …"` | | 3 | `main.rs:4187` (`dispatch_run`, inline copy of #2) | `"aura: usage: aura run …"` | `"aura: Usage: aura run …"` | | 4 | `main.rs:4272` (`dispatch_runs`) | `"aura: usage: aura runs family [rank ]"` | `"aura: Usage: aura runs family [rank ]"` | | 5 | `main.rs:4465` (`dispatch_mc`, blueprint) | `"usage: mc …"` | `"Usage: aura mc …"` | | 6 | `main.rs:4503` (`dispatch_mc`, built-in) | `"usage: mc [--name \|--trace ] \| mc --strategy r-sma …"` | `"Usage: aura mc [--name \|--trace ] \| aura mc --strategy r-sma …"` | | 7 | `main.rs:4288` (`dispatch_sweep`, blueprint) | `"sweep --axis …"` | `"Usage: aura sweep --axis …"` | | 8 | `main.rs:4346` (`dispatch_sweep`, built-in) | `"sweep [--strategy …"` | `"Usage: aura sweep [--strategy …"` | | 9 | `main.rs:4386` (`dispatch_walkforward`, blueprint) | `"walkforward --axis …"` | `"Usage: aura walkforward --axis …"` | | 10 | `main.rs:4424` (`dispatch_walkforward`, built-in) | `"walkforward [--strategy …"` | `"Usage: aura walkforward [--strategy …"` | Site #6 carries two grammar alternatives separated by ` | `; **both** gain the program name (`… | aura mc --strategy r-sma …`), so the line stays internally consistent. ### Test-pin edit (lockstep, exactly one casing-sensitive pin) `crates/aura-cli/tests/cli_run.rs:1409` (test `mc_rejects_real_flag`, pinning site #6): ```rust // before assert!(err.contains("usage"), …); // after assert!(err.contains("Usage"), …); ``` (The exact assertion text at that line is preserved except for the pinned substring's casing; if the assertion carries a message argument, it is left untouched.) All other pins are casing-neutral and stay byte-identical, verified against the current suite: `cli_run.rs:116` and `:669` already require capital `Usage` (satisfied by site `main.rs:4012` and by clap, respectively — both unedited); `cli_run.rs:1444/1445` pin the verbs `sweep`/`walkforward` and the flag `--real` (still substrings after the prefix is prepended); `cli_run.rs:3192/3628/3876` pin out-of-scope refusal texts (unedited); `tests/graph_construct.rs:294-297` pins only the exit code and an echo of the bogus node name. ## Components | File | Change | |------|--------| | `crates/aura-cli/src/main.rs` | 9 usage-literal edits (sites #2–#10) | | `crates/aura-cli/src/graph_construct.rs` | 1 usage-literal edit (site #1) | | `crates/aura-cli/tests/cli_run.rs` | 1 pin flip (`:1409`, lowercase `usage` → `Usage`) | No new files, no signature changes, no dependency changes. ## Data flow Unchanged. Every touched literal keeps its current path to the user: defined in its dispatch branch (as `&str`, `String` closure, or inline `eprintln!`), printed to **stderr** with the `aura: ` program prefix, followed by `exit(2)`. No emission moves between stdout/stderr, no exit code changes, no message is added or removed — only bytes inside existing literals change. ## Error handling The #175 exit-code partition is the invariant to preserve: usage errors exit 2, runtime failures exit 1. All twelve edited sites are on exit-2 paths today and stay there. The suite's exit-code pins (`exit_codes_partition_usage_two_from_runtime_one`, the per-command rejection tests) run unmodified except for the single casing pin above. ## Testing strategy No new tests: the change is cosmetic and the existing suite already pins the touched surface. The gate is the suite itself: 1. `cargo build --workspace` clean. 2. `cargo test --workspace` green with **exactly one** test-file edit (the `cli_run.rs:1409` casing flip). Any other failing pin means an edit strayed outside the normative table — fix the edit, not the pin. 3. `cargo clippy --workspace --all-targets -- -D warnings` clean. 4. Literal grep gates over `crates/aura-cli/src/`: - `grep -rn '"usage:' crates/aura-cli/src/` → 0 hits; - `grep -rn 'aura: usage:' crates/aura-cli/src/` → 0 hits; - every hand-rolled usage literal now starts `Usage: aura ` (or `aura: Usage: aura ` where the program prefix is baked into the literal). 5. Smoke: `aura sweep --strategy bogus` prints the house-style line to stderr and exits 2 (the worked example above). ## Acceptance criteria - [ ] All 10 normative literal edits applied exactly as tabled (11 grammar alternatives counting site #6's two; sites #2/#3 remain verbatim twins). - [ ] `cli_run.rs:1409` pins capital `Usage`; no other test bytes change. - [ ] Grep gates (Testing strategy #4) pass: no lowercase `usage:` literal survives in `crates/aura-cli/src/`. - [ ] `cargo build` / `cargo test --workspace` / clippy `-D warnings` all green. - [ ] Exit codes unchanged at every touched site (usage = 2). - [ ] Out-of-scope surfaces byte-identical: refusal diagnostics, `run_args_from` literal, clap output, fieldtests corpus, README / design-ledger prose.