test(cli): per-test project dirs via a [nodes] pointer — project_lock retired

Every E2E test that mutated the shared demo-project fixture store now
mints its own tempdir project whose 2-line Aura.toml points at the
once-built fixture crate by absolute [nodes] pointer; the runs/ store
follows the project root, so no two tests contend and libtest's
default thread parallelism applies. project_load keeps driving the
fixture directly (the suite's only proof of the inline-crate routing
arm); its single store-mutating test is that binary's only one, so no
lock is needed there either. This also closes the documented
cross-process race window (#223): there is no shared mutable store
left to race on.

Measured on the data-full host: cli_run 211s -> 57.2s (140 tests),
research_docs 21.1s -> 2.1s (73 tests), project_load green, clippy
clean.

refs #250
This commit is contained in:
2026-07-13 15:11:21 +02:00
parent 00cc2fe927
commit 25b8354959
4 changed files with 275 additions and 303 deletions
+56 -80
View File
@@ -1,12 +1,11 @@
//! Integration test: drive the built `aura` binary as a downstream user would,
//! asserting the `run` subcommand's stdout/exit contract and the bad-args path.
use std::path::{Path, PathBuf};
use std::path::Path;
use std::process::Command;
use std::sync::MutexGuard;
mod common;
use common::{built_project, project_lock};
use common::fresh_project;
/// Path to the freshly-built `aura` binary (Cargo sets this env var for the test
/// crate; the binary is named `aura` in `Cargo.toml`).
@@ -22,29 +21,6 @@ fn temp_cwd(name: &str) -> std::path::PathBuf {
dir
}
/// Removes `<fixture>/runs` on drop (including mid-panic) so a migrated test never
/// leaks its content-addressed store into the git-tracked fixture tree.
struct RunsCleanup(PathBuf);
impl Drop for RunsCleanup {
fn drop(&mut self) {
std::fs::remove_dir_all(&self.0).ok();
}
}
/// Enter the shared built project fixture with a FRESH `runs/` store, serialized.
/// Returns the fixture dir (has an Aura.toml, so `provenance()` is `Some`) and the
/// guards; bind the guards for the whole test body: `let (dir, _g) = fresh_project();`.
/// The guard tuple orders `RunsCleanup` before the `MutexGuard` deliberately: tuple
/// fields drop in index order, so the `runs/` removal (index 0) runs while the lock
/// (index 1) is still held — the serialization the lock exists to enforce.
fn fresh_project() -> (&'static PathBuf, (RunsCleanup, MutexGuard<'static, ()>)) {
let lock = project_lock();
let dir = built_project();
let runs = dir.join("runs");
std::fs::remove_dir_all(&runs).ok();
(dir, (RunsCleanup(runs), lock))
}
/// #218: a well-formed dissolved verb run outside a project refuses up front
/// (exit 1, "needs a project") and leaves no store — parity with `campaign run`.
/// The refusal names the INVOKED verb, not a copy-pasted generic string — a
@@ -1215,7 +1191,7 @@ fn sweep_real_no_geometry_symbol_refuses_with_exit_1() {
let fixture = format!("{}/examples/r_sma.json", env!("CARGO_MANIFEST_DIR"));
let out = std::process::Command::new(BIN)
.args(["sweep", &fixture, "--axis", "sma_signal.fast.length=2,4", "--real", "NONEXISTENT"])
.current_dir(dir).output().unwrap();
.current_dir(&dir).output().unwrap();
assert_eq!(out.status.code(), Some(1));
assert!(String::from_utf8_lossy(&out.stderr).contains("no recorded geometry"));
}
@@ -1301,7 +1277,7 @@ fn sweep_real_blueprint_member_manifest_stamps_the_default_stop() {
"--axis", "sma_signal.slow.length=8",
"--name", "brp_nostop",
])
.current_dir(dir)
.current_dir(&dir)
.output()
.unwrap();
assert!(out.status.success(), "stderr: {}", String::from_utf8_lossy(&out.stderr));
@@ -1348,7 +1324,7 @@ fn sweep_real_blueprint_member_manifest_stamps_project_provenance() {
"--axis", "sma_signal.slow.length=8",
"--name", "brp_provenance",
])
.current_dir(dir)
.current_dir(&dir)
.output()
.unwrap();
assert!(out.status.success(), "stderr: {}", String::from_utf8_lossy(&out.stderr));
@@ -1434,7 +1410,7 @@ fn sweep_real_ohlc_channel_members_run_and_reproduce() {
let fixture = format!("{}/tests/fixtures/r_channel_open.json", env!("CARGO_MANIFEST_DIR"));
let axes = std::process::Command::new(BIN)
.args(["sweep", &fixture, "--list-axes"])
.current_dir(dir)
.current_dir(&dir)
.output()
.unwrap();
assert_eq!(
@@ -1455,7 +1431,7 @@ fn sweep_real_ohlc_channel_members_run_and_reproduce() {
"--axis", "hl_channel.channel_length=3,5",
"--name", "chan",
])
.current_dir(dir)
.current_dir(&dir)
.output()
.unwrap();
assert!(out.status.success(), "stderr: {}", String::from_utf8_lossy(&out.stderr));
@@ -1476,7 +1452,7 @@ fn sweep_real_ohlc_channel_members_run_and_reproduce() {
.to_string();
let rep = std::process::Command::new(BIN)
.args(["reproduce", &family_id])
.current_dir(dir)
.current_dir(&dir)
.output()
.unwrap();
assert!(
@@ -1523,7 +1499,7 @@ fn sweep_real_blueprint_member_lines_pin_the_dissolved_contract() {
"--axis", "sma_signal.slow.length=8,16",
"--name", "brp",
])
.current_dir(dir)
.current_dir(&dir)
.output()
.unwrap();
assert!(out.status.success(), "stderr: {}", String::from_utf8_lossy(&out.stderr));
@@ -1571,7 +1547,7 @@ fn sweep_real_blueprint_member_lines_pin_the_dissolved_contract() {
// exactly one new Sweep family persisted, with the grid's four members.
let fams = std::process::Command::new(BIN)
.args(["runs", "families"])
.current_dir(dir)
.current_dir(&dir)
.output()
.unwrap();
assert!(fams.status.success(), "families exit: {:?}", fams.status);
@@ -1674,7 +1650,7 @@ fn sweep_real_blueprint_member_lines_pin_the_dissolved_contract() {
"--axis", "sma_signal.slow.length=8,16",
"--name", "brp",
])
.current_dir(dir)
.current_dir(&dir)
.output()
.unwrap();
assert!(out2.status.success(), "second run stderr: {}", String::from_utf8_lossy(&out2.stderr));
@@ -1761,7 +1737,7 @@ fn sweep_real_with_trace_writes_tap_series_to_disk() {
"--axis", "sma_signal.slow.length=8",
"--trace", "brp",
])
.current_dir(dir)
.current_dir(&dir)
.output()
.unwrap();
// (1) the #168 refusal is lifted: the advertised flag runs instead of exit 2.
@@ -1829,13 +1805,13 @@ fn reproduce_real_sweep_family_re_derives_bit_identically() {
"--axis", "sma_signal.slow.length=8",
"--name", "repro_sweep",
])
.current_dir(dir)
.current_dir(&dir)
.output()
.unwrap();
assert!(mint.status.success(), "sweep mint stderr: {}", String::from_utf8_lossy(&mint.stderr));
let id = family_id_of_kind(dir, "Sweep");
let out = Command::new(BIN).args(["reproduce", &id]).current_dir(dir).output().unwrap();
let id = family_id_of_kind(&dir, "Sweep");
let out = Command::new(BIN).args(["reproduce", &id]).current_dir(&dir).output().unwrap();
let stdout = String::from_utf8_lossy(&out.stdout).into_owned();
assert!(
out.status.success(),
@@ -1984,13 +1960,13 @@ fn reproduce_real_walkforward_family_does_not_panic() {
"--axis", "sma_signal.slow.length=8",
"--name", "repro_wf",
])
.current_dir(dir)
.current_dir(&dir)
.output()
.unwrap();
assert!(mint.status.success(), "walkforward mint stderr: {}", String::from_utf8_lossy(&mint.stderr));
let id = family_id_of_kind(dir, "WalkForward");
let out = Command::new(BIN).args(["reproduce", &id]).current_dir(dir).output().unwrap();
let id = family_id_of_kind(&dir, "WalkForward");
let out = Command::new(BIN).args(["reproduce", &id]).current_dir(&dir).output().unwrap();
let stdout = String::from_utf8_lossy(&out.stdout).into_owned();
let stderr = String::from_utf8_lossy(&out.stderr).into_owned();
assert_ne!(
@@ -2147,7 +2123,7 @@ fn sweep_real_multi_column_blueprint_opens_high_and_low_columns() {
"--axis", "hl_signal.fast.length=2,4",
"--axis", "hl_signal.slow.length=8",
])
.current_dir(dir)
.current_dir(&dir)
.output()
.unwrap();
assert!(out.status.success(), "stderr: {}", String::from_utf8_lossy(&out.stderr));
@@ -2232,7 +2208,7 @@ fn aura_sweep_real_blueprint_subset_axes_refuses_without_store_litter() {
"--axis", "sma_signal.fast.length=2,4",
"--name", "c0110-subset",
])
.current_dir(dir)
.current_dir(&dir)
.output()
.expect("spawn aura sweep (subset axes)");
assert_ne!(
@@ -2288,7 +2264,7 @@ fn sweep_dissolved_accepts_an_axis_over_a_bound_param() {
"--axis", "sma_signal.fast.length=2,3",
"--name", "bound-override",
])
.current_dir(dir)
.current_dir(&dir)
.output()
.expect("spawn aura sweep over a bound-param axis");
assert_eq!(
@@ -2298,7 +2274,7 @@ fn sweep_dissolved_accepts_an_axis_over_a_bound_param() {
path too, stderr: {}",
String::from_utf8_lossy(&out.stderr)
);
let fams = Command::new(BIN).args(["runs", "families"]).current_dir(dir).output().unwrap();
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}");
@@ -2731,7 +2707,7 @@ fn generalize_grades_a_candidate_across_two_instruments() {
"--stop-length", "14", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -2777,7 +2753,7 @@ fn generalize_real_e2e_pins_the_exact_current_grade() {
"--stop-length", "14", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -2834,7 +2810,7 @@ fn generalize_grades_a_non_r_sma_blueprint() {
"--stop-length", "14", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -2882,7 +2858,7 @@ fn walkforward_real_e2e_pins_the_exact_current_grade() {
"--stop-length", "14", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -2944,7 +2920,7 @@ fn walkforward_dissolves_a_non_r_sma_blueprint() {
"--stop-length", "14", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -3009,7 +2985,7 @@ fn walkforward_dissolved_accepts_select_plateau() {
"--select", "plateau:worst",
"--from", "1735689600000", "--to", "1747353600000",
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -3054,7 +3030,7 @@ fn walkforward_real_e2e_pins_the_exact_current_plateau_grade() {
"--from", FROM_MS, "--to", TO_MS,
"--select", "plateau:worst",
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -3109,7 +3085,7 @@ fn walkforward_dissolved_defaults_a_single_omitted_knob() {
"--stop-length", "3",
"--from", "1735689600000", "--to", "1747353600000",
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -3257,7 +3233,7 @@ fn walkforward_dissolves_through_the_campaign_path() {
"--stop-length", "14", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -3303,7 +3279,7 @@ fn walkforward_dissolves_through_the_campaign_path() {
let fams = std::process::Command::new(env!("CARGO_BIN_EXE_aura"))
.args(["runs", "families"])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn families");
let fams_out = String::from_utf8_lossy(&fams.stdout).into_owned();
@@ -3351,7 +3327,7 @@ fn walkforward_stopless_defaults_the_regime_byte_identically_to_explicit_3_2() {
"--axis", "sma_signal.fast.length=3", "--axis", "sma_signal.slow.length=12",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if stopless.status.code() == Some(1) {
@@ -3380,7 +3356,7 @@ fn walkforward_stopless_defaults_the_regime_byte_identically_to_explicit_3_2() {
"--stop-length", "3", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
assert_eq!(
@@ -3434,7 +3410,7 @@ fn generalize_dissolves_through_the_campaign_path() {
"--stop-length", "14", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -3485,7 +3461,7 @@ fn generalize_dissolves_through_the_campaign_path() {
// per-instrument Sweep family per cell (persisted by the executor).
let fams = std::process::Command::new(env!("CARGO_BIN_EXE_aura"))
.args(["runs", "families"])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn families");
let fams_out = String::from_utf8_lossy(&fams.stdout).into_owned();
@@ -3526,7 +3502,7 @@ fn generalize_repeated_identical_invocation_does_not_litter_the_store() {
"--stop-length", "14", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura")
};
@@ -3582,7 +3558,7 @@ fn generalize_distinct_invocations_persist_distinct_campaign_documents() {
"--stop-length", "14", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura")
};
@@ -3629,7 +3605,7 @@ fn generalize_without_explicit_window_resolves_a_shared_window_and_completes() {
"--axis", "sma_signal.fast.length=3", "--axis", "sma_signal.slow.length=12",
"--stop-length", "14", "--stop-k", "2.0",
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -3707,7 +3683,7 @@ fn generalize_without_explicit_window_resolves_the_intersection_of_all_symbols()
"--axis", "sma_signal.fast.length=3", "--axis", "sma_signal.slow.length=12",
"--name", name,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura sweep");
assert_eq!(
@@ -3739,7 +3715,7 @@ fn generalize_without_explicit_window_resolves_the_intersection_of_all_symbols()
"--axis", "sma_signal.fast.length=3", "--axis", "sma_signal.slow.length=12",
"--name", "gen-both",
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura generalize");
assert_eq!(
@@ -3919,7 +3895,7 @@ fn generalize_persists_a_discoverable_cross_instrument_family() {
"--stop-length", "14", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -3936,7 +3912,7 @@ fn generalize_persists_a_discoverable_cross_instrument_family() {
// the run persisted the per-instrument members as a discoverable CrossInstrument family.
let fams = std::process::Command::new(env!("CARGO_BIN_EXE_aura"))
.args(["runs", "families"])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn families");
assert!(fams.status.success(), "families exit: {:?}", fams.status);
@@ -3981,7 +3957,7 @@ fn generalize_family_members_are_attributed_to_the_right_instrument() {
"--stop-length", "14", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -3997,7 +3973,7 @@ fn generalize_family_members_are_attributed_to_the_right_instrument() {
let fam = std::process::Command::new(env!("CARGO_BIN_EXE_aura"))
.args(["runs", "family", "generalize-0"])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn runs family");
assert!(fam.status.success(), "runs family exit: {:?}", fam.status);
@@ -4048,7 +4024,7 @@ fn generalize_family_members_stamp_project_provenance() {
"--stop-length", "14", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -4064,7 +4040,7 @@ fn generalize_family_members_stamp_project_provenance() {
let fam = std::process::Command::new(env!("CARGO_BIN_EXE_aura"))
.args(["runs", "family", "generalize-0"])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn runs family");
assert!(fam.status.success(), "runs family exit: {:?}", fam.status);
@@ -5083,7 +5059,7 @@ fn mc_r_bootstrap_real_e2e_pins_the_exact_current_grade() {
"--block-len", "5", "--resamples", "1000", "--seed", "42",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -5140,7 +5116,7 @@ fn mc_dissolves_a_non_r_sma_blueprint() {
"--block-len", "5", "--resamples", "1000", "--seed", "42",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -5195,7 +5171,7 @@ fn mc_dissolves_through_the_campaign_path() {
"--block-len", "5", "--resamples", "1000", "--seed", "42",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -5249,7 +5225,7 @@ fn mc_dissolves_through_the_campaign_path() {
let fams = std::process::Command::new(env!("CARGO_BIN_EXE_aura"))
.args(["runs", "families"])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn families");
let fams_out = String::from_utf8_lossy(&fams.stdout).into_owned();
@@ -5305,7 +5281,7 @@ fn mc_real_fits_the_injected_roller_to_a_short_window() {
"--block-len", "5", "--resamples", "100", "--seed", "42",
"--from", SUB_FROM_MS, "--to", SUB_TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura mc");
@@ -5414,7 +5390,7 @@ fn mc_dissolved_seed_changes_the_bootstrap_draw_not_the_pooled_series() {
"--block-len", "5", "--resamples", "1000", "--seed", seed,
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura")
};
@@ -5475,7 +5451,7 @@ fn walkforward_campaign_runs_an_arbitrary_blueprint() {
"--stop-length", "3", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -5527,7 +5503,7 @@ fn mc_campaign_runs_an_arbitrary_blueprint() {
"--block-len", "5", "--resamples", "100", "--seed", "7",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -5576,7 +5552,7 @@ fn generalize_campaign_runs_an_arbitrary_blueprint() {
"--stop-length", "3", "--stop-k", "2.0",
"--from", GER40_SEPT2024_FROM_MS, "--to", GER40_SEPT2024_TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
+46 -16
View File
@@ -3,14 +3,11 @@
//! and drive the `tests/fixtures/demo-project` fixture through the real
//! `aura` binary (#223).
//!
//! **Process-local serialization only.** [`project_lock`]'s `Mutex` is a
//! per-process `static`: it serializes test THREADS within one test-binary
//! process, but grants no cross-process exclusion. A process-parallel test
//! runner (e.g. `cargo-nextest`, which forks one process per test binary) —
//! or simply two concurrent `cargo test` invocations over the same working
//! tree — still race on the shared `tests/fixtures/demo-project/runs` store.
//! That boundary is a known, documented limitation (#223), not something
//! this module claims to close.
//! **Per-test project directories, no shared store.** [`fresh_project`] mints
//! a unique tempdir per test, wired to the shared, once-built fixture crate
//! via an absolute `[nodes]` pointer (`project.rs`'s pointer-arm routing), so
//! no two tests ever race on the same `runs/` store — libtest's default
//! thread parallelism applies without a serializing lock (#250).
//!
//! Each of the three test binaries compiles this file as its own `mod
//! common`, so an item unused by one binary trips that binary's `-D
@@ -18,7 +15,8 @@
//! rather than deleting a helper just because one binary doesn't need it.
use std::path::{Path, PathBuf};
use std::sync::{Mutex, MutexGuard, OnceLock};
use std::sync::OnceLock;
use std::sync::atomic::{AtomicUsize, Ordering};
/// The demo-project fixture (`Aura.toml` present), built once per test-binary
/// process. Each test binary has its own `OnceLock` (this module is compiled
@@ -42,13 +40,45 @@ pub fn built_project() -> &'static PathBuf {
})
}
/// Serializes every test that touches the shared demo-project fixture store
/// (they remove/re-seed `<fixture>/runs`, so parallel test threads would race
/// on it). A poisoned lock is taken over: one failed test must not cascade
/// into unrelated lock panics.
pub fn project_lock() -> MutexGuard<'static, ()> {
static LOCK: Mutex<()> = Mutex::new(());
LOCK.lock().unwrap_or_else(|e| e.into_inner())
/// A per-test project directory, removed on drop (including mid-test panic).
#[allow(dead_code)]
pub struct FreshProject {
root: PathBuf,
}
impl Drop for FreshProject {
fn drop(&mut self) {
let _ = std::fs::remove_dir_all(&self.root);
}
}
/// Mint a unique tempdir holding a 2-line data-level project (`Aura.toml`
/// with an absolute `[nodes]` pointer at the shared, once-built fixture
/// crate) plus a copy of `demo_signal.json`. Every test gets its own `runs/`
/// store under this root, so no two tests ever contend for the same store —
/// this is what lets `project_lock` disappear (#250). Bind the guard for the
/// whole test body: `let (dir, _g) = fresh_project();`.
#[allow(dead_code)]
pub fn fresh_project() -> (PathBuf, FreshProject) {
static COUNTER: AtomicUsize = AtomicUsize::new(0);
let root = std::env::temp_dir().join(format!(
"aura-e2e-{}-{}",
std::process::id(),
COUNTER.fetch_add(1, Ordering::Relaxed)
));
std::fs::create_dir_all(&root).expect("create fresh project tempdir");
let fixture = built_project();
std::fs::write(
root.join("Aura.toml"),
format!(
"[paths]\nruns = \"runs\"\n\n[nodes]\ncrates = [\"{}\"]\n",
fixture.display()
),
)
.expect("write fresh project Aura.toml");
std::fs::copy(fixture.join("demo_signal.json"), root.join("demo_signal.json"))
.expect("copy demo_signal.json into the fresh project");
(root.clone(), FreshProject { root })
}
/// A scratch filesystem entry a test writes under the git-tracked
+1 -2
View File
@@ -9,7 +9,7 @@ use std::process::{Command, Output};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
mod common;
use common::{built_project, project_lock};
use common::built_project;
fn fixture_dir() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/demo-project")
@@ -98,7 +98,6 @@ fn outside_a_project_the_demo_blueprint_is_unknown() {
/// rather than shell-relative (C17).
#[test]
fn project_registry_anchors_at_discovered_root_not_invocation_cwd() {
let _fixture = project_lock();
let dir = built_project();
let sub = dir.join("src");
let runs_dir = dir.join("runs");
+172 -205
View File
@@ -5,7 +5,7 @@
use std::path::{Path, PathBuf};
mod common;
use common::{ScratchGuard, ScratchPath, built_project, project_lock};
use common::{ScratchGuard, ScratchPath, fresh_project};
/// A fresh, unique working directory for a process test that persists
/// content-addressed documents under `./runs/` (so `aura process register`
@@ -304,8 +304,7 @@ fn process_register_stores_content_addressed_under_runs_root() {
/// them together end to end.
#[test]
fn campaign_validate_in_project_reports_referential_tier_end_to_end() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -321,7 +320,7 @@ fn campaign_validate_in_project_reports_referential_tier_end_to_end() {
// test).
let closed_bp = format!("{}/examples/r_sma.json", env!("CARGO_MANIFEST_DIR"));
let (sweep_out, sweep_code) = run_code_in(
dir,
&dir,
&[
"sweep",
&closed_bp,
@@ -360,8 +359,8 @@ fn campaign_validate_in_project_reports_referential_tier_end_to_end() {
// overfit_probability (not per-member) flip to a per-member scalar.
.replacen("\"overfit_probability\", \"cmp\": \"lt\", \"value\": 0.1", "\"win_rate\", \"cmp\": \"lt\", \"value\": 1.1", 1);
assert_ne!(exec_process, PROCESS_DOC, "replacen must match the sweep stage");
write_doc(dir, "seed.process.json", &exec_process);
let (proc_out, proc_code) = run_code_in(dir, &["process", "register", "seed.process.json"]);
write_doc(&dir, "seed.process.json", &exec_process);
let (proc_out, proc_code) = run_code_in(&dir, &["process", "register", "seed.process.json"]);
assert_eq!(proc_code, Some(0), "seed process register failed: {proc_out}");
let proc_id = proc_out
.lines()
@@ -394,8 +393,8 @@ fn campaign_validate_in_project_reports_referential_tier_end_to_end() {
bp = bp_id,
proc = proc_id
);
write_doc(dir, "ref-ok.campaign.json", &campaign);
let (out, code) = run_code_in(dir, &["campaign", "validate", "ref-ok.campaign.json"]);
write_doc(&dir, "ref-ok.campaign.json", &campaign);
let (out, code) = run_code_in(&dir, &["campaign", "validate", "ref-ok.campaign.json"]);
assert_eq!(code, Some(0), "stdout/stderr: {out}");
assert!(out.contains(
"campaign document valid (referential): all references resolve, axes are in the param space"
@@ -404,8 +403,8 @@ fn campaign_validate_in_project_reports_referential_tier_end_to_end() {
// An unresolved process reference: the fault block + `ref_fault_prose`
// mapping, prose exit 1, at the same CLI seam.
let bad = campaign.replace(&proc_id, "0000000000000000000000000000000000000000000000000000000000000000");
write_doc(dir, "ref-bad.campaign.json", &bad);
let (out2, code2) = run_code_in(dir, &["campaign", "validate", "ref-bad.campaign.json"]);
write_doc(&dir, "ref-bad.campaign.json", &bad);
let (out2, code2) = run_code_in(&dir, &["campaign", "validate", "ref-bad.campaign.json"]);
assert_eq!(code2, Some(1));
assert!(out2.contains("campaign references do not resolve:"), "stdout/stderr: {out2}");
assert!(out2.contains("not found in the project store"), "stdout/stderr: {out2}");
@@ -1129,9 +1128,8 @@ fn campaign_run_outside_project_refuses() {
/// both readings (inside the project, past the project gate).
#[test]
fn campaign_run_bogus_target_refuses() {
let _fixture = project_lock();
let dir = built_project();
let (out, code) = run_code_in(dir, &["campaign", "run", "no-such-target"]);
let (dir, _fixture) = fresh_project();
let (out, code) = run_code_in(&dir, &["campaign", "run", "no-such-target"]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
assert!(
out.contains("'no-such-target' is neither a readable .json file nor a 64-hex content id"),
@@ -1142,10 +1140,9 @@ fn campaign_run_bogus_target_refuses() {
/// A well-formed but unknown content id refuses with the store-miss prose.
#[test]
fn campaign_run_unknown_id_refuses() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let id = "0".repeat(64);
let (out, code) = run_code_in(dir, &["campaign", "run", &id]);
let (out, code) = run_code_in(&dir, &["campaign", "run", &id]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
assert!(
out.contains(&format!("no campaign {id} in the project store")),
@@ -1169,8 +1166,7 @@ fn campaign_run_unknown_id_refuses() {
/// bare-store-line contract exactly.
#[test]
fn campaign_runs_lists_and_dumps_the_bare_stored_record() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
std::fs::create_dir_all(&runs_dir).expect("create runs dir");
@@ -1185,7 +1181,7 @@ fn campaign_runs_lists_and_dumps_the_bare_stored_record() {
// LIST mode: one scannable line per stored record, carrying the campaign
// id (bare 64-hex or a prefix), exit 0.
let (list_out, list_code) = run_code_in(dir, &["campaign", "runs"]);
let (list_out, list_code) = run_code_in(&dir, &["campaign", "runs"]);
assert_eq!(list_code, Some(0), "list exits 0: {list_out}");
assert!(
list_out.contains(&campaign_id[..8]),
@@ -1195,7 +1191,7 @@ fn campaign_runs_lists_and_dumps_the_bare_stored_record() {
// DUMP mode: addressed by the campaign content id, prints the BARE stored
// record line — the store form, NOT the `{{"campaign_run": …}}` run-emit
// wrapper (F10) — byte-identical to the seeded line, exit 0.
let (dump_out, dump_code) = run_code_in(dir, &["campaign", "runs", &campaign_id]);
let (dump_out, dump_code) = run_code_in(&dir, &["campaign", "runs", &campaign_id]);
assert_eq!(dump_code, Some(0), "dump exits 0: {dump_out}");
assert!(
!dump_out.contains("\"campaign_run\""),
@@ -1221,8 +1217,7 @@ fn campaign_runs_lists_and_dumps_the_bare_stored_record() {
/// depends on.
#[test]
fn campaign_runs_dump_round_trips_a_populated_trace_name() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
std::fs::create_dir_all(&runs_dir).expect("create runs dir");
@@ -1235,7 +1230,7 @@ fn campaign_runs_dump_round_trips_a_populated_trace_name() {
std::fs::write(runs_dir.join("campaign_runs.jsonl"), format!("{record_line}\n"))
.expect("seed the campaign-run store");
let (dump_out, dump_code) = run_code_in(dir, &["campaign", "runs", &campaign_id]);
let (dump_out, dump_code) = run_code_in(&dir, &["campaign", "runs", &campaign_id]);
assert_eq!(dump_code, Some(0), "dump exits 0: {dump_out}");
assert_eq!(
dump_out.trim(),
@@ -1254,8 +1249,7 @@ fn campaign_runs_dump_round_trips_a_populated_trace_name() {
/// runs, with Debug-free PipelineShape prose.
#[test]
fn campaign_run_refuses_mc_before_walk_forward() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -1263,10 +1257,10 @@ fn campaign_run_refuses_mc_before_walk_forward() {
ScratchPath::File(dir.join("mcwf.process.json")),
ScratchPath::File(dir.join("mcwf.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-mcwf-seed");
let proc_id = register_process_doc(dir, "mcwf.process.json", MC_BEFORE_WF_PROCESS_DOC);
write_doc(dir, "mcwf.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (out, code) = run_code_in(dir, &["campaign", "run", "mcwf.campaign.json"]);
let bp_id = seed_blueprint(&dir, "campaign-run-mcwf-seed");
let proc_id = register_process_doc(&dir, "mcwf.process.json", MC_BEFORE_WF_PROCESS_DOC);
write_doc(&dir, "mcwf.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (out, code) = run_code_in(&dir, &["campaign", "run", "mcwf.campaign.json"]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
assert!(out.contains("process pipeline is not executable:"), "stdout/stderr: {out}");
assert!(
@@ -1304,8 +1298,7 @@ const SELECTION_FREE_SWEEP_THEN_GATE_PROCESS_DOC: &str = r#"{
/// nothing for a following stage to consume).
#[test]
fn campaign_run_refuses_a_non_terminal_selection_free_sweep() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -1313,11 +1306,11 @@ fn campaign_run_refuses_a_non_terminal_selection_free_sweep() {
ScratchPath::File(dir.join("selfree.process.json")),
ScratchPath::File(dir.join("selfree.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-selfree-seed");
let bp_id = seed_blueprint(&dir, "campaign-run-selfree-seed");
let proc_id =
register_process_doc(dir, "selfree.process.json", SELECTION_FREE_SWEEP_THEN_GATE_PROCESS_DOC);
write_doc(dir, "selfree.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (out, code) = run_code_in(dir, &["campaign", "run", "selfree.campaign.json"]);
register_process_doc(&dir, "selfree.process.json", SELECTION_FREE_SWEEP_THEN_GATE_PROCESS_DOC);
write_doc(&dir, "selfree.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (out, code) = run_code_in(&dir, &["campaign", "run", "selfree.campaign.json"]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
assert!(
out.contains(
@@ -1344,8 +1337,7 @@ const SELECTION_FREE_SWEEP_ONLY_PROCESS_DOC: &str = r#"{
#[test]
fn campaign_validate_accepts_a_terminal_selection_free_sweep() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -1353,15 +1345,15 @@ fn campaign_validate_accepts_a_terminal_selection_free_sweep() {
ScratchPath::File(dir.join("selfreeonly.process.json")),
ScratchPath::File(dir.join("selfreeonly.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-validate-selfreeonly-seed");
let bp_id = seed_blueprint(&dir, "campaign-validate-selfreeonly-seed");
let proc_id =
register_process_doc(dir, "selfreeonly.process.json", SELECTION_FREE_SWEEP_ONLY_PROCESS_DOC);
register_process_doc(&dir, "selfreeonly.process.json", SELECTION_FREE_SWEEP_ONLY_PROCESS_DOC);
write_doc(
dir,
&dir,
"selfreeonly.campaign.json",
&campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""),
);
let (out, code) = run_code_in(dir, &["campaign", "validate", "selfreeonly.campaign.json"]);
let (out, code) = run_code_in(&dir, &["campaign", "validate", "selfreeonly.campaign.json"]);
assert_eq!(code, Some(0), "a terminal selection-free sweep validates as executable: {out}");
assert!(
out.contains("campaign document valid (executable): pipeline shape and static guards pass"),
@@ -1378,8 +1370,7 @@ fn campaign_validate_accepts_a_terminal_selection_free_sweep() {
/// single-instrument, and this refusal is data-free by construction).
#[test]
fn campaign_run_refuses_single_instrument_generalize() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -1387,10 +1378,10 @@ fn campaign_run_refuses_single_instrument_generalize() {
ScratchPath::File(dir.join("gen1.process.json")),
ScratchPath::File(dir.join("gen1.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-gen1-seed");
let proc_id = register_process_doc(dir, "gen1.process.json", GENERALIZE_PROCESS_DOC);
write_doc(dir, "gen1.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (out, code) = run_code_in(dir, &["campaign", "run", "gen1.campaign.json"]);
let bp_id = seed_blueprint(&dir, "campaign-run-gen1-seed");
let proc_id = register_process_doc(&dir, "gen1.process.json", GENERALIZE_PROCESS_DOC);
write_doc(&dir, "gen1.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (out, code) = run_code_in(&dir, &["campaign", "run", "gen1.campaign.json"]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
assert!(
out.contains("std::generalize needs at least 2"),
@@ -1423,8 +1414,7 @@ const GENERALIZE_NON_R_PROCESS_DOC: &str = r#"{
/// would silently accept a pip-denominated `std::generalize`.
#[test]
fn campaign_run_refuses_generalize_non_r_metric() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -1432,8 +1422,8 @@ fn campaign_run_refuses_generalize_non_r_metric() {
ScratchPath::File(dir.join("genpip.process.json")),
ScratchPath::File(dir.join("genpip.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-genpip-seed");
let proc_id = register_process_doc(dir, "genpip.process.json", GENERALIZE_NON_R_PROCESS_DOC);
let bp_id = seed_blueprint(&dir, "campaign-run-genpip-seed");
let proc_id = register_process_doc(&dir, "genpip.process.json", GENERALIZE_NON_R_PROCESS_DOC);
// Two instruments (arity passes), so the metric guard is the one that
// actually fires. The [1, 2] 1970 window never matters: this refusal is
// data-free, before any member runs.
@@ -1451,8 +1441,8 @@ fn campaign_run_refuses_generalize_non_r_metric() {
"presentation": {{ "persist_taps": [], "emit": [] }}
}}"#
);
write_doc(dir, "genpip.campaign.json", &campaign_doc);
let (out, code) = run_code_in(dir, &["campaign", "run", "genpip.campaign.json"]);
write_doc(&dir, "genpip.campaign.json", &campaign_doc);
let (out, code) = run_code_in(&dir, &["campaign", "run", "genpip.campaign.json"]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
// #207 (fieldtest 0108 F8): the refusal names the REAL rule (the rankable
// R-expectancy family), never the mislabel "pip metric" — max_r_drawdown is
@@ -1505,8 +1495,7 @@ fn process_validate_permits_wf_after_mc_but_campaign_run_refuses_it() {
);
// executor tier: campaign run's v2 preflight refuses the same shape.
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -1514,10 +1503,10 @@ fn process_validate_permits_wf_after_mc_but_campaign_run_refuses_it() {
ScratchPath::File(dir.join("wfmc.process.json")),
ScratchPath::File(dir.join("wfmc.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-wfmc-seed");
let proc_id = register_process_doc(dir, "wfmc.process.json", WF_AFTER_MC_PROCESS_DOC);
write_doc(dir, "wfmc.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (out, code) = run_code_in(dir, &["campaign", "run", "wfmc.campaign.json"]);
let bp_id = seed_blueprint(&dir, "campaign-run-wfmc-seed");
let proc_id = register_process_doc(&dir, "wfmc.process.json", WF_AFTER_MC_PROCESS_DOC);
write_doc(&dir, "wfmc.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (out, code) = run_code_in(&dir, &["campaign", "run", "wfmc.campaign.json"]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
assert!(
out.contains("std::walk_forward cannot follow std::monte_carlo"),
@@ -1545,8 +1534,7 @@ fn process_validate_permits_wf_after_mc_but_campaign_run_refuses_it() {
/// shape validate clean (exit 0), the F6 friction.
#[test]
fn campaign_validate_runs_the_executor_preflight_as_a_third_tier() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -1556,15 +1544,15 @@ fn campaign_validate_runs_the_executor_preflight_as_a_third_tier() {
ScratchPath::File(dir.join("wfmc.process.json")),
ScratchPath::File(dir.join("wfmc.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-validate-3tier-seed");
let bp_id = seed_blueprint(&dir, "campaign-validate-3tier-seed");
// Face 1 — the happy path: an executable pipeline shape (a bare
// std::sweep). Intrinsic + referential pass today (exit 0), but the
// executor tier is invisible; after #205 validate gains the third
// "valid (executable)" line while staying exit 0.
let ok_proc = register_process_doc(dir, "runnable.process.json", SWEEP_ONLY_PROCESS_DOC);
write_doc(dir, "runnable.campaign.json", &campaign_doc_json(&bp_id, &ok_proc, (1, 2), "", ""));
let (ok_out, ok_code) = run_code_in(dir, &["campaign", "validate", "runnable.campaign.json"]);
let ok_proc = register_process_doc(&dir, "runnable.process.json", SWEEP_ONLY_PROCESS_DOC);
write_doc(&dir, "runnable.campaign.json", &campaign_doc_json(&bp_id, &ok_proc, (1, 2), "", ""));
let (ok_out, ok_code) = run_code_in(&dir, &["campaign", "validate", "runnable.campaign.json"]);
assert_eq!(ok_code, Some(0), "an executable campaign validates clean: {ok_out}");
assert!(
ok_out.contains("campaign document valid (referential): all references resolve"),
@@ -1583,9 +1571,9 @@ fn campaign_validate_runs_the_executor_preflight_as_a_third_tier() {
// reaches the third tier — which refuses the non-executable shape at
// validate time (data-free: the [1, 2] 1970-epoch-ms window is never
// reached), exit 1, with the executor fault header + the shape prose.
let bad_proc = register_process_doc(dir, "wfmc.process.json", WF_AFTER_MC_PROCESS_DOC);
write_doc(dir, "wfmc.campaign.json", &campaign_doc_json(&bp_id, &bad_proc, (1, 2), "", ""));
let (bad_out, bad_code) = run_code_in(dir, &["campaign", "validate", "wfmc.campaign.json"]);
let bad_proc = register_process_doc(&dir, "wfmc.process.json", WF_AFTER_MC_PROCESS_DOC);
write_doc(&dir, "wfmc.campaign.json", &campaign_doc_json(&bp_id, &bad_proc, (1, 2), "", ""));
let (bad_out, bad_code) = run_code_in(&dir, &["campaign", "validate", "wfmc.campaign.json"]);
assert_eq!(bad_code, Some(1), "an executor-unrunnable shape refuses at validate: {bad_out}");
assert!(
bad_out.contains("campaign is not executable:"),
@@ -1639,8 +1627,7 @@ const WF_PLATEAU_GATED_PROCESS_DOC: &str = r#"{
/// exit 0 — either direction goes red here.
#[test]
fn campaign_validate_narrows_plateau_in_wf_refusal_to_gate_preceded_stages() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -1650,19 +1637,19 @@ fn campaign_validate_narrows_plateau_in_wf_refusal_to_gate_preceded_stages() {
ScratchPath::File(dir.join("wf-plateau-gated.process.json")),
ScratchPath::File(dir.join("wf-plateau-gated.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-validate-wf-plateau-seed");
let bp_id = seed_blueprint(&dir, "campaign-validate-wf-plateau-seed");
// Face 1 — gate-free: sweep -> walk_forward(plateau:worst). The lattice
// is intact, so the executor tier accepts it (exit 0).
let free_id =
register_process_doc(dir, "wf-plateau-free.process.json", WF_PLATEAU_GATE_FREE_PROCESS_DOC);
register_process_doc(&dir, "wf-plateau-free.process.json", WF_PLATEAU_GATE_FREE_PROCESS_DOC);
write_doc(
dir,
&dir,
"wf-plateau-free.campaign.json",
&campaign_doc_json(&bp_id, &free_id, (1, 2), "", ""),
);
let (free_out, free_code) =
run_code_in(dir, &["campaign", "validate", "wf-plateau-free.campaign.json"]);
run_code_in(&dir, &["campaign", "validate", "wf-plateau-free.campaign.json"]);
assert_eq!(free_code, Some(0), "gate-free plateau walk_forward validates clean: {free_out}");
assert!(
free_out.contains(
@@ -1675,14 +1662,14 @@ fn campaign_validate_narrows_plateau_in_wf_refusal_to_gate_preceded_stages() {
// The gate can break the lattice, so the executor tier still refuses it
// (exit 1), naming the offending stage.
let gated_id =
register_process_doc(dir, "wf-plateau-gated.process.json", WF_PLATEAU_GATED_PROCESS_DOC);
register_process_doc(&dir, "wf-plateau-gated.process.json", WF_PLATEAU_GATED_PROCESS_DOC);
write_doc(
dir,
&dir,
"wf-plateau-gated.campaign.json",
&campaign_doc_json(&bp_id, &gated_id, (1, 2), "", ""),
);
let (gated_out, gated_code) =
run_code_in(dir, &["campaign", "validate", "wf-plateau-gated.campaign.json"]);
run_code_in(&dir, &["campaign", "validate", "wf-plateau-gated.campaign.json"]);
assert_eq!(gated_code, Some(1), "gate-preceded plateau walk_forward still refuses: {gated_out}");
assert!(
gated_out.contains("campaign is not executable:"),
@@ -1717,8 +1704,7 @@ const ZERO_RESAMPLES_MC_PROCESS_DOC: &str = r#"{
/// would let this refusal disappear or drift to a different message.
#[test]
fn campaign_run_refuses_zero_resamples_monte_carlo_before_any_member_runs() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -1726,10 +1712,10 @@ fn campaign_run_refuses_zero_resamples_monte_carlo_before_any_member_runs() {
ScratchPath::File(dir.join("zeromc.process.json")),
ScratchPath::File(dir.join("zeromc.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-zeromc-seed");
let proc_id = register_process_doc(dir, "zeromc.process.json", ZERO_RESAMPLES_MC_PROCESS_DOC);
write_doc(dir, "zeromc.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (out, code) = run_code_in(dir, &["campaign", "run", "zeromc.campaign.json"]);
let bp_id = seed_blueprint(&dir, "campaign-run-zeromc-seed");
let proc_id = register_process_doc(&dir, "zeromc.process.json", ZERO_RESAMPLES_MC_PROCESS_DOC);
write_doc(&dir, "zeromc.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (out, code) = run_code_in(&dir, &["campaign", "run", "zeromc.campaign.json"]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
assert!(
out.contains("process stage 1: monte_carlo resamples must be > 0"),
@@ -1749,8 +1735,7 @@ fn campaign_run_refuses_zero_resamples_monte_carlo_before_any_member_runs() {
/// pinned here.
#[test]
fn campaign_run_refuses_unknown_tap_at_validate() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -1758,14 +1743,14 @@ fn campaign_run_refuses_unknown_tap_at_validate() {
ScratchPath::File(dir.join("badtap.process.json")),
ScratchPath::File(dir.join("badtap.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-badtap-seed");
let proc_id = register_process_doc(dir, "badtap.process.json", SWEEP_ONLY_PROCESS_DOC);
let bp_id = seed_blueprint(&dir, "campaign-run-badtap-seed");
let proc_id = register_process_doc(&dir, "badtap.process.json", SWEEP_ONLY_PROCESS_DOC);
write_doc(
dir,
&dir,
"badtap.campaign.json",
&campaign_doc_json(&bp_id, &proc_id, (1, 2), "\"r_record\"", ""),
);
let (out, code) = run_code_in(dir, &["campaign", "run", "badtap.campaign.json"]);
let (out, code) = run_code_in(&dir, &["campaign", "run", "badtap.campaign.json"]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
assert!(out.contains("campaign document invalid:"), "stdout/stderr: {out}");
assert!(
@@ -1794,8 +1779,7 @@ fn campaign_run_refuses_unknown_tap_at_validate() {
/// tightens this test to pin its absence.
#[test]
fn campaign_run_valid_tap_reaches_the_member_data_seam() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -1803,14 +1787,14 @@ fn campaign_run_valid_tap_reaches_the_member_data_seam() {
ScratchPath::File(dir.join("taps.process.json")),
ScratchPath::File(dir.join("taps.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-taps-seed");
let proc_id = register_process_doc(dir, "taps.process.json", SWEEP_ONLY_PROCESS_DOC);
let bp_id = seed_blueprint(&dir, "campaign-run-taps-seed");
let proc_id = register_process_doc(&dir, "taps.process.json", SWEEP_ONLY_PROCESS_DOC);
write_doc(
dir,
&dir,
"taps.campaign.json",
&campaign_doc_json(&bp_id, &proc_id, (1, 2), "\"equity\"", ""),
);
let (out, code) = run_code_in(dir, &["campaign", "run", "taps.campaign.json"]);
let (out, code) = run_code_in(&dir, &["campaign", "run", "taps.campaign.json"]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
assert!(
!out.contains("unknown tap"),
@@ -1849,8 +1833,7 @@ fn campaign_run_valid_tap_reaches_the_member_data_seam() {
/// stays green on a data-less machine.
#[test]
fn campaign_run_real_e2e_sweep_gate_walkforward() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -1858,12 +1841,12 @@ fn campaign_run_real_e2e_sweep_gate_walkforward() {
ScratchPath::File(dir.join("wf.process.json")),
ScratchPath::File(dir.join("wf.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-e2e-seed");
let proc_id = register_process_doc(dir, "wf.process.json", WF_PROCESS_DOC);
let bp_id = seed_blueprint(&dir, "campaign-run-e2e-seed");
let proc_id = register_process_doc(&dir, "wf.process.json", WF_PROCESS_DOC);
// The GER40 Sept-2024 window (inclusive Unix-ms) — the same gated window
// cli_run.rs drives; ~30 days, so the (14d, 7d, 7d) roller tiles it.
write_doc(
dir,
&dir,
"wf.campaign.json",
&campaign_doc_json(
&bp_id,
@@ -1873,7 +1856,7 @@ fn campaign_run_real_e2e_sweep_gate_walkforward() {
"\"family_table\", \"selection_report\"",
),
);
let (out, code) = run_code_in(dir, &["campaign", "run", "wf.campaign.json"]);
let (out, code) = run_code_in(&dir, &["campaign", "run", "wf.campaign.json"]);
// Skip on a data-less machine: the member-data refusal, never a panic.
if code == Some(1)
@@ -1999,7 +1982,7 @@ fn campaign_run_real_e2e_sweep_gate_walkforward() {
// The shipped viewer reads the member back (the cli_run.rs chart
// idiom): exit 0 and an HTML page carrying both persisted tap series.
let (chart_out, chart_code) =
run_code_in(dir, &["chart", &format!("{trace_name}/{cell_key}")]);
run_code_in(&dir, &["chart", &format!("{trace_name}/{cell_key}")]);
assert_eq!(chart_code, Some(0), "aura chart reads the persisted member: {chart_out}");
assert!(
chart_out.contains("\"equity\"") && chart_out.contains("\"r_equity\""),
@@ -2015,8 +1998,7 @@ fn campaign_run_real_e2e_sweep_gate_walkforward() {
/// Gated on the local GER40 archive; skips cleanly when absent.
#[test]
fn campaign_run_real_e2e_bindings_override_rebinds_price_to_open() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -2025,8 +2007,8 @@ fn campaign_run_real_e2e_bindings_override_rebinds_price_to_open() {
ScratchPath::File(dir.join("close.campaign.json")),
ScratchPath::File(dir.join("open.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "binding-override-seed");
let proc_id = register_process_doc(dir, "sweep.process.json", SWEEP_ONLY_PROCESS_DOC);
let bp_id = seed_blueprint(&dir, "binding-override-seed");
let proc_id = register_process_doc(&dir, "sweep.process.json", SWEEP_ONLY_PROCESS_DOC);
let base = campaign_doc_json(
&bp_id,
&proc_id,
@@ -2039,10 +2021,10 @@ fn campaign_run_real_e2e_bindings_override_rebinds_price_to_open() {
r#""data": { "bindings": { "price": "open" }, "instruments": ["GER40"],"#,
);
assert_ne!(rebound, base, "the override splice must hit the data section");
write_doc(dir, "close.campaign.json", &base);
write_doc(dir, "open.campaign.json", &rebound);
write_doc(&dir, "close.campaign.json", &base);
write_doc(&dir, "open.campaign.json", &rebound);
let (out_close, code_close) = run_code_in(dir, &["campaign", "run", "close.campaign.json"]);
let (out_close, code_close) = run_code_in(&dir, &["campaign", "run", "close.campaign.json"]);
if code_close == Some(1)
&& (out_close.contains("no recorded geometry") || out_close.contains("no data for instrument"))
{
@@ -2050,7 +2032,7 @@ fn campaign_run_real_e2e_bindings_override_rebinds_price_to_open() {
return;
}
assert_eq!(code_close, Some(0), "stdout/stderr: {out_close}");
let (out_open, code_open) = run_code_in(dir, &["campaign", "run", "open.campaign.json"]);
let (out_open, code_open) = run_code_in(&dir, &["campaign", "run", "open.campaign.json"]);
assert_eq!(code_open, Some(0), "stdout/stderr: {out_open}");
let first_member = |out: &str| -> serde_json::Value {
@@ -2081,8 +2063,7 @@ fn campaign_run_real_e2e_bindings_override_rebinds_price_to_open() {
/// above; skips on a data-less host.
#[test]
fn campaign_run_real_e2e_non_default_regime_stamps_its_own_stop() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -2090,8 +2071,8 @@ fn campaign_run_real_e2e_non_default_regime_stamps_its_own_stop() {
ScratchPath::File(dir.join("regime.process.json")),
ScratchPath::File(dir.join("regime.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-regime-seed");
let proc_id = register_process_doc(dir, "regime.process.json", SWEEP_ONLY_PROCESS_DOC);
let bp_id = seed_blueprint(&dir, "campaign-run-regime-seed");
let proc_id = register_process_doc(&dir, "regime.process.json", SWEEP_ONLY_PROCESS_DOC);
let base = campaign_doc_json(
&bp_id,
&proc_id,
@@ -2105,8 +2086,8 @@ fn campaign_run_real_e2e_non_default_regime_stamps_its_own_stop() {
1,
);
assert_ne!(with_regime, base, "replacen must actually match the fixture's seed field");
write_doc(dir, "regime.campaign.json", &with_regime);
let (out, code) = run_code_in(dir, &["campaign", "run", "regime.campaign.json"]);
write_doc(&dir, "regime.campaign.json", &with_regime);
let (out, code) = run_code_in(&dir, &["campaign", "run", "regime.campaign.json"]);
if code == Some(1)
&& (out.contains("no recorded geometry") || out.contains("no data for instrument"))
@@ -2151,8 +2132,7 @@ fn campaign_run_real_e2e_non_default_regime_stamps_its_own_stop() {
/// on the local GER40 archive like its siblings; skips on a data-less host.
#[test]
fn campaign_run_real_e2e_two_regimes_each_stamp_their_own_stop() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -2160,8 +2140,8 @@ fn campaign_run_real_e2e_two_regimes_each_stamp_their_own_stop() {
ScratchPath::File(dir.join("tworegimes.process.json")),
ScratchPath::File(dir.join("tworegimes.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-two-regimes-seed");
let proc_id = register_process_doc(dir, "tworegimes.process.json", SWEEP_ONLY_PROCESS_DOC);
let bp_id = seed_blueprint(&dir, "campaign-run-two-regimes-seed");
let proc_id = register_process_doc(&dir, "tworegimes.process.json", SWEEP_ONLY_PROCESS_DOC);
let base = campaign_doc_json(
&bp_id,
&proc_id,
@@ -2176,8 +2156,8 @@ fn campaign_run_real_e2e_two_regimes_each_stamp_their_own_stop() {
1,
);
assert_ne!(with_regimes, base, "replacen must actually match the fixture's seed field");
write_doc(dir, "tworegimes.campaign.json", &with_regimes);
let (out, code) = run_code_in(dir, &["campaign", "run", "tworegimes.campaign.json"]);
write_doc(&dir, "tworegimes.campaign.json", &with_regimes);
let (out, code) = run_code_in(&dir, &["campaign", "run", "tworegimes.campaign.json"]);
if code == Some(1)
&& (out.contains("no recorded geometry") || out.contains("no data for instrument"))
@@ -2236,8 +2216,7 @@ fn campaign_run_real_e2e_two_regimes_each_stamp_their_own_stop() {
/// archive like its siblings; skips on a data-less host.
#[test]
fn campaign_persist_non_default_regime_does_not_false_fail_c1() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -2245,9 +2224,9 @@ fn campaign_persist_non_default_regime_does_not_false_fail_c1() {
ScratchPath::File(dir.join("regime-persist.process.json")),
ScratchPath::File(dir.join("regime-persist.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-persist-regime-seed");
let bp_id = seed_blueprint(&dir, "campaign-persist-regime-seed");
let proc_id =
register_process_doc(dir, "regime-persist.process.json", SWEEP_ONLY_PROCESS_DOC);
register_process_doc(&dir, "regime-persist.process.json", SWEEP_ONLY_PROCESS_DOC);
let base = campaign_doc_json(
&bp_id,
&proc_id,
@@ -2264,8 +2243,8 @@ fn campaign_persist_non_default_regime_does_not_false_fail_c1() {
1,
);
assert_ne!(with_regime, base, "replacen must actually match the fixture's seed field");
write_doc(dir, "regime-persist.campaign.json", &with_regime);
let (out, code) = run_code_in(dir, &["campaign", "run", "regime-persist.campaign.json"]);
write_doc(&dir, "regime-persist.campaign.json", &with_regime);
let (out, code) = run_code_in(&dir, &["campaign", "run", "regime-persist.campaign.json"]);
// Skip on a data-less machine: the member-data refusal, never a panic.
if code == Some(1)
@@ -2321,8 +2300,7 @@ fn campaign_persist_non_default_regime_does_not_false_fail_c1() {
/// the local GER40 archive; skips on a data-less host.
#[test]
fn campaign_run_real_e2e_costed_campaign_persists_without_drift_alarm() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -2330,8 +2308,8 @@ fn campaign_run_real_e2e_costed_campaign_persists_without_drift_alarm() {
ScratchPath::File(dir.join("cost-persist.process.json")),
ScratchPath::File(dir.join("cost-persist.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-persist-cost-seed");
let proc_id = register_process_doc(dir, "cost-persist.process.json", SWEEP_ONLY_PROCESS_DOC);
let bp_id = seed_blueprint(&dir, "campaign-persist-cost-seed");
let proc_id = register_process_doc(&dir, "cost-persist.process.json", SWEEP_ONLY_PROCESS_DOC);
let base = campaign_doc_json(
&bp_id,
&proc_id,
@@ -2345,8 +2323,8 @@ fn campaign_run_real_e2e_costed_campaign_persists_without_drift_alarm() {
1,
);
assert_ne!(with_cost, base, "replacen must actually match the fixture's seed field");
write_doc(dir, "cost-persist.campaign.json", &with_cost);
let (out, code) = run_code_in(dir, &["campaign", "run", "cost-persist.campaign.json"]);
write_doc(&dir, "cost-persist.campaign.json", &with_cost);
let (out, code) = run_code_in(&dir, &["campaign", "run", "cost-persist.campaign.json"]);
// Skip on a data-less machine: the member-data refusal, never a panic.
if code == Some(1)
@@ -2417,8 +2395,7 @@ fn campaign_run_real_e2e_costed_campaign_persists_without_drift_alarm() {
/// archive; skips on a data-less host.
#[test]
fn campaign_run_real_e2e_net_r_equity_tap_persists_the_cost_adjusted_curve() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -2426,8 +2403,8 @@ fn campaign_run_real_e2e_net_r_equity_tap_persists_the_cost_adjusted_curve() {
ScratchPath::File(dir.join("net-persist.process.json")),
ScratchPath::File(dir.join("net-persist.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-persist-net-seed");
let proc_id = register_process_doc(dir, "net-persist.process.json", SWEEP_ONLY_PROCESS_DOC);
let bp_id = seed_blueprint(&dir, "campaign-persist-net-seed");
let proc_id = register_process_doc(&dir, "net-persist.process.json", SWEEP_ONLY_PROCESS_DOC);
let base = campaign_doc_json(
&bp_id,
&proc_id,
@@ -2441,8 +2418,8 @@ fn campaign_run_real_e2e_net_r_equity_tap_persists_the_cost_adjusted_curve() {
1,
);
assert_ne!(with_cost, base, "replacen must actually match the fixture's seed field");
write_doc(dir, "net-persist.campaign.json", &with_cost);
let (out, code) = run_code_in(dir, &["campaign", "run", "net-persist.campaign.json"]);
write_doc(&dir, "net-persist.campaign.json", &with_cost);
let (out, code) = run_code_in(&dir, &["campaign", "run", "net-persist.campaign.json"]);
// Skip on a data-less machine: the member-data refusal, never a panic.
if code == Some(1)
@@ -2531,8 +2508,7 @@ fn campaign_run_real_e2e_net_r_equity_tap_persists_the_cost_adjusted_curve() {
/// wired). Gated on the local GER40 archive; skips on a data-less host.
#[test]
fn campaign_run_real_e2e_vol_slippage_cost_persists_without_drift_alarm() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -2540,9 +2516,9 @@ fn campaign_run_real_e2e_vol_slippage_cost_persists_without_drift_alarm() {
ScratchPath::File(dir.join("volcost-persist.process.json")),
ScratchPath::File(dir.join("volcost-persist.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-persist-volcost-seed");
let bp_id = seed_blueprint(&dir, "campaign-persist-volcost-seed");
let proc_id =
register_process_doc(dir, "volcost-persist.process.json", SWEEP_ONLY_PROCESS_DOC);
register_process_doc(&dir, "volcost-persist.process.json", SWEEP_ONLY_PROCESS_DOC);
let base = campaign_doc_json(
&bp_id,
&proc_id,
@@ -2556,8 +2532,8 @@ fn campaign_run_real_e2e_vol_slippage_cost_persists_without_drift_alarm() {
1,
);
assert_ne!(with_cost, base, "replacen must actually match the fixture's seed field");
write_doc(dir, "volcost-persist.campaign.json", &with_cost);
let (out, code) = run_code_in(dir, &["campaign", "run", "volcost-persist.campaign.json"]);
write_doc(&dir, "volcost-persist.campaign.json", &with_cost);
let (out, code) = run_code_in(&dir, &["campaign", "run", "volcost-persist.campaign.json"]);
// Skip on a data-less machine: the member-data refusal, never a panic.
if code == Some(1)
@@ -2617,8 +2593,7 @@ fn campaign_run_real_e2e_vol_slippage_cost_persists_without_drift_alarm() {
/// into one dir. Gated on the local GER40 archive; skips on a data-less host.
#[test]
fn campaign_persist_two_regimes_land_in_distinct_trace_dirs() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -2626,9 +2601,9 @@ fn campaign_persist_two_regimes_land_in_distinct_trace_dirs() {
ScratchPath::File(dir.join("tworegimes-persist.process.json")),
ScratchPath::File(dir.join("tworegimes-persist.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-persist-two-regimes-seed");
let bp_id = seed_blueprint(&dir, "campaign-persist-two-regimes-seed");
let proc_id = register_process_doc(
dir,
&dir,
"tworegimes-persist.process.json",
SWEEP_ONLY_PROCESS_DOC,
);
@@ -2646,8 +2621,8 @@ fn campaign_persist_two_regimes_land_in_distinct_trace_dirs() {
1,
);
assert_ne!(with_regimes, base, "replacen must actually match the fixture's seed field");
write_doc(dir, "tworegimes-persist.campaign.json", &with_regimes);
let (out, code) = run_code_in(dir, &["campaign", "run", "tworegimes-persist.campaign.json"]);
write_doc(&dir, "tworegimes-persist.campaign.json", &with_regimes);
let (out, code) = run_code_in(&dir, &["campaign", "run", "tworegimes-persist.campaign.json"]);
// Skip on a data-less machine: the member-data refusal, never a panic.
if code == Some(1)
@@ -2704,8 +2679,7 @@ fn campaign_persist_two_regimes_land_in_distinct_trace_dirs() {
/// host like its siblings.
#[test]
fn campaign_run_real_e2e_skips_unproducible_tap_gracefully() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -2713,10 +2687,10 @@ fn campaign_run_real_e2e_skips_unproducible_tap_gracefully() {
ScratchPath::File(dir.join("mixedtap.process.json")),
ScratchPath::File(dir.join("mixedtap.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-mixedtap-seed");
let proc_id = register_process_doc(dir, "mixedtap.process.json", SWEEP_ONLY_PROCESS_DOC);
let bp_id = seed_blueprint(&dir, "campaign-run-mixedtap-seed");
let proc_id = register_process_doc(&dir, "mixedtap.process.json", SWEEP_ONLY_PROCESS_DOC);
write_doc(
dir,
&dir,
"mixedtap.campaign.json",
&campaign_doc_json(
&bp_id,
@@ -2726,7 +2700,7 @@ fn campaign_run_real_e2e_skips_unproducible_tap_gracefully() {
"",
),
);
let (out, code) = run_code_in(dir, &["campaign", "run", "mixedtap.campaign.json"]);
let (out, code) = run_code_in(&dir, &["campaign", "run", "mixedtap.campaign.json"]);
// Skip on a data-less machine: the member-data refusal, never a panic.
if code == Some(1)
@@ -2781,8 +2755,7 @@ fn campaign_run_real_e2e_skips_unproducible_tap_gracefully() {
/// manifests). Skips on a data-less host like its siblings.
#[test]
fn campaign_run_real_e2e_cost_block_nets_members_and_persists_net_r_equity() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -2791,8 +2764,8 @@ fn campaign_run_real_e2e_cost_block_nets_members_and_persists_net_r_equity() {
ScratchPath::File(dir.join("costless.campaign.json")),
ScratchPath::File(dir.join("costnet.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-costnet-seed");
let proc_id = register_process_doc(dir, "costnet.process.json", SWEEP_ONLY_PROCESS_DOC);
let bp_id = seed_blueprint(&dir, "campaign-run-costnet-seed");
let proc_id = register_process_doc(&dir, "costnet.process.json", SWEEP_ONLY_PROCESS_DOC);
let base = campaign_doc_json(
&bp_id,
&proc_id,
@@ -2809,8 +2782,8 @@ fn campaign_run_real_e2e_cost_block_nets_members_and_persists_net_r_equity() {
1,
);
assert_ne!(with_cost, base, "replacen must actually match the fixture's seed field");
write_doc(dir, "costless.campaign.json", &base);
write_doc(dir, "costnet.campaign.json", &with_cost);
write_doc(&dir, "costless.campaign.json", &base);
write_doc(&dir, "costnet.campaign.json", &with_cost);
// Per-member (axis-params key -> (expectancy_r, net_expectancy_r)),
// parsed from the emitted family_table member lines. Cost stamps are
@@ -2843,7 +2816,7 @@ fn campaign_run_real_e2e_cost_block_nets_members_and_persists_net_r_equity() {
// (a) the cost-less baseline: net == gross, and net_r_equity skips with
// the remedy notice while equity still persists.
let (out_gross, code_gross) = run_code_in(dir, &["campaign", "run", "costless.campaign.json"]);
let (out_gross, code_gross) = run_code_in(&dir, &["campaign", "run", "costless.campaign.json"]);
if code_gross == Some(1)
&& (out_gross.contains("no recorded geometry") || out_gross.contains("no data for instrument"))
{
@@ -2865,7 +2838,7 @@ fn campaign_run_real_e2e_cost_block_nets_members_and_persists_net_r_equity() {
// (b) the costed run: gross identical member-for-member, net strictly
// below gross, no skip notice, net_r_equity persisted on disk.
let (out_net, code_net) = run_code_in(dir, &["campaign", "run", "costnet.campaign.json"]);
let (out_net, code_net) = run_code_in(&dir, &["campaign", "run", "costnet.campaign.json"]);
assert_eq!(code_net, Some(0), "costed run: {out_net}");
assert!(
!out_net.contains("skipped"),
@@ -2916,7 +2889,7 @@ fn campaign_run_real_e2e_cost_block_nets_members_and_persists_net_r_equity() {
.to_string()
})
.expect("a costed member line carries the family id");
let (rep_out, rep_code) = run_code_in(dir, &["reproduce", &family_id]);
let (rep_out, rep_code) = run_code_in(&dir, &["reproduce", &family_id]);
assert_eq!(rep_code, Some(0), "reproduce: {rep_out}");
assert!(
rep_out.contains("reproduced 4/4 members bit-identically"),
@@ -2939,8 +2912,7 @@ fn campaign_run_real_e2e_cost_block_nets_members_and_persists_net_r_equity() {
/// local GER40 archive; skips on a data-less host.
#[test]
fn campaign_run_real_e2e_carry_cost_persists_without_drift_alarm() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -2948,9 +2920,9 @@ fn campaign_run_real_e2e_carry_cost_persists_without_drift_alarm() {
ScratchPath::File(dir.join("carrycost-persist.process.json")),
ScratchPath::File(dir.join("carrycost-persist.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-persist-carrycost-seed");
let bp_id = seed_blueprint(&dir, "campaign-persist-carrycost-seed");
let proc_id =
register_process_doc(dir, "carrycost-persist.process.json", SWEEP_ONLY_PROCESS_DOC);
register_process_doc(&dir, "carrycost-persist.process.json", SWEEP_ONLY_PROCESS_DOC);
let base = campaign_doc_json(
&bp_id,
&proc_id,
@@ -2964,8 +2936,8 @@ fn campaign_run_real_e2e_carry_cost_persists_without_drift_alarm() {
1,
);
assert_ne!(with_cost, base, "replacen must actually match the fixture's seed field");
write_doc(dir, "carrycost-persist.campaign.json", &with_cost);
let (out, code) = run_code_in(dir, &["campaign", "run", "carrycost-persist.campaign.json"]);
write_doc(&dir, "carrycost-persist.campaign.json", &with_cost);
let (out, code) = run_code_in(&dir, &["campaign", "run", "carrycost-persist.campaign.json"]);
// Skip on a data-less machine: the member-data refusal, never a panic.
if code == Some(1)
@@ -3021,8 +2993,7 @@ fn campaign_run_real_e2e_carry_cost_persists_without_drift_alarm() {
/// data-free refusal fixture).
#[test]
fn campaign_run_real_e2e_sweep_monte_carlo_per_survivor() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -3030,15 +3001,15 @@ fn campaign_run_real_e2e_sweep_monte_carlo_per_survivor() {
ScratchPath::File(dir.join("mc.process.json")),
ScratchPath::File(dir.join("mc.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-mc-persurvivor-seed");
let proc_id = register_process_doc(dir, "mc.process.json", MC_PROCESS_DOC);
let bp_id = seed_blueprint(&dir, "campaign-run-mc-persurvivor-seed");
let proc_id = register_process_doc(&dir, "mc.process.json", MC_PROCESS_DOC);
// Same GER40 Sept-2024 window as the gated wf e2e above.
write_doc(
dir,
&dir,
"mc.campaign.json",
&campaign_doc_json(&bp_id, &proc_id, (1725148800000, 1727740799999), "", ""),
);
let (out, code) = run_code_in(dir, &["campaign", "run", "mc.campaign.json"]);
let (out, code) = run_code_in(&dir, &["campaign", "run", "mc.campaign.json"]);
// Skip on a data-less machine: the member-data refusal, never a panic.
if code == Some(1)
@@ -3095,8 +3066,7 @@ fn campaign_run_real_e2e_sweep_monte_carlo_per_survivor() {
/// prose either way (the message depends only on env/instrument/window).
#[test]
fn campaign_run_by_content_id_matches_file_sugar_refusal() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -3104,14 +3074,14 @@ fn campaign_run_by_content_id_matches_file_sugar_refusal() {
ScratchPath::File(dir.join("mc2.process.json")),
ScratchPath::File(dir.join("mc2.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-id-seed");
let proc_id = register_process_doc(dir, "mc2.process.json", MC_PROCESS_DOC);
write_doc(dir, "mc2.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let bp_id = seed_blueprint(&dir, "campaign-run-id-seed");
let proc_id = register_process_doc(&dir, "mc2.process.json", MC_PROCESS_DOC);
write_doc(&dir, "mc2.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (file_out, file_code) = run_code_in(dir, &["campaign", "run", "mc2.campaign.json"]);
let (file_out, file_code) = run_code_in(&dir, &["campaign", "run", "mc2.campaign.json"]);
assert_eq!(file_code, Some(1), "stdout/stderr: {file_out}");
let (reg_out, reg_code) = run_code_in(dir, &["campaign", "register", "mc2.campaign.json"]);
let (reg_out, reg_code) = run_code_in(&dir, &["campaign", "register", "mc2.campaign.json"]);
assert_eq!(reg_code, Some(0), "register failed: {reg_out}");
let id = reg_out
.lines()
@@ -3123,7 +3093,7 @@ fn campaign_run_by_content_id_matches_file_sugar_refusal() {
.expect("id")
.trim_start_matches("content:")
.to_string();
let (id_out, id_code) = run_code_in(dir, &["campaign", "run", &id]);
let (id_out, id_code) = run_code_in(&dir, &["campaign", "run", &id]);
assert_eq!(id_code, Some(1), "stdout/stderr: {id_out}");
let file_line = file_out.lines().find(|l| l.starts_with("aura: ")).expect("file refusal line");
@@ -3146,8 +3116,7 @@ fn campaign_run_by_content_id_matches_file_sugar_refusal() {
/// needed.
#[test]
fn campaign_run_tolerates_content_prefix_on_target() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -3155,11 +3124,11 @@ fn campaign_run_tolerates_content_prefix_on_target() {
ScratchPath::File(dir.join("prefix.process.json")),
ScratchPath::File(dir.join("prefix.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-prefix-seed");
let proc_id = register_process_doc(dir, "prefix.process.json", MC_PROCESS_DOC);
write_doc(dir, "prefix.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let bp_id = seed_blueprint(&dir, "campaign-run-prefix-seed");
let proc_id = register_process_doc(&dir, "prefix.process.json", MC_PROCESS_DOC);
write_doc(&dir, "prefix.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (reg_out, reg_code) = run_code_in(dir, &["campaign", "register", "prefix.campaign.json"]);
let (reg_out, reg_code) = run_code_in(&dir, &["campaign", "register", "prefix.campaign.json"]);
assert_eq!(reg_code, Some(0), "register failed: {reg_out}");
let id = reg_out
.lines()
@@ -3172,8 +3141,8 @@ fn campaign_run_tolerates_content_prefix_on_target() {
.trim_start_matches("content:")
.to_string();
let (bare_out, _) = run_code_in(dir, &["campaign", "run", &id]);
let (pfx_out, _) = run_code_in(dir, &["campaign", "run", &format!("content:{id}")]);
let (bare_out, _) = run_code_in(&dir, &["campaign", "run", &id]);
let (pfx_out, _) = run_code_in(&dir, &["campaign", "run", &format!("content:{id}")]);
let pfx_line = pfx_out.lines().find(|l| l.starts_with("aura: ")).expect("prefixed refusal line");
assert!(
@@ -3201,8 +3170,7 @@ fn campaign_run_tolerates_content_prefix_on_target() {
/// data-free refusal) rather than failing earlier at referencing or binding.
#[test]
fn campaign_run_accepts_a_graph_register_seeded_strategy() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -3211,7 +3179,7 @@ fn campaign_run_accepts_a_graph_register_seeded_strategy() {
ScratchPath::File(dir.join("onramp.campaign.json")),
]);
let closed_bp = format!("{}/examples/r_sma.json", env!("CARGO_MANIFEST_DIR"));
let (reg_out, reg_code) = run_code_in(dir, &["graph", "register", &closed_bp]);
let (reg_out, reg_code) = run_code_in(&dir, &["graph", "register", &closed_bp]);
assert_eq!(reg_code, Some(0), "graph register failed: {reg_out}");
let bp_id = reg_out
.lines()
@@ -3224,9 +3192,9 @@ fn campaign_run_accepts_a_graph_register_seeded_strategy() {
.trim_start_matches("content:")
.to_string();
let proc_id = register_process_doc(dir, "onramp.process.json", SWEEP_ONLY_PROCESS_DOC);
write_doc(dir, "onramp.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (out, code) = run_code_in(dir, &["campaign", "run", "onramp.campaign.json"]);
let proc_id = register_process_doc(&dir, "onramp.process.json", SWEEP_ONLY_PROCESS_DOC);
write_doc(&dir, "onramp.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (out, code) = run_code_in(&dir, &["campaign", "run", "onramp.campaign.json"]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
assert!(
out.contains("no recorded geometry") || out.contains("no data for instrument"),
@@ -3248,15 +3216,14 @@ fn campaign_run_invalid_file_refuses_before_touching_store() {
// Run inside the built project (campaign run needs one, per the project
// gate); the document fails intrinsic validation before any store or
// referential check is reached, so the project's own store is untouched.
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let bad = CAMPAIGN_DOC.replacen(r#""values": [8]"#, r#""values": []"#, 1);
let bad_path = write_doc(dir, "bad.campaign.json", &bad);
let bad_path = write_doc(&dir, "bad.campaign.json", &bad);
let _cleanup = ScratchGuard(vec![ScratchPath::Dir(runs_dir.clone()), ScratchPath::File(bad_path)]);
let (out, code) = run_code_in(dir, &["campaign", "run", "bad.campaign.json"]);
let (out, code) = run_code_in(&dir, &["campaign", "run", "bad.campaign.json"]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
assert!(
out.contains("aura: campaign document invalid:"),