diff --git a/crates/aura-cli/tests/cli_run.rs b/crates/aura-cli/tests/cli_run.rs index e4fe732..1b36a2e 100644 --- a/crates/aura-cli/tests/cli_run.rs +++ b/crates/aura-cli/tests/cli_run.rs @@ -1225,6 +1225,82 @@ fn sweep_real_blueprint_member_lines_pin_the_dissolved_contract() { assert_eq!(count("campaigns"), 1, "second identical run dedupes the campaign doc"); } +/// True iff `root` contains, at any depth, a regular file of non-zero length — +/// the layout-agnostic "traces actually landed on disk" probe. #224 does not yet +/// pin the per-member trace-directory naming (the sweep sugar's cell has no +/// nominee and `persist_campaign_traces` keys by `/`), so +/// this walks the tree rather than hard-coding a path, keeping the headline about +/// *that* traces are written, not *where*. +fn any_nonempty_file(root: &Path) -> bool { + let mut stack = vec![root.to_path_buf()]; + while let Some(p) = stack.pop() { + let Ok(entries) = std::fs::read_dir(&p) else { continue }; + for entry in entries.flatten() { + let path = entry.path(); + if path.is_dir() { + stack.push(path); + } else if std::fs::metadata(&path).map(|m| m.len() > 0).unwrap_or(false) { + return true; + } + } + } + false +} + +/// Property (#224): `aura sweep --real SYM --axis … --trace ` +/// DELIVERS the advertised trace-writing capability instead of the #168 +/// refuse-with-pointer. Two things must hold once the capability ships: +/// (1) the run no longer refuses (`aura: --trace is not yet available on sweep; +/// see #224`, exit 2) but succeeds, and (2) the tap series actually land on disk +/// under `runs/traces/` — at least one non-empty tap file is written, the honest +/// inverse of the #168 no-op where the `--real` sugar set `persist_taps: vec![]` +/// (verb_sugar.rs) and `run_blueprint_sweep` did `let _ = persist`, so nothing was +/// ever written. The exact on-disk layout (trace name + per-member/nominee key) +/// is deliberately NOT pinned here: this headline pins that traces are written at +/// all — not how many dirs, nor under what member key — because that naming is +/// the GREEN slice's open design point (the selection-free sweep cell has no +/// nominee for the existing per-cell `persist_campaign_traces` mechanism, #224). +/// Gated on the local GER40 archive (the project skip-on-no-data convention); +/// the refused status quo makes it RED on a data-ful host today. +#[test] +fn sweep_real_with_trace_writes_tap_series_to_disk() { + 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_open.json", env!("CARGO_MANIFEST_DIR")); + let out = std::process::Command::new(BIN) + .args([ + "sweep", &fixture, + "--real", "GER40", + "--from", GER40_SEPT2024_FROM_MS, + "--to", GER40_SEPT2024_TO_MS, + "--axis", "sma_signal.fast.length=2,4", + "--trace", "brp", + ]) + .current_dir(dir) + .output() + .unwrap(); + // (1) the #168 refusal is lifted: the advertised flag runs instead of exit 2. + assert!( + out.status.success(), + "sweep --trace must no longer refuse (#224); exit {:?}, stderr: {}", + out.status.code(), + String::from_utf8_lossy(&out.stderr), + ); + // (2) the tap series actually land on disk under runs/traces/ (non-empty) — + // the honest inverse of the #168 `persist_taps: vec![]` no-op. + let traces_root = dir.join("runs").join("traces"); + assert!( + any_nonempty_file(&traces_root), + "sweep --trace must write at least one non-empty tap file under {} \ + (found none — the #168 no-op wrote nothing); stderr: {}", + traces_root.display(), + String::from_utf8_lossy(&out.stderr), + ); +} + /// Extract the first persisted family whose `kind` matches `want` from /// `aura runs families` stdout (one JSON object per line), returning its /// `family_id` — the id `aura reproduce` addresses. Panics if none matches so a