test(cli): RED — aura graph must render a consumer blueprint, not the sample (#28)

aura graph is the last verb still sample-bound: its no-subcommand arm always
renders the embedded r_sma_open.json, ignoring any blueprint path, while
run/sweep/mc/walkforward/generalize consume a consumer blueprint file via
is_blueprint_file. This pins the target: aura graph <blueprint.json> renders
that file's own graph (its inlined model reflects the file's nodes, e.g.
r-breakout's channel_hi), not the embedded sample.

refs #28
This commit is contained in:
2026-07-10 03:14:44 +02:00
parent 94cdbf90cc
commit 7cc986486f
+54
View File
@@ -655,6 +655,60 @@ fn graph_emits_self_contained_html_viewer() {
assert!(!stdout.contains("Sub(#Sf,#Ss)"), "retired ascii-dag notation must be gone: {stdout}");
}
/// Property (#28): `aura graph <blueprint.json>` renders the CONSUMER's own
/// graph — the structure of the file it is handed — not the embedded r_sma
/// sample. Mirrors the `dispatch_run` dual-grammar: a first-positional naming
/// an existing `.json` selects the loaded-blueprint branch, which reads the
/// file, reloads it via `blueprint_from_json`, and `render_html`s it — so the
/// emitted page's inlined `window.AURA_MODEL` reflects THAT file's nodes.
/// Handed the retired r-breakout example (std-vocabulary only, so no project is
/// needed), the page must carry a marker unique to that graph — `channel_hi`, a
/// RollingMax node name absent from the sample and from every static viewer
/// asset — and must NOT carry the sample-only `"type":"Bias"` node, i.e. it did
/// not silently fall back to the embedded r_sma sample. Driven through the built
/// binary so it pins the observable CLI contract.
#[test]
fn graph_renders_a_consumer_blueprint_file_not_the_embedded_sample() {
let cwd = temp_cwd("graph-consumer-blueprint");
// A committed consumer blueprint that is NOT the embedded sample and resolves
// against the base std vocabulary alone (RollingMax/RollingMin/Delay/Gt/Latch/
// Sub) — no project fixture required. Absolute path, so the temp cwd is free of
// any Aura.toml (guarantees std-env resolution).
let blueprint = format!("{}/examples/r_breakout.json", env!("CARGO_MANIFEST_DIR"));
let out = Command::new(BIN)
.arg("graph")
.arg(&blueprint)
.current_dir(&cwd)
.output()
.expect("spawn aura graph <blueprint>");
assert_eq!(
out.status.code(),
Some(0),
"`aura graph <blueprint.json>` exit: {:?}\nstderr: {}",
out.status,
String::from_utf8_lossy(&out.stderr)
);
let stdout = String::from_utf8(out.stdout).expect("utf-8 stdout");
// the page inlines a model as the viewer's data source...
assert!(
stdout.contains("window.AURA_MODEL = {\"root\":"),
"model not inlined into the page"
);
// ...and that model is the CONSUMER graph's — its own node `channel_hi`
// (unique to r-breakout, absent from the r_sma sample and from every static
// asset) is present.
assert!(
stdout.contains("channel_hi"),
"the consumer blueprint's own node (channel_hi) is missing — its graph was not rendered"
);
// ...NOT the embedded r_sma sample: the sample's Bias node type must be absent
// (proof the file was rendered, not silently ignored in favour of the sample).
assert!(
!stdout.contains("\"type\":\"Bias\""),
"rendered the embedded r_sma sample (its Bias node is present) instead of the consumer blueprint"
);
}
#[test]
fn sweep_with_trailing_token_is_strict_and_exits_two() {
// strict-arg reading (#16): an unexpected trailing token is a usage error.