From 7a386dc9bb35fa7b82540f523dbf56ad1084ed51 Mon Sep 17 00:00:00 2001 From: Brummel Date: Thu, 2 Jul 2026 12:31:48 +0200 Subject: [PATCH] spec: 0101 normalize CLI usage-message casing (boss-signed) Single house style for every hand-rolled usage line: 'Usage: aura ...' (clap's capital prefix + program name), 10 literal edits + the one casing-sensitive test pin in lockstep. Refusal diagnostics, the conforming run_args_from site, clap output, and the fieldtests corpus stay byte-identical. Grounding-check PASS is the autonomous signature; scope-fork decisions are recorded on the issue. refs #179 --- docs/specs/0101-normalize-cli-usage-casing.md | 210 ++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 docs/specs/0101-normalize-cli-usage-casing.md diff --git a/docs/specs/0101-normalize-cli-usage-casing.md b/docs/specs/0101-normalize-cli-usage-casing.md new file mode 100644 index 0000000..5d6138c --- /dev/null +++ b/docs/specs/0101-normalize-cli-usage-casing.md @@ -0,0 +1,210 @@ +# 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.