From 4e6d5d4688818e5e144f9edf6719a6c0e25d6a62 Mon Sep 17 00:00:00 2001 From: claude Date: Mon, 13 Jul 2026 13:41:21 +0200 Subject: [PATCH] =?UTF-8?q?test(cli):=20RED=20=E2=80=94=20run=20manifest?= =?UTF-8?q?=20stamps=20untouched=20bound=20defaults=20(refs=20#249)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Executable spec for the defaults field: aura run on the fully bound examples/r_sma.json must report a manifest whose params stays [] (the "what varied" record) and whose new defaults field carries the untouched bound params as wrap-prefixed (name, Scalar) pairs in bound_param_space() order — fast.length I64 2, slow.length I64 4, bias.scale F64 0.5. Asserts on the stdout JSON (C14: stdout shape == on-disk shape), so it compiles against the current RunManifest and fails on the absent key. --- crates/aura-cli/tests/cli_run.rs | 34 ++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/crates/aura-cli/tests/cli_run.rs b/crates/aura-cli/tests/cli_run.rs index 6f0852e..c1dfd95 100644 --- a/crates/aura-cli/tests/cli_run.rs +++ b/crates/aura-cli/tests/cli_run.rs @@ -141,6 +141,40 @@ fn run_prints_json_and_exits_zero() { assert!(line.contains("\"r\":{\"expectancy_r\":"), "got: {line}"); } +/// Property (#249): a plain `aura run` on a fully bound blueprint records the +/// untouched bound param values *directly in the outcome artifact*, so a raw +/// reader of the manifest recovers the effective params without dereferencing +/// the topology hash into the content-addressed store and re-implementing +/// aura's merge semantics. The manifest carries a `defaults` field — the bound +/// params merged inside `PrimitiveBuilder::build` below every record-writing +/// layer — as wrap-prefixed `(name, Scalar)` pairs in `bound_param_space()` +/// order (the same coordinate `--axis` uses). `params` keeps its "what varied" +/// meaning: on a plain run nothing varied, so it stays `[]`, and every bound +/// value lands in `defaults` instead of vanishing from the record. +#[test] +fn run_manifest_stamps_untouched_bound_defaults() { + // The shipped r_sma.json is fully bound (fast.length=2, slow.length=4, + // bias.scale=0.5); no axis re-opens any of them, so none flow through the + // param space — today they appear in no outcome artifact ("params":[]). + let out = Command::new(BIN).args(["run", "examples/r_sma.json"]).output().expect("spawn aura run"); + assert!(out.status.success(), "exit status: {:?}", out.status); + let stdout = String::from_utf8(out.stdout).expect("utf-8 stdout"); + let line = stdout.trim_end(); + + // "what varied" is empty on a plain run — the bound defaults are NOT params. + assert!(line.contains("\"params\":[]"), "params stays empty on a plain run: {line}"); + + // The untouched bound values are stamped in `defaults`, wrap-prefixed with + // the blueprint name and ordered by `bound_param_space()` (node-declaration + // order: fast, slow, bias), each a self-describing tagged Scalar (C14). + assert!( + line.contains( + r#""defaults":[["sma_signal.fast.length",{"I64":2}],["sma_signal.slow.length",{"I64":4}],["sma_signal.bias.scale",{"F64":0.5}]]"# + ), + "manifest must carry the untouched bound defaults: {line}", + ); +} + /// Property: the RunManifest is self-identifying — its `commit` carries the /// real code identity that produced the run, not a placeholder. C8/C18 audit /// trail (this run = this commit): once runs are archived, `manifest.commit`