fix(cli): aura graph rejects a bad blueprint arg, not a silent sample (#28)

The #28 cycle-close audit found aura graph <file> 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 <file> render surface,
absent while graph was the last sample-bound verb.

refs #28
This commit is contained in:
2026-07-10 04:10:02 +02:00
parent 692760d3b0
commit 962b249814
3 changed files with 17 additions and 4 deletions
+9 -1
View File
@@ -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 [<blueprint.json>] [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),