feat(cli): sweep/walkforward --trace writes every member's tap series (#168 refusal lifted)

--trace <fam> now translates through the verb sugar into a persist_taps
campaign-presentation block (was persist_taps: vec![] — the #168 no-op)
and persist_campaign_traces writes EVERY member of a selection-free
swept cell, one subdirectory per member under the cell dir, keyed by
the member's manifest params label in reproduce's exact format
(filesystem-sanitized, ordinal fallback); nominee cells keep their flat
layout. Members re-run at the cell's own stop regime and resolved pip,
streaming one member at a time, with the C1 drift alarm preserved per
member. The walkforward sibling lifts identically; run/mc --trace stay
refused by design (no campaign context / no family-name concept — their
help was already honest). Clap help lines and the chart NotFound hint
restored; the old #168 refusal pins re-pinned to the delivered
behaviour.

Post-review repairs: member_trace_key + cell_member_fanout extracted
pure and unit-pinned (6 tests), persisted_cells counts cells again,
cell-invariant space/geo hoisted out of the member loop, verb_sugar
tail comment corrected.

Verified: headline e2e green (GER40 archive), cli_run 124/0, full
workspace suite green, clippy -D warnings clean; independent spec
review compliant, quality review findings all repaired.

closes #224
refs #168
This commit is contained in:
2026-07-10 22:16:09 +02:00
parent fe4ea0a08d
commit 00e15b9371
4 changed files with 411 additions and 131 deletions
+11 -7
View File
@@ -1277,6 +1277,7 @@ fn sweep_real_with_trace_writes_tap_series_to_disk() {
"--from", GER40_SEPT2024_FROM_MS,
"--to", GER40_SEPT2024_TO_MS,
"--axis", "sma_signal.fast.length=2,4",
"--axis", "sma_signal.slow.length=8",
"--trace", "brp",
])
.current_dir(dir)
@@ -2321,10 +2322,11 @@ fn walkforward_dissolved_refuses_an_unknown_select_token() {
assert!(stderr.contains("Usage: aura walkforward"), "unknown-select refusal: {stderr}");
}
/// `--trace` is now refused up front on every blueprint-mode arm (#168, before the
/// `--name`/`--trace` mutual-exclusion check even runs) — the dissolved r-sma-real
/// path must surface that #224 forward-pointer refusal (exit 2), not the generic
/// mutual-exclusion message which its early return now pre-empts.
/// `--name`/`--trace` are mutually exclusive on the walkforward real-data path
/// (#224 delivers `--trace` there — the up-front #168 forward-pointer refusal
/// is gone; `walkforward_args_from`'s own mutual-exclusion check is what fires
/// when both are given at once), exit 2, naming the mutual-exclusion contract
/// rather than a now-stale #224 forward pointer.
#[test]
fn walkforward_dissolved_refuses_name_and_trace_together() {
let cwd = temp_cwd("walkforward-name-and-trace");
@@ -2339,10 +2341,12 @@ fn walkforward_dissolved_refuses_name_and_trace_together() {
.current_dir(&cwd)
.output()
.expect("spawn aura");
assert_eq!(out.status.code(), Some(2), "--trace is refused up front (exit 2)");
assert_eq!(out.status.code(), Some(2), "--name/--trace together is refused (exit 2)");
let stderr = String::from_utf8_lossy(&out.stderr);
assert!(stderr.contains("--trace"), "refusal names the flag: {stderr}");
assert!(stderr.contains("#224"), "refusal points forward to #224: {stderr}");
assert!(
stderr.contains("mutually exclusive"),
"refusal names the mutual-exclusion contract: {stderr}"
);
}
/// Property (#210 T3, dispatch split): a successful real-data walkforward