feat(cli,registry): bound-param axis overrides reach the campaign/--real trunk

Task 5 of the bound-override cycle. The campaign executor and its gates
accept an axis naming a bound param everywhere the open surface was
already accepted: CliMemberRunner::run_member re-opens the override set
on the cell's probe space and raw reload (raw_bound_overrides_of — the
campaign document's axis names live in strategy coordinates, matched
against bound_param_space directly), the P3 preflight in
validate_before_register threads the same set so the executable-shape
check passes, and aura-registry's validate_campaign_refs treats a bound
name as a valid axis (open space wins the arm order; the kind check
still faults a mismatched axis over a bound path).

The CLI-side helper family is named by coordinate system now:
wrapped_bound_overrides_of (wrap-prefixed, sweep/wf/reproduce) beside
raw_bound_overrides_of (campaign). A fresh post-block quality review
found no correctness defect; its two stale-comment findings (renamed
helpers cited under their old names) are fixed in this commit.

refs #246
This commit is contained in:
2026-07-13 03:37:54 +02:00
parent 3f4c9478bf
commit e902a0f31d
5 changed files with 334 additions and 62 deletions
+55 -1
View File
@@ -1870,7 +1870,7 @@ fn reproduce_family_with_overridden_bound_param_re_derives() {
}
/// Property (#246, distinct code path from `reproduce_family_with_overridden_bound_param_re_derives`):
/// `reproduce_family_in`'s override derivation (`bound_overrides_of`, computed once
/// `reproduce_family_in`'s override derivation (`wrapped_bound_overrides_of`, computed once
/// per family from the FIRST member's recorded params) applies uniformly across
/// `FamilyKind`s, not only `WalkForward` — a plain `aura sweep` family minted by
/// overriding a bound param on the CLOSED `r_sma.json` fixture re-derives
@@ -2215,6 +2215,60 @@ fn aura_sweep_real_blueprint_subset_axes_refuses_without_store_litter() {
);
}
/// Property (issue #246, task 5): the dissolved real-data `aura sweep`
/// campaign path accepts an `--axis` naming a BOUND param of a CLOSED
/// blueprint, not only an already-open one. Tasks 3-4 threaded this override
/// convention (bound value = default, `Composite::reopen`) through the
/// SYNTHETIC blueprint verb paths (`blueprint_sweep_family`/
/// `blueprint_sweep_over`, `reproduce_family_with_overridden_bound_param_re_derives`);
/// the real-data dissolved path routes through a distinct seam
/// (`CliMemberRunner::run_member` + `verb_sugar::validate_before_register`'s
/// P3 preflight) that carried no such threading at all, the explicit gap
/// named on `reproduce_family_with_overridden_bound_param_re_derives`'s doc
/// comment. Modelled on `sweep_real_blueprint_member_lines_pin_the_dissolved_contract`
/// (the dissolved-sweep e2e family `walkforward_dissolved_refuses_an_unknown_axis_name`
/// belongs to): same store-reading assertions (`aura runs families`, one
/// persisted `Sweep` family, member count), but over the CLOSED `r_sma.json`
/// fixture (`sma_signal.fast.length`/`sma_signal.slow.length` both bound)
/// instead of the OPEN `r_sma_open.json` every other real-data sweep pin uses.
#[test]
fn sweep_dissolved_accepts_an_axis_over_a_bound_param() {
if !local_data_present() {
eprintln!("skip: no local data at {}", data_server::DEFAULT_DATA_PATH);
return;
}
let (dir, _g) = fresh_project();
let fixture = format!("{}/examples/r_sma.json", env!("CARGO_MANIFEST_DIR"));
let out = Command::new(BIN)
.args([
"sweep", &fixture,
"--real", "GER40",
"--from", GER40_SEPT2024_FROM_MS,
"--to", GER40_SEPT2024_TO_MS,
"--axis", "sma_signal.fast.length=2,3",
"--name", "bound-override",
])
.current_dir(dir)
.output()
.expect("spawn aura sweep over a bound-param axis");
assert_eq!(
out.status.code(),
Some(0),
"a bound-param axis must re-open (#246) on the dissolved real-data campaign \
path too, stderr: {}",
String::from_utf8_lossy(&out.stderr)
);
let fams = Command::new(BIN).args(["runs", "families"]).current_dir(dir).output().unwrap();
assert!(fams.status.success(), "families exit: {:?}", fams.status);
let fams_out = String::from_utf8_lossy(&fams.stdout).into_owned();
assert_eq!(fams_out.lines().count(), 1, "exactly one family persisted: {fams_out}");
assert!(fams_out.contains("\"kind\":\"Sweep\""), "families: {fams_out}");
assert!(
fams_out.contains("\"members\":2"),
"the two-value bound-param axis grid yields two members: {fams_out}"
);
}
/// The synthetic seed-resweep `mc` is undefined over real bars (one realization ->
/// identical members), so a bare `aura mc --real EURUSD` — with no R candidate — is
/// REJECTED (usage on stderr, exit 2) at the binary boundary. The real path is