From 962b249814a8969c166c6a86b6ab04cc40392cdd Mon Sep 17 00:00:00 2001 From: Brummel Date: Fri, 10 Jul 2026 04:10:02 +0200 Subject: [PATCH] fix(cli): aura graph rejects a bad blueprint arg, not a silent sample (#28) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The #28 cycle-close audit found aura graph silently rendered the embedded sample at exit 0 when the positional named an unreadable blueprint (typo, nonexistent path, wrong extension): is_blueprint_file returns None both for "no positional" and for a bad arg, and dispatch_graph's None arm conflated them — re-introducing the exact #28 "I asked for my graph, got the sample" surprise in the error path, and diverging from every sibling verb (a bad blueprint arg is a usage fault, exit 2, per C14). Split the None arm: no positional -> the sample (unchanged); a positional that is not a readable .json -> a usage error naming the arg, exit 2, mirroring dispatch_run. Also close the paired doc drift the audit flagged: the README blueprint-verb table and the authoring guide now document the aura graph render surface, absent while graph was the last sample-bound verb. refs #28 --- README.md | 6 ++++-- crates/aura-cli/src/main.rs | 10 +++++++++- docs/authoring-guide.md | 5 ++++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0ce9615..2bca8e9 100644 --- a/README.md +++ b/README.md @@ -43,8 +43,9 @@ Invoke it as `aura …` (examples below use the plain name). ## Running & orchestrating a loaded blueprint -These verbs all take the **blueprint file as their first positional argument** -and drive a family of runs over it. `walkforward`, `mc`, and `generalize` share +These verbs all take the **blueprint file as their first positional argument**. +Most drive a family of runs over it; `graph` renders its structure so a mis-wire +is visible before a run. `walkforward`, `mc`, and `generalize` share `sweep`'s generic grammar — the blueprint positional plus `--real` and a repeatable `--axis =` (`generalize` takes `--real `, at least two instruments, with a single value per axis) — see `--help`. @@ -52,6 +53,7 @@ least two instruments, with a single value per axis) — see `--help`. | Command | Purpose | |---|---| | `aura run ` | Run one backtest of a **closed** blueprint and print its report. An open (free-knob) blueprint is refused with a clean error — bind it, or use `sweep`. | +| `aura graph ` | **Render** the blueprint's structure as an interactive HTML DAG so a mis-wire is visible before a run. Omit the file to render the built-in sample; a named-but-unreadable file is a usage error. | | `aura sweep --list-axes` | **Discover** the blueprint's open, sweepable knobs. Prints each as `:`. Run this first to learn the axis names. | | `aura sweep --axis = [--axis …]` | Run a **grid family** over the named axes and persist it. | | `aura mc --seeds ` | Run a **synthetic Monte-Carlo family** of `n` seeded realizations. Wants a **closed** blueprint (the inverse of sweep). | diff --git a/crates/aura-cli/src/main.rs b/crates/aura-cli/src/main.rs index 42ce15e..0a205e6 100644 --- a/crates/aura-cli/src/main.rs +++ b/crates/aura-cli/src/main.rs @@ -2685,7 +2685,7 @@ fn dispatch_graph(a: GraphCmd, env: &project::Env) { }); print!("{}", render::render_html(&bp)); } - None => { + None if a.blueprint.is_none() => { let bp = blueprint_from_json( include_str!("../examples/r_sma_open.json"), &|t| env.resolve(t), @@ -2693,6 +2693,14 @@ fn dispatch_graph(a: GraphCmd, env: &project::Env) { .expect("the shipped r-sma example reloads into a renderable blueprint"); print!("{}", render::render_html(&bp)); } + None => { + eprintln!( + "aura: Usage: aura graph [] [build|introspect|register]; \ + {} is not a readable .json blueprint", + a.blueprint.as_deref().unwrap_or_default() + ); + std::process::exit(2); + } }, Some(GraphSub::Build) => graph_construct::build_cmd(env), Some(GraphSub::Introspect(i)) => graph_construct::introspect_cmd(i, env), diff --git a/docs/authoring-guide.md b/docs/authoring-guide.md index dda5834..9c2605c 100644 --- a/docs/authoring-guide.md +++ b/docs/authoring-guide.md @@ -86,7 +86,10 @@ $ aura graph build < smacross.json "input_roles":[{"name":"price",...,"source":"F64"}],"output":[...]}} ``` -Introspection is build-free wherever possible: +The built blueprint renders visually, too: `aura graph blueprint.json` emits an +interactive HTML DAG so a mis-wire is visible before any run (`aura graph` with +no file renders the built-in sample; a named-but-unreadable file is a usage +error). Introspection is build-free wherever possible: ``` $ aura graph introspect --vocabulary # one node type per line